1use std::collections::BTreeMap;
8
9use serde::{Serialize, Serializer, ser::SerializeMap};
10use serde_json::Value;
11
12use super::{
13 icon::Icon,
14 types::{
15 AvatarVariant, ButtonVariant, ChoiceStyle, ColumnFormat, Disabled, ItemStatus, SortDir,
16 Status, Text, TextAlign, Tone, Truncate,
17 },
18};
19
20#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
22pub struct KvItem {
23 pub k: Text,
25 pub v: Text,
27}
28
29#[derive(Clone, Debug, Default, PartialEq, Serialize)]
31pub struct Column {
32 pub id: String,
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub head: Option<Text>,
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub align: Option<TextAlign>,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub truncate: Option<Truncate>,
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub priority: Option<f64>,
46 #[serde(skip_serializing_if = "Option::is_none")]
48 pub grow: Option<f64>,
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub mono: Option<bool>,
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub sortable: Option<bool>,
55}
56
57impl Column {
58 pub fn new(id: impl Into<String>, head: impl Into<Text>) -> Self {
60 Self { id: id.into(), head: Some(head.into()), ..Self::default() }
61 }
62
63 pub fn align(mut self, align: impl Into<TextAlign>) -> Self {
65 self.align = Some(align.into());
66 self
67 }
68
69 pub const fn grow(mut self, grow: f64) -> Self {
71 self.grow = Some(grow);
72 self
73 }
74
75 pub const fn priority(mut self, priority: f64) -> Self {
77 self.priority = Some(priority);
78 self
79 }
80
81 pub fn truncate(mut self, truncate: impl Into<Truncate>) -> Self {
83 self.truncate = Some(truncate.into());
84 self
85 }
86
87 pub const fn mono(mut self, mono: bool) -> Self {
89 self.mono = Some(mono);
90 self
91 }
92
93 pub const fn sortable(mut self, sortable: bool) -> Self {
95 self.sortable = Some(sortable);
96 self
97 }
98}
99
100#[derive(Clone, Debug, Default, PartialEq, Serialize)]
102pub struct Part {
103 pub value: f64,
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub token: Option<String>,
108 #[serde(skip_serializing_if = "Option::is_none")]
110 pub label: Option<String>,
111 #[serde(skip_serializing_if = "Option::is_none")]
113 pub hatch: Option<bool>,
114}
115
116#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize)]
118pub struct Thresholds {
119 #[serde(skip_serializing_if = "Option::is_none")]
121 pub warn: Option<f64>,
122 #[serde(skip_serializing_if = "Option::is_none")]
124 pub bad: Option<f64>,
125}
126
127#[derive(Clone, Debug, Default, PartialEq, Serialize)]
129pub struct MeterCell {
130 #[serde(skip_serializing_if = "Option::is_none")]
132 pub value: Option<f64>,
133 #[serde(skip_serializing_if = "Vec::is_empty")]
135 pub parts: Vec<Part>,
136 #[serde(skip_serializing_if = "Option::is_none")]
138 pub thresholds: Option<Thresholds>,
139 #[serde(skip_serializing_if = "Option::is_none")]
141 pub tone: Option<Tone>,
142 #[serde(skip_serializing_if = "Option::is_none")]
144 pub title: Option<String>,
145}
146
147#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
149pub struct TextCell {
150 pub text: Text,
152 #[serde(skip_serializing_if = "Option::is_none")]
154 pub icon: Option<Icon>,
155 #[serde(skip_serializing_if = "Option::is_none")]
157 pub dot: Option<Tone>,
158 #[serde(skip_serializing_if = "Option::is_none")]
160 pub tone: Option<Tone>,
161 #[serde(skip_serializing_if = "Option::is_none")]
163 pub title: Option<String>,
164}
165
166impl TextCell {
167 pub fn new(text: impl Into<Text>) -> Self {
169 Self { text: text.into(), ..Self::default() }
170 }
171
172 pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
174 self.icon = Some(icon.into());
175 self
176 }
177
178 pub fn dot(mut self, tone: impl Into<Tone>) -> Self {
180 self.dot = Some(tone.into());
181 self
182 }
183
184 pub fn tone(mut self, tone: impl Into<Tone>) -> Self {
186 self.tone = Some(tone.into());
187 self
188 }
189
190 pub fn title(mut self, title: impl Into<String>) -> Self {
192 self.title = Some(title.into());
193 self
194 }
195}
196
197#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
200pub struct ButtonCell {
201 pub text: String,
203 pub act: String,
205 #[serde(skip_serializing_if = "Option::is_none")]
207 pub icon: Option<Icon>,
208 #[serde(skip_serializing_if = "Vec::is_empty")]
210 pub keys: Vec<String>,
211 #[serde(skip_serializing_if = "Option::is_none")]
213 pub variant: Option<ButtonVariant>,
214 #[serde(skip_serializing_if = "Option::is_none")]
216 pub disabled: Option<Disabled>,
217}
218
219impl ButtonCell {
220 pub fn new(text: impl Into<String>, act: impl Into<String>) -> Self {
222 Self { text: text.into(), act: act.into(), ..Self::default() }
223 }
224
225 pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
227 self.icon = Some(icon.into());
228 self
229 }
230
231 pub fn keys<K: Into<String>>(mut self, keys: impl IntoIterator<Item = K>) -> Self {
233 self.keys = keys.into_iter().map(Into::into).collect();
234 self
235 }
236
237 pub fn variant(mut self, variant: impl Into<ButtonVariant>) -> Self {
239 self.variant = Some(variant.into());
240 self
241 }
242
243 pub fn disabled(mut self, disabled: impl Into<Disabled>) -> Self {
245 self.disabled = Some(disabled.into());
246 self
247 }
248}
249
250#[derive(Clone, Debug, Default, PartialEq, Serialize)]
252pub struct SparkCell {
253 pub values: Vec<f64>,
255 #[serde(skip_serializing_if = "Option::is_none")]
257 pub tone: Option<Tone>,
258 #[serde(skip_serializing_if = "Option::is_none")]
260 pub min: Option<f64>,
261 #[serde(skip_serializing_if = "Option::is_none")]
263 pub max: Option<f64>,
264 #[serde(skip_serializing_if = "Option::is_none")]
266 pub title: Option<String>,
267}
268
269impl SparkCell {
270 pub fn new(values: impl Into<Vec<f64>>) -> Self {
272 Self { values: values.into(), ..Self::default() }
273 }
274
275 pub fn tone(mut self, tone: impl Into<Tone>) -> Self {
277 self.tone = Some(tone.into());
278 self
279 }
280
281 pub const fn range(mut self, min: f64, max: f64) -> Self {
283 self.min = Some(min);
284 self.max = Some(max);
285 self
286 }
287}
288
289#[derive(Clone, Debug, PartialEq)]
292pub enum Cell {
293 Text(Text),
295 Meter(MeterCell),
297 Rich(TextCell),
299 Badge(BadgeSpec),
301 Button(ButtonCell),
303 Spark(SparkCell),
305}
306
307impl Serialize for Cell {
308 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
309 fn one<S: Serializer>(s: S, key: &str, value: &impl Serialize) -> Result<S::Ok, S::Error> {
310 let mut map = s.serialize_map(Some(1))?;
311 map.serialize_entry(key, value)?;
312 map.end()
313 }
314 match self {
315 Self::Text(t) => t.serialize(s),
316 Self::Rich(c) => c.serialize(s),
317 Self::Meter(m) => one(s, "meter", m),
318 Self::Badge(b) => one(s, "badge", b),
319 Self::Button(b) => one(s, "button", b),
320 Self::Spark(c) => one(s, "spark", c),
321 }
322 }
323}
324
325impl<T: Into<Text>> From<T> for Cell {
326 fn from(t: T) -> Self {
327 Self::Text(t.into())
328 }
329}
330
331impl From<MeterCell> for Cell {
332 fn from(m: MeterCell) -> Self {
333 Self::Meter(m)
334 }
335}
336
337impl From<TextCell> for Cell {
338 fn from(c: TextCell) -> Self {
339 Self::Rich(c)
340 }
341}
342
343impl From<BadgeSpec> for Cell {
344 fn from(b: BadgeSpec) -> Self {
345 Self::Badge(b)
346 }
347}
348
349impl From<ButtonCell> for Cell {
350 fn from(b: ButtonCell) -> Self {
351 Self::Button(b)
352 }
353}
354
355impl From<SparkCell> for Cell {
356 fn from(c: SparkCell) -> Self {
357 Self::Spark(c)
358 }
359}
360
361#[derive(Clone, Debug, Default, PartialEq, Serialize)]
363pub struct TableRow {
364 pub id: String,
366 pub cells: BTreeMap<String, Cell>,
368 #[serde(skip_serializing_if = "Option::is_none")]
370 pub disabled: Option<Disabled>,
371 #[serde(skip_serializing_if = "Vec::is_empty")]
373 pub menu: Vec<String>,
374 #[serde(skip_serializing_if = "Option::is_none")]
376 pub title: Option<String>,
377}
378
379impl TableRow {
380 pub fn new(id: impl Into<String>) -> Self {
382 Self { id: id.into(), ..Self::default() }
383 }
384
385 pub fn disabled(mut self, disabled: impl Into<Disabled>) -> Self {
387 self.disabled = Some(disabled.into());
388 self
389 }
390
391 pub fn menu(mut self, act: impl Into<String>) -> Self {
393 self.menu.push(act.into());
394 self
395 }
396
397 pub fn title(mut self, title: impl Into<String>) -> Self {
399 self.title = Some(title.into());
400 self
401 }
402
403 pub fn cell(mut self, col: impl Into<String>, cell: impl Into<Cell>) -> Self {
405 self.cells.insert(col.into(), cell.into());
406 self
407 }
408}
409
410#[derive(Clone, Debug, Default, PartialEq, Serialize)]
412pub struct TreeItem {
413 pub id: String,
415 pub label: Text,
417 #[serde(skip_serializing_if = "Option::is_none")]
419 pub icon: Option<Icon>,
420 #[serde(skip_serializing_if = "Option::is_none")]
422 pub open: Option<bool>,
423 #[serde(skip_serializing_if = "Vec::is_empty")]
425 pub children: Vec<Self>,
426}
427
428impl TreeItem {
429 pub fn new(id: impl Into<String>, label: impl Into<Text>) -> Self {
431 Self { id: id.into(), label: label.into(), ..Self::default() }
432 }
433
434 pub fn child(mut self, item: Self) -> Self {
436 self.children.push(item);
437 self
438 }
439
440 pub const fn open(mut self, open: bool) -> Self {
442 self.open = Some(open);
443 self
444 }
445}
446
447#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
449pub struct Tab {
450 pub id: String,
452 pub label: Text,
454}
455
456#[derive(Clone, Debug, Default, PartialEq, Serialize)]
458pub struct CodeMark {
459 pub line: u64,
461 #[serde(skip_serializing_if = "Option::is_none")]
463 pub tone: Option<Tone>,
464 #[serde(skip_serializing_if = "Option::is_none")]
467 pub heat: Option<f64>,
468 #[serde(skip_serializing_if = "Vec::is_empty")]
470 pub ranges: Vec<[u64; 2]>,
471 #[serde(skip_serializing_if = "Vec::is_empty")]
474 pub wash: Vec<f64>,
475}
476
477#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
479pub struct CodeFold {
480 pub from: u64,
482 pub to: u64,
484 #[serde(skip_serializing_if = "Option::is_none")]
487 pub label: Option<String>,
488 #[serde(skip_serializing_if = "Option::is_none")]
490 pub note: Option<Text>,
491 #[serde(skip_serializing_if = "Option::is_none")]
493 pub tone: Option<Tone>,
494 #[serde(skip_serializing_if = "Option::is_none")]
497 pub open: Option<bool>,
498 #[serde(skip_serializing_if = "Option::is_none")]
501 pub hovercard: Option<Value>,
502}
503
504#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
506#[serde(rename_all = "camelCase")]
507pub struct Hunk {
508 #[serde(skip_serializing_if = "Option::is_none")]
510 pub old_start: Option<u64>,
511 #[serde(skip_serializing_if = "Option::is_none")]
513 pub new_start: Option<u64>,
514 pub lines: Vec<String>,
516}
517
518#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
520pub struct Decor {
521 pub from: usize,
523 pub to: usize,
525 pub s: String,
527 #[serde(skip_serializing_if = "Option::is_none")]
529 pub fx: Option<super::types::Fx>,
530}
531
532#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
534pub struct ShimmerPalette {
535 #[serde(skip_serializing_if = "Option::is_none")]
537 pub low: Option<String>,
538 #[serde(skip_serializing_if = "Option::is_none")]
540 pub mid: Option<String>,
541 #[serde(skip_serializing_if = "Option::is_none")]
543 pub high: Option<String>,
544}
545
546#[derive(Clone, Debug, Default, PartialEq, Serialize)]
548pub struct MeterMark {
549 pub at: f64,
551 #[serde(skip_serializing_if = "Option::is_none")]
553 pub tone: Option<Tone>,
554 #[serde(skip_serializing_if = "Option::is_none")]
556 pub title: Option<String>,
557 #[serde(skip_serializing_if = "Option::is_none")]
559 pub icon: Option<Icon>,
560}
561
562#[derive(Clone, Debug, Default, PartialEq, Serialize)]
565pub struct Point {
566 pub value: f64,
568 #[serde(skip_serializing_if = "Option::is_none")]
570 pub label: Option<String>,
571 #[serde(skip_serializing_if = "Option::is_none")]
573 pub title: Option<String>,
574 #[serde(skip_serializing_if = "Option::is_none")]
576 pub tone: Option<Tone>,
577 #[serde(skip_serializing_if = "Option::is_none")]
579 pub token: Option<String>,
580}
581
582#[derive(Clone, Debug, Default, PartialEq, Serialize)]
584pub struct Series {
585 #[serde(skip_serializing_if = "Option::is_none")]
587 pub label: Option<String>,
588 #[serde(skip_serializing_if = "Option::is_none")]
590 pub token: Option<String>,
591 pub values: Vec<Option<f64>>,
593}
594
595impl Series {
596 pub fn new(values: impl Into<Vec<Option<f64>>>) -> Self {
598 Self { values: values.into(), ..Self::default() }
599 }
600
601 pub fn label(mut self, label: impl Into<String>) -> Self {
603 self.label = Some(label.into());
604 self
605 }
606
607 pub fn token(mut self, token: impl Into<String>) -> Self {
609 self.token = Some(token.into());
610 self
611 }
612}
613
614#[derive(Clone, Debug, Default, PartialEq, Serialize)]
617pub struct ChartMark {
618 pub value: f64,
620 #[serde(skip_serializing_if = "Option::is_none")]
622 pub tone: Option<Tone>,
623 #[serde(skip_serializing_if = "Option::is_none")]
625 pub title: Option<String>,
626}
627
628#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
630pub struct ChartCol {
631 pub at: u32,
633 pub label: String,
635}
636
637#[derive(Clone, Debug, PartialEq, Eq)]
639pub enum Anchor {
640 Center,
642 Top,
644 Bottom,
646 Node {
648 id: String,
650 above: bool,
652 },
653 Caret(String),
655}
656
657impl Serialize for Anchor {
658 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
659 use serde::ser::SerializeMap as _;
660 match self {
661 Self::Center => s.serialize_str("center"),
662 Self::Top => s.serialize_str("top"),
663 Self::Bottom => s.serialize_str("bottom"),
664 Self::Node { id, above } => {
665 let mut m = s.serialize_map(Some(2))?;
666 m.serialize_entry("node", id)?;
667 m.serialize_entry("side", if *above { "above" } else { "below" })?;
668 m.end()
669 },
670 Self::Caret(id) => {
671 let mut m = s.serialize_map(Some(1))?;
672 m.serialize_entry("caret", id)?;
673 m.end()
674 },
675 }
676 }
677}
678
679#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
681pub struct BadgeSpec {
682 pub text: String,
684 #[serde(skip_serializing_if = "Option::is_none")]
686 pub tone: Option<Tone>,
687 #[serde(skip_serializing_if = "Option::is_none")]
689 pub title: Option<String>,
690}
691
692impl BadgeSpec {
693 pub fn new(text: impl Into<String>) -> Self {
695 Self { text: text.into(), ..Self::default() }
696 }
697
698 pub fn tone(mut self, tone: impl Into<Tone>) -> Self {
700 self.tone = Some(tone.into());
701 self
702 }
703
704 pub fn title(mut self, title: impl Into<String>) -> Self {
706 self.title = Some(title.into());
707 self
708 }
709}
710
711#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
713pub struct StatItem {
714 pub label: Text,
716 pub value: Text,
718 #[serde(skip_serializing_if = "Option::is_none")]
720 pub sub: Option<Text>,
721 #[serde(skip_serializing_if = "Option::is_none")]
723 pub tone: Option<Tone>,
724 #[serde(skip_serializing_if = "Option::is_none")]
726 pub title: Option<String>,
727}
728
729impl StatItem {
730 pub fn new(label: impl Into<Text>, value: impl Into<Text>) -> Self {
732 Self { label: label.into(), value: value.into(), ..Self::default() }
733 }
734
735 #[expect(clippy::should_implement_trait, reason = "named after the wire prop `sub`")]
737 pub fn sub(mut self, sub: impl Into<Text>) -> Self {
738 self.sub = Some(sub.into());
739 self
740 }
741
742 pub fn tone(mut self, tone: impl Into<Tone>) -> Self {
744 self.tone = Some(tone.into());
745 self
746 }
747
748 pub fn title(mut self, title: impl Into<String>) -> Self {
750 self.title = Some(title.into());
751 self
752 }
753}
754
755#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
757pub struct ToolButton {
758 pub id: String,
760 #[serde(skip_serializing_if = "Option::is_none")]
762 pub label: Option<String>,
763 #[serde(skip_serializing_if = "Vec::is_empty")]
765 pub keys: Vec<String>,
766}
767
768#[derive(Clone, Copy, Debug, PartialEq, Eq)]
770pub enum ToolPreview {
771 Lines(u32),
773 Tail(u32),
775}
776
777impl Serialize for ToolPreview {
778 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
779 use serde::ser::SerializeMap as _;
780 let mut m = s.serialize_map(Some(1))?;
781 match *self {
782 Self::Lines(n) => m.serialize_entry("lines", &n)?,
783 Self::Tail(n) => m.serialize_entry("tail", &n)?,
784 }
785 m.end()
786 }
787}
788
789#[derive(Clone, Copy, Debug, PartialEq, Eq)]
791pub enum Preview {
792 Auto,
794 Lines(u32),
796}
797
798impl Serialize for Preview {
799 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
800 use serde::ser::SerializeMap as _;
801 match *self {
802 Self::Auto => s.serialize_str("auto"),
803 Self::Lines(n) => {
804 let mut m = s.serialize_map(Some(1))?;
805 m.serialize_entry("lines", &n)?;
806 m.end()
807 },
808 }
809 }
810}
811
812#[derive(Clone, Debug, Default, PartialEq, Serialize)]
814#[serde(rename_all = "camelCase")]
815pub struct AgentStats {
816 #[serde(skip_serializing_if = "Option::is_none")]
818 pub tools: Option<u64>,
819 #[serde(skip_serializing_if = "Option::is_none")]
821 pub requests: Option<u64>,
822 #[serde(skip_serializing_if = "Option::is_none")]
824 pub done: Option<f64>,
825 #[serde(skip_serializing_if = "Option::is_none")]
827 pub context: Option<f64>,
828 #[serde(skip_serializing_if = "Option::is_none")]
830 pub context_label: Option<String>,
831 #[serde(skip_serializing_if = "Option::is_none")]
833 pub tokens: Option<u64>,
834 #[serde(skip_serializing_if = "Option::is_none")]
836 pub cost: Option<f64>,
837 #[serde(skip_serializing_if = "Option::is_none")]
839 pub age: Option<i64>,
840 #[serde(skip_serializing_if = "Option::is_none")]
842 pub took: Option<u64>,
843}
844
845#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
847pub struct AgentTool {
848 pub name: String,
850 #[serde(skip_serializing_if = "Option::is_none")]
852 pub intent: Option<String>,
853 #[serde(skip_serializing_if = "Option::is_none")]
855 pub age: Option<i64>,
856}
857
858#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
860pub struct Retry {
861 #[serde(skip_serializing_if = "Option::is_none")]
863 pub attempt: Option<u32>,
864 #[serde(skip_serializing_if = "Option::is_none")]
866 pub max: Option<u32>,
867 #[serde(skip_serializing_if = "Option::is_none")]
869 pub delay: Option<u64>,
870 #[serde(skip_serializing_if = "Option::is_none")]
872 pub age: Option<i64>,
873 #[serde(skip_serializing_if = "Option::is_none")]
875 pub error: Option<String>,
876}
877
878#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
880pub struct ChecklistItem {
881 pub id: String,
883 pub text: Text,
885 #[serde(skip_serializing_if = "Option::is_none")]
887 pub status: Option<ItemStatus>,
888 #[serde(skip_serializing_if = "Option::is_none")]
890 pub note: Option<Text>,
891}
892
893#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
895pub struct Phase {
896 pub id: String,
898 #[serde(skip_serializing_if = "Option::is_none")]
900 pub title: Option<Text>,
901 pub items: Vec<ChecklistItem>,
903 #[serde(skip_serializing_if = "Option::is_none")]
905 pub collapsed: Option<bool>,
906}
907
908#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
910pub struct PickerItem {
911 pub id: String,
913 pub label: Text,
915 #[serde(skip_serializing_if = "Option::is_none")]
917 pub detail: Option<Text>,
918 #[serde(skip_serializing_if = "Option::is_none")]
920 pub icon: Option<Icon>,
921 #[serde(skip_serializing_if = "Option::is_none")]
923 pub role: Option<String>,
924 #[serde(skip_serializing_if = "Option::is_none")]
926 pub mark: Option<Value>,
927 #[serde(skip_serializing_if = "Option::is_none")]
929 pub dot: Option<Tone>,
930 #[serde(skip_serializing_if = "Option::is_none")]
932 pub mono: Option<bool>,
933 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
935 pub facts: BTreeMap<String, Value>,
936 #[serde(skip_serializing_if = "Vec::is_empty")]
938 pub badges: Vec<BadgeSpec>,
939 #[serde(skip_serializing_if = "Vec::is_empty")]
941 pub chips: Vec<Value>,
942 #[serde(skip_serializing_if = "Option::is_none")]
944 pub tone: Option<Tone>,
945 #[serde(skip_serializing_if = "Option::is_none")]
947 pub disabled: Option<Value>,
948 #[serde(skip_serializing_if = "Vec::is_empty")]
950 pub hits: Vec<[usize; 2]>,
951 #[serde(skip_serializing_if = "Option::is_none")]
953 pub node: Option<String>,
954 #[serde(skip_serializing_if = "Option::is_none")]
956 pub depth: Option<u32>,
957 #[serde(skip_serializing_if = "Option::is_none")]
959 pub open: Option<bool>,
960 #[serde(skip_serializing_if = "Option::is_none")]
962 pub title: Option<String>,
963}
964
965impl PickerItem {
966 pub fn new(id: impl Into<String>, label: impl Into<Text>) -> Self {
968 Self { id: id.into(), label: label.into(), ..Self::default() }
969 }
970}
971
972#[derive(Clone, Debug, PartialEq, Eq)]
974pub enum OrderEntry {
975 Item(String),
977 Group {
979 group: String,
981 label: String,
983 count: Option<u64>,
985 },
986}
987
988impl Serialize for OrderEntry {
989 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
990 use serde::ser::SerializeMap as _;
991 match self {
992 Self::Item(id) => s.serialize_str(id),
993 Self::Group { group, label, count } => {
994 let mut m = s.serialize_map(None)?;
995 m.serialize_entry("group", group)?;
996 m.serialize_entry("label", label)?;
997 if let Some(count) = count {
998 m.serialize_entry("count", count)?;
999 }
1000 m.end()
1001 },
1002 }
1003 }
1004}
1005
1006#[derive(Clone, Debug, Default, PartialEq, Serialize)]
1008pub struct PickerColumn {
1009 pub id: String,
1011 #[serde(skip_serializing_if = "Option::is_none")]
1013 pub head: Option<String>,
1014 #[serde(skip_serializing_if = "Option::is_none")]
1016 pub format: Option<ColumnFormat>,
1017 #[serde(skip_serializing_if = "Option::is_none")]
1019 pub priority: Option<f64>,
1020 #[serde(skip_serializing_if = "Option::is_none")]
1022 pub min: Option<u32>,
1023}
1024
1025#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1027pub struct Confirm {
1028 pub text: String,
1030 #[serde(skip_serializing_if = "Option::is_none")]
1032 pub act: Option<String>,
1033 #[serde(skip_serializing_if = "Option::is_none")]
1035 pub label: Option<String>,
1036}
1037
1038#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1040pub struct Scope {
1041 pub id: String,
1043 pub label: String,
1045 #[serde(skip_serializing_if = "Option::is_none")]
1047 pub group: Option<String>,
1048 #[serde(skip_serializing_if = "Option::is_none")]
1050 pub mark: Option<Value>,
1051 #[serde(skip_serializing_if = "Option::is_none")]
1053 pub icon: Option<Icon>,
1054 #[serde(skip_serializing_if = "Option::is_none")]
1056 pub dot: Option<Tone>,
1057 #[serde(skip_serializing_if = "Option::is_none")]
1059 pub count: Option<u64>,
1060 #[serde(skip_serializing_if = "Option::is_none")]
1062 pub disabled: Option<Value>,
1063}
1064
1065#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1067pub struct PickerTab {
1068 pub id: String,
1070 pub label: String,
1072 #[serde(skip_serializing_if = "Option::is_none")]
1074 pub count: Option<u64>,
1075}
1076
1077#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1079pub struct StripItem {
1080 pub id: String,
1082 pub label: String,
1084 #[serde(skip_serializing_if = "Option::is_none")]
1086 pub on: Option<bool>,
1087 #[serde(skip_serializing_if = "Option::is_none")]
1089 pub dot: Option<String>,
1090}
1091
1092#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1094pub struct Strip {
1095 #[serde(skip_serializing_if = "Option::is_none")]
1097 pub label: Option<String>,
1098 pub items: Vec<StripItem>,
1100 #[serde(skip_serializing_if = "Option::is_none")]
1102 pub selected: Option<String>,
1103}
1104
1105#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1107pub struct PickerAction {
1108 pub id: String,
1110 #[serde(skip_serializing_if = "Option::is_none")]
1112 pub label: Option<String>,
1113 #[serde(skip_serializing_if = "Vec::is_empty")]
1115 pub keys: Vec<String>,
1116 #[serde(skip_serializing_if = "Option::is_none")]
1118 pub primary: Option<bool>,
1119 #[serde(skip_serializing_if = "Option::is_none")]
1121 pub end: Option<bool>,
1122 #[serde(skip_serializing_if = "Option::is_none")]
1124 pub danger: Option<bool>,
1125 #[serde(skip_serializing_if = "Option::is_none")]
1127 pub on: Option<bool>,
1128 #[serde(skip_serializing_if = "Option::is_none")]
1130 pub disabled: Option<Value>,
1131}
1132
1133#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1135pub struct PrefsPage {
1136 pub id: String,
1138 #[serde(skip_serializing_if = "Option::is_none")]
1140 pub label: Option<String>,
1141 #[serde(skip_serializing_if = "Option::is_none")]
1143 pub group: Option<String>,
1144 #[serde(skip_serializing_if = "Option::is_none")]
1146 pub icon: Option<Icon>,
1147 #[serde(skip_serializing_if = "Option::is_none")]
1149 pub disabled: Option<String>,
1150 #[serde(skip_serializing_if = "Option::is_none")]
1152 pub changed: Option<u32>,
1153}
1154
1155#[derive(Clone, Debug, Default, PartialEq, Serialize)]
1157pub struct PrefsSection {
1158 #[serde(skip_serializing_if = "Option::is_none")]
1160 pub id: Option<String>,
1161 #[serde(skip_serializing_if = "Option::is_none")]
1163 pub title: Option<String>,
1164 #[serde(skip_serializing_if = "Option::is_none")]
1166 pub page: Option<String>,
1167 pub rows: Vec<PrefsRow>,
1169}
1170
1171#[derive(Clone, Debug, Default, PartialEq, Serialize)]
1173#[serde(rename_all = "camelCase")]
1174pub struct PrefsRow {
1175 pub id: String,
1177 #[serde(skip_serializing_if = "Option::is_none")]
1179 pub label: Option<String>,
1180 #[serde(skip_serializing_if = "Option::is_none")]
1182 pub hint: Option<String>,
1183 #[serde(skip_serializing_if = "Option::is_none")]
1185 pub warning: Option<String>,
1186 #[serde(skip_serializing_if = "Option::is_none")]
1188 pub disabled: Option<String>,
1189 #[serde(skip_serializing_if = "Option::is_none")]
1191 pub changed: Option<bool>,
1192 #[serde(skip_serializing_if = "Option::is_none")]
1194 pub default_label: Option<String>,
1195 #[serde(skip_serializing_if = "Option::is_none")]
1197 pub control: Option<Control>,
1198}
1199
1200#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1202pub struct ChoiceOption {
1203 pub value: String,
1205 #[serde(skip_serializing_if = "Option::is_none")]
1207 pub label: Option<String>,
1208 #[serde(skip_serializing_if = "Option::is_none")]
1210 pub detail: Option<String>,
1211}
1212
1213#[derive(Clone, Debug, PartialEq, Serialize)]
1215#[serde(tag = "k", rename_all = "lowercase")]
1216pub enum Control {
1217 Switch {
1219 on: bool,
1221 },
1222 Choice {
1224 value: String,
1226 options: Vec<ChoiceOption>,
1228 #[serde(skip_serializing_if = "Option::is_none")]
1230 style: Option<ChoiceStyle>,
1231 #[serde(skip_serializing_if = "Option::is_none")]
1233 mono: Option<bool>,
1234 },
1235 Number {
1237 value: f64,
1239 #[serde(skip_serializing_if = "Option::is_none")]
1241 min: Option<f64>,
1242 #[serde(skip_serializing_if = "Option::is_none")]
1244 max: Option<f64>,
1245 #[serde(skip_serializing_if = "Option::is_none")]
1247 step: Option<f64>,
1248 #[serde(skip_serializing_if = "Option::is_none")]
1250 unit: Option<String>,
1251 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
1253 labels: BTreeMap<String, String>,
1254 },
1255 Text {
1257 value: String,
1259 #[serde(skip_serializing_if = "Option::is_none")]
1261 placeholder: Option<String>,
1262 #[serde(skip_serializing_if = "Option::is_none")]
1264 secret: Option<bool>,
1265 #[serde(skip_serializing_if = "Option::is_none")]
1267 mono: Option<bool>,
1268 },
1269 Keys {
1271 keys: Vec<Vec<String>>,
1273 },
1274 Multi {
1276 values: Vec<String>,
1278 options: Vec<ChoiceOption>,
1280 #[serde(skip_serializing_if = "Option::is_none")]
1282 ordered: Option<bool>,
1283 },
1284 Action {
1286 #[serde(skip_serializing_if = "Option::is_none")]
1288 act: Option<String>,
1289 #[serde(skip_serializing_if = "Option::is_none")]
1291 label: Option<String>,
1292 },
1293}
1294
1295#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1297pub struct Editing {
1298 pub row: String,
1300 #[serde(skip_serializing_if = "Option::is_none")]
1302 pub option: Option<String>,
1303 #[serde(skip_serializing_if = "Option::is_none")]
1305 pub draft: Option<String>,
1306 #[serde(skip_serializing_if = "Option::is_none")]
1308 pub cursor: Option<usize>,
1309}
1310
1311#[derive(Clone, Debug, PartialEq, Eq)]
1313pub enum MenuEntry {
1314 Act(String),
1316 Item(MenuItem),
1318 Header(String),
1320 Separator,
1322}
1323
1324impl MenuEntry {
1325 pub fn header(title: impl Into<String>) -> Self {
1327 Self::Header(title.into())
1328 }
1329}
1330
1331impl Serialize for MenuEntry {
1332 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1333 match self {
1334 Self::Act(act) => s.serialize_str(act),
1335 Self::Item(item) => item.serialize(s),
1336 Self::Header(title) => {
1337 let mut map = s.serialize_map(Some(1))?;
1338 map.serialize_entry("header", title)?;
1339 map.end()
1340 },
1341 Self::Separator => s.serialize_str("-"),
1342 }
1343 }
1344}
1345
1346impl From<&str> for MenuEntry {
1347 fn from(act: &str) -> Self {
1348 Self::Act(act.to_owned())
1349 }
1350}
1351
1352impl From<String> for MenuEntry {
1353 fn from(act: String) -> Self {
1354 Self::Act(act)
1355 }
1356}
1357
1358impl From<MenuItem> for MenuEntry {
1359 fn from(item: MenuItem) -> Self {
1360 Self::Item(item)
1361 }
1362}
1363
1364#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1367pub struct MenuItem {
1368 pub id: String,
1370 #[serde(skip_serializing_if = "Option::is_none")]
1372 pub label: Option<String>,
1373 #[serde(skip_serializing_if = "Option::is_none")]
1375 pub icon: Option<Icon>,
1376 #[serde(skip_serializing_if = "Vec::is_empty")]
1378 pub keys: Vec<String>,
1379 #[serde(skip_serializing_if = "Option::is_none")]
1381 pub detail: Option<String>,
1382 #[serde(skip_serializing_if = "Option::is_none")]
1384 pub checked: Option<bool>,
1385 #[serde(skip_serializing_if = "Option::is_none")]
1387 pub radio: Option<String>,
1388 #[serde(skip_serializing_if = "Option::is_none")]
1390 pub disabled: Option<Disabled>,
1391 #[serde(skip_serializing_if = "Option::is_none")]
1393 pub danger: Option<bool>,
1394 #[serde(skip_serializing_if = "Vec::is_empty")]
1396 pub items: Vec<MenuEntry>,
1397}
1398
1399impl MenuItem {
1400 pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
1402 Self { id: id.into(), label: Some(label.into()), ..Self::default() }
1403 }
1404
1405 pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
1407 self.icon = Some(icon.into());
1408 self
1409 }
1410
1411 pub fn keys<K: Into<String>>(mut self, keys: impl IntoIterator<Item = K>) -> Self {
1413 self.keys = keys.into_iter().map(Into::into).collect();
1414 self
1415 }
1416
1417 pub fn detail(mut self, detail: impl Into<String>) -> Self {
1419 self.detail = Some(detail.into());
1420 self
1421 }
1422
1423 pub const fn checked(mut self, checked: bool) -> Self {
1425 self.checked = Some(checked);
1426 self
1427 }
1428
1429 pub fn radio(mut self, group: impl Into<String>) -> Self {
1431 self.radio = Some(group.into());
1432 self
1433 }
1434
1435 pub fn disabled(mut self, disabled: impl Into<Disabled>) -> Self {
1437 self.disabled = Some(disabled.into());
1438 self
1439 }
1440
1441 pub const fn danger(mut self, danger: bool) -> Self {
1443 self.danger = Some(danger);
1444 self
1445 }
1446
1447 pub fn item(mut self, entry: impl Into<MenuEntry>) -> Self {
1449 self.items.push(entry.into());
1450 self
1451 }
1452}
1453
1454#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1456pub struct MenubarMenu {
1457 pub id: String,
1459 #[serde(skip_serializing_if = "Option::is_none")]
1461 pub label: Option<String>,
1462 pub items: Vec<MenuEntry>,
1464}
1465
1466impl MenubarMenu {
1467 pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
1469 Self { id: id.into(), label: Some(label.into()), ..Self::default() }
1470 }
1471
1472 pub fn item(mut self, entry: impl Into<MenuEntry>) -> Self {
1474 self.items.push(entry.into());
1475 self
1476 }
1477}
1478
1479#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1483pub struct ActButton {
1484 pub act: String,
1486 #[serde(skip_serializing_if = "Option::is_none")]
1488 pub text: Option<String>,
1489 #[serde(skip_serializing_if = "Option::is_none")]
1491 pub icon: Option<Icon>,
1492 #[serde(skip_serializing_if = "Option::is_none")]
1494 pub variant: Option<ButtonVariant>,
1495 #[serde(skip_serializing_if = "Vec::is_empty")]
1497 pub keys: Vec<String>,
1498 #[serde(skip_serializing_if = "Option::is_none")]
1500 pub title: Option<String>,
1501 #[serde(skip_serializing_if = "Option::is_none")]
1503 pub disabled: Option<Disabled>,
1504 #[serde(skip_serializing_if = "Option::is_none")]
1506 pub busy: Option<bool>,
1507}
1508
1509impl ActButton {
1510 pub fn new(act: impl Into<String>, text: impl Into<String>) -> Self {
1512 Self { act: act.into(), text: Some(text.into()), ..Self::default() }
1513 }
1514
1515 pub fn icon_only(act: impl Into<String>, icon: impl Into<Icon>) -> Self {
1517 Self { act: act.into(), icon: Some(icon.into()), ..Self::default() }
1518 }
1519
1520 pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
1522 self.icon = Some(icon.into());
1523 self
1524 }
1525
1526 pub fn variant(mut self, variant: impl Into<ButtonVariant>) -> Self {
1528 self.variant = Some(variant.into());
1529 self
1530 }
1531
1532 pub fn keys<K: Into<String>>(mut self, keys: impl IntoIterator<Item = K>) -> Self {
1534 self.keys = keys.into_iter().map(Into::into).collect();
1535 self
1536 }
1537
1538 pub fn title(mut self, title: impl Into<String>) -> Self {
1540 self.title = Some(title.into());
1541 self
1542 }
1543
1544 pub fn disabled(mut self, disabled: impl Into<Disabled>) -> Self {
1546 self.disabled = Some(disabled.into());
1547 self
1548 }
1549
1550 pub const fn busy(mut self, busy: bool) -> Self {
1552 self.busy = Some(busy);
1553 self
1554 }
1555}
1556
1557#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1559pub struct IconAction {
1560 pub act: String,
1562 #[serde(skip_serializing_if = "Option::is_none")]
1564 pub icon: Option<Icon>,
1565 #[serde(skip_serializing_if = "Option::is_none")]
1567 pub title: Option<String>,
1568}
1569
1570impl IconAction {
1571 pub fn new(act: impl Into<String>) -> Self {
1573 Self { act: act.into(), ..Self::default() }
1574 }
1575
1576 pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
1578 self.icon = Some(icon.into());
1579 self
1580 }
1581
1582 pub fn title(mut self, title: impl Into<String>) -> Self {
1584 self.title = Some(title.into());
1585 self
1586 }
1587}
1588
1589#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
1591pub struct Sort {
1592 pub col: String,
1594 pub dir: SortDir,
1596}
1597
1598impl Sort {
1599 pub fn asc(col: impl Into<String>) -> Self {
1601 Self { col: col.into(), dir: SortDir::Asc }
1602 }
1603
1604 pub fn desc(col: impl Into<String>) -> Self {
1606 Self { col: col.into(), dir: SortDir::Desc }
1607 }
1608}
1609
1610#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1612pub struct AskScope {
1613 pub id: String,
1615 #[serde(skip_serializing_if = "Option::is_none")]
1617 pub label: Option<String>,
1618}
1619
1620impl AskScope {
1621 pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
1623 Self { id: id.into(), label: Some(label.into()) }
1624 }
1625}
1626
1627#[derive(Clone, Debug, PartialEq, Eq)]
1629pub enum AskAlways {
1630 Label(String),
1632 Hidden,
1634}
1635
1636impl Serialize for AskAlways {
1637 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1638 match self {
1639 Self::Label(label) => s.serialize_str(label),
1640 Self::Hidden => s.serialize_bool(false),
1641 }
1642 }
1643}
1644
1645impl From<&str> for AskAlways {
1646 fn from(label: &str) -> Self {
1647 Self::Label(label.to_owned())
1648 }
1649}
1650
1651impl From<String> for AskAlways {
1652 fn from(label: String) -> Self {
1653 Self::Label(label)
1654 }
1655}
1656
1657#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1660pub struct Ask {
1661 #[serde(skip_serializing_if = "Option::is_none")]
1663 pub text: Option<String>,
1664 #[serde(skip_serializing_if = "Option::is_none")]
1666 pub allow: Option<String>,
1667 #[serde(skip_serializing_if = "Option::is_none")]
1669 pub deny: Option<String>,
1670 #[serde(skip_serializing_if = "Option::is_none")]
1672 pub always: Option<AskAlways>,
1673 #[serde(skip_serializing_if = "Vec::is_empty")]
1675 pub scopes: Vec<AskScope>,
1676 #[serde(skip_serializing_if = "Option::is_none")]
1678 pub scope: Option<String>,
1679}
1680
1681impl Ask {
1682 pub fn new(text: impl Into<String>) -> Self {
1684 Self { text: Some(text.into()), ..Self::default() }
1685 }
1686
1687 pub fn allow(mut self, label: impl Into<String>) -> Self {
1689 self.allow = Some(label.into());
1690 self
1691 }
1692
1693 pub fn deny(mut self, label: impl Into<String>) -> Self {
1695 self.deny = Some(label.into());
1696 self
1697 }
1698
1699 pub fn always(mut self, always: impl Into<AskAlways>) -> Self {
1701 self.always = Some(always.into());
1702 self
1703 }
1704
1705 pub fn scope_option(mut self, scope: AskScope) -> Self {
1707 self.scopes.push(scope);
1708 self
1709 }
1710
1711 pub fn scope(mut self, id: impl Into<String>) -> Self {
1713 self.scope = Some(id.into());
1714 self
1715 }
1716}
1717
1718#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1720pub struct SelectOption {
1721 pub value: String,
1723 #[serde(skip_serializing_if = "Option::is_none")]
1726 pub label: Option<String>,
1727 #[serde(skip_serializing_if = "Option::is_none")]
1729 pub detail: Option<String>,
1730 #[serde(skip_serializing_if = "Option::is_none")]
1732 pub icon: Option<Icon>,
1733 #[serde(skip_serializing_if = "Option::is_none")]
1735 pub group: Option<String>,
1736 #[serde(skip_serializing_if = "Option::is_none")]
1738 pub disabled: Option<bool>,
1739}
1740
1741impl SelectOption {
1742 pub fn new(value: impl Into<String>, label: impl Into<String>) -> Self {
1744 Self { value: value.into(), label: Some(label.into()), ..Self::default() }
1745 }
1746
1747 pub fn detail(mut self, detail: impl Into<String>) -> Self {
1749 self.detail = Some(detail.into());
1750 self
1751 }
1752
1753 pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
1755 self.icon = Some(icon.into());
1756 self
1757 }
1758
1759 pub fn group(mut self, group: impl Into<String>) -> Self {
1761 self.group = Some(group.into());
1762 self
1763 }
1764
1765 pub const fn disabled(mut self, disabled: bool) -> Self {
1767 self.disabled = Some(disabled);
1768 self
1769 }
1770}
1771
1772impl From<&str> for SelectOption {
1773 fn from(value: &str) -> Self {
1774 Self { value: value.to_owned(), ..Self::default() }
1775 }
1776}
1777
1778impl From<String> for SelectOption {
1779 fn from(value: String) -> Self {
1780 Self { value, ..Self::default() }
1781 }
1782}
1783
1784#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1786pub struct AvatarItem {
1787 pub text: String,
1789 #[serde(skip_serializing_if = "Option::is_none")]
1791 pub variant: Option<AvatarVariant>,
1792 #[serde(skip_serializing_if = "Option::is_none")]
1794 pub seed: Option<String>,
1795 #[serde(skip_serializing_if = "Option::is_none")]
1797 pub icon: Option<Icon>,
1798 #[serde(skip_serializing_if = "Option::is_none")]
1800 pub blob: Option<String>,
1801 #[serde(skip_serializing_if = "Option::is_none")]
1803 pub status: Option<Tone>,
1804 #[serde(skip_serializing_if = "Option::is_none")]
1806 pub title: Option<String>,
1807}
1808
1809impl AvatarItem {
1810 pub fn new(text: impl Into<String>) -> Self {
1812 Self { text: text.into(), ..Self::default() }
1813 }
1814
1815 pub fn variant(mut self, variant: impl Into<AvatarVariant>) -> Self {
1817 self.variant = Some(variant.into());
1818 self
1819 }
1820
1821 pub fn seed(mut self, seed: impl Into<String>) -> Self {
1823 self.seed = Some(seed.into());
1824 self
1825 }
1826
1827 pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
1829 self.icon = Some(icon.into());
1830 self
1831 }
1832
1833 pub fn blob(mut self, blob: impl Into<String>) -> Self {
1835 self.blob = Some(blob.into());
1836 self
1837 }
1838
1839 pub fn title(mut self, title: impl Into<String>) -> Self {
1841 self.title = Some(title.into());
1842 self
1843 }
1844}
1845
1846#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1848pub struct Crumb {
1849 pub id: String,
1851 #[serde(skip_serializing_if = "Option::is_none")]
1853 pub label: Option<String>,
1854 #[serde(skip_serializing_if = "Option::is_none")]
1856 pub icon: Option<Icon>,
1857 #[serde(skip_serializing_if = "Option::is_none")]
1859 pub href: Option<String>,
1860}
1861
1862impl Crumb {
1863 pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
1865 Self { id: id.into(), label: Some(label.into()), ..Self::default() }
1866 }
1867
1868 pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
1870 self.icon = Some(icon.into());
1871 self
1872 }
1873
1874 pub fn href(mut self, href: impl Into<String>) -> Self {
1876 self.href = Some(href.into());
1877 self
1878 }
1879}
1880
1881#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1883pub struct DayMark {
1884 pub date: String,
1886 #[serde(skip_serializing_if = "Option::is_none")]
1888 pub tone: Option<Tone>,
1889}
1890
1891impl DayMark {
1892 pub fn new(date: impl Into<String>, tone: impl Into<Tone>) -> Self {
1894 Self { date: date.into(), tone: Some(tone.into()) }
1895 }
1896}
1897
1898impl From<&str> for DayMark {
1899 fn from(date: &str) -> Self {
1900 Self { date: date.to_owned(), tone: None }
1901 }
1902}
1903
1904impl From<String> for DayMark {
1905 fn from(date: String) -> Self {
1906 Self { date, tone: None }
1907 }
1908}
1909
1910#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1912pub struct Preset {
1913 pub id: String,
1915 #[serde(skip_serializing_if = "Option::is_none")]
1917 pub label: Option<String>,
1918}
1919
1920impl Preset {
1921 pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
1923 Self { id: id.into(), label: Some(label.into()) }
1924 }
1925}
1926
1927#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1929pub struct NavItem {
1930 pub id: String,
1932 #[serde(skip_serializing_if = "Option::is_none")]
1934 pub label: Option<String>,
1935 #[serde(skip_serializing_if = "Option::is_none")]
1937 pub icon: Option<Icon>,
1938 #[serde(skip_serializing_if = "Option::is_none")]
1940 pub count: Option<String>,
1941 #[serde(skip_serializing_if = "Vec::is_empty")]
1943 pub items: Vec<NavSubItem>,
1944}
1945
1946impl NavItem {
1947 pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
1949 Self { id: id.into(), label: Some(label.into()), ..Self::default() }
1950 }
1951
1952 pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
1954 self.icon = Some(icon.into());
1955 self
1956 }
1957
1958 pub fn count(mut self, count: impl Into<String>) -> Self {
1960 self.count = Some(count.into());
1961 self
1962 }
1963
1964 pub fn item(mut self, item: NavSubItem) -> Self {
1966 self.items.push(item);
1967 self
1968 }
1969}
1970
1971#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1973pub struct NavSubItem {
1974 pub id: String,
1976 #[serde(skip_serializing_if = "Option::is_none")]
1978 pub label: Option<String>,
1979 #[serde(skip_serializing_if = "Option::is_none")]
1981 pub detail: Option<String>,
1982 #[serde(skip_serializing_if = "Option::is_none")]
1984 pub icon: Option<Icon>,
1985}
1986
1987impl NavSubItem {
1988 pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
1990 Self { id: id.into(), label: Some(label.into()), ..Self::default() }
1991 }
1992
1993 pub fn detail(mut self, detail: impl Into<String>) -> Self {
1995 self.detail = Some(detail.into());
1996 self
1997 }
1998
1999 pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
2001 self.icon = Some(icon.into());
2002 self
2003 }
2004}
2005
2006#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
2008pub struct Reaction {
2009 pub text: String,
2011 #[serde(skip_serializing_if = "Option::is_none")]
2013 pub count: Option<u32>,
2014 #[serde(skip_serializing_if = "Option::is_none")]
2016 pub on: Option<bool>,
2017}
2018
2019impl Reaction {
2020 pub fn new(text: impl Into<String>, count: u32) -> Self {
2022 Self { text: text.into(), count: Some(count), on: None }
2023 }
2024
2025 pub const fn on(mut self, on: bool) -> Self {
2027 self.on = Some(on);
2028 self
2029 }
2030}
2031
2032#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
2034pub struct Source {
2035 #[serde(skip_serializing_if = "Option::is_none")]
2037 pub title: Option<String>,
2038 #[serde(skip_serializing_if = "Option::is_none")]
2040 pub href: Option<String>,
2041 #[serde(skip_serializing_if = "Option::is_none")]
2043 pub site: Option<String>,
2044}
2045
2046impl Source {
2047 pub fn new(href: impl Into<String>) -> Self {
2049 Self { href: Some(href.into()), ..Self::default() }
2050 }
2051
2052 pub fn title(mut self, title: impl Into<String>) -> Self {
2054 self.title = Some(title.into());
2055 self
2056 }
2057
2058 pub fn site(mut self, site: impl Into<String>) -> Self {
2060 self.site = Some(site.into());
2061 self
2062 }
2063}
2064
2065#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
2067pub struct TraceLine {
2068 #[serde(skip_serializing_if = "Option::is_none")]
2071 pub id: Option<String>,
2072 #[serde(skip_serializing_if = "Option::is_none")]
2074 pub icon: Option<Icon>,
2075 #[serde(skip_serializing_if = "Option::is_none")]
2077 pub title: Option<Text>,
2078 #[serde(skip_serializing_if = "Option::is_none")]
2080 pub target: Option<Text>,
2081 #[serde(skip_serializing_if = "Option::is_none")]
2083 pub detail: Option<Text>,
2084 #[serde(skip_serializing_if = "Option::is_none")]
2086 pub status: Option<Status>,
2087 #[serde(skip_serializing_if = "Option::is_none")]
2089 pub age: Option<u64>,
2090 #[serde(skip_serializing_if = "Option::is_none")]
2092 pub took: Option<u64>,
2093 #[serde(skip_serializing_if = "Option::is_none")]
2095 pub open: Option<bool>,
2096 #[serde(skip_serializing_if = "Vec::is_empty")]
2098 pub sources: Vec<Source>,
2099}
2100
2101impl TraceLine {
2102 pub fn new(id: impl Into<String>, title: impl Into<Text>) -> Self {
2104 Self { id: Some(id.into()), title: Some(title.into()), ..Self::default() }
2105 }
2106
2107 pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
2109 self.icon = Some(icon.into());
2110 self
2111 }
2112
2113 pub fn target(mut self, target: impl Into<Text>) -> Self {
2115 self.target = Some(target.into());
2116 self
2117 }
2118
2119 pub fn detail(mut self, detail: impl Into<Text>) -> Self {
2121 self.detail = Some(detail.into());
2122 self
2123 }
2124
2125 pub fn status(mut self, status: impl Into<Status>) -> Self {
2127 self.status = Some(status.into());
2128 self
2129 }
2130
2131 pub const fn age(mut self, age: u64) -> Self {
2133 self.age = Some(age);
2134 self
2135 }
2136
2137 pub const fn took(mut self, took: u64) -> Self {
2139 self.took = Some(took);
2140 self
2141 }
2142
2143 pub const fn open(mut self, open: bool) -> Self {
2145 self.open = Some(open);
2146 self
2147 }
2148
2149 pub fn source(mut self, source: Source) -> Self {
2151 self.sources.push(source);
2152 self
2153 }
2154}
2155
2156#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
2158pub struct StackError {
2159 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
2161 pub kind: Option<String>,
2162 #[serde(skip_serializing_if = "Option::is_none")]
2164 pub message: Option<String>,
2165}
2166
2167impl StackError {
2168 pub fn new(kind: impl Into<String>, message: impl Into<String>) -> Self {
2170 Self { kind: Some(kind.into()), message: Some(message.into()) }
2171 }
2172}
2173
2174#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
2176pub struct Frame {
2177 #[serde(rename = "fn")]
2179 pub func: String,
2180 pub file: String,
2182 #[serde(skip_serializing_if = "Option::is_none")]
2184 pub line: Option<u32>,
2185 #[serde(skip_serializing_if = "Option::is_none")]
2187 pub col: Option<u32>,
2188 #[serde(skip_serializing_if = "Option::is_none")]
2190 pub app: Option<bool>,
2191 #[serde(skip_serializing_if = "Option::is_none")]
2193 pub code: Option<FrameCode>,
2194}
2195
2196impl Frame {
2197 pub fn new(func: impl Into<String>, file: impl Into<String>) -> Self {
2199 Self { func: func.into(), file: file.into(), ..Self::default() }
2200 }
2201
2202 pub const fn at(mut self, line: u32, col: u32) -> Self {
2204 self.line = Some(line);
2205 self.col = Some(col);
2206 self
2207 }
2208
2209 pub const fn line(mut self, line: u32) -> Self {
2211 self.line = Some(line);
2212 self
2213 }
2214
2215 pub const fn app(mut self, app: bool) -> Self {
2217 self.app = Some(app);
2218 self
2219 }
2220
2221 pub fn code(mut self, code: FrameCode) -> Self {
2223 self.code = Some(code);
2224 self
2225 }
2226}
2227
2228#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
2230pub struct FrameCode {
2231 #[serde(skip_serializing_if = "Option::is_none")]
2233 pub start: Option<u32>,
2234 pub lines: Vec<String>,
2236 #[serde(skip_serializing_if = "Option::is_none")]
2238 pub line: Option<u32>,
2239}
2240
2241impl FrameCode {
2242 pub fn new<L: Into<String>>(start: u32, lines: impl IntoIterator<Item = L>) -> Self {
2244 Self { start: Some(start), lines: lines.into_iter().map(Into::into).collect(), line: None }
2245 }
2246
2247 pub const fn line(mut self, line: u32) -> Self {
2249 self.line = Some(line);
2250 self
2251 }
2252}
2253
2254#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
2256pub struct Suggestion {
2257 #[serde(skip_serializing_if = "Option::is_none")]
2259 pub id: Option<String>,
2260 pub text: String,
2262 #[serde(skip_serializing_if = "Option::is_none")]
2265 pub detail: Option<String>,
2266 #[serde(skip_serializing_if = "Option::is_none")]
2268 pub icon: Option<Icon>,
2269 #[serde(skip_serializing_if = "Option::is_none")]
2272 pub keys: Option<Vec<String>>,
2273}
2274
2275impl Suggestion {
2276 pub fn new(text: impl Into<String>) -> Self {
2278 Self { text: text.into(), ..Self::default() }
2279 }
2280
2281 pub fn id(mut self, id: impl Into<String>) -> Self {
2283 self.id = Some(id.into());
2284 self
2285 }
2286
2287 pub fn detail(mut self, detail: impl Into<String>) -> Self {
2289 self.detail = Some(detail.into());
2290 self
2291 }
2292
2293 pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
2295 self.icon = Some(icon.into());
2296 self
2297 }
2298
2299 pub fn keys<K: Into<String>>(mut self, keys: impl IntoIterator<Item = K>) -> Self {
2301 self.keys = Some(keys.into_iter().map(Into::into).collect());
2302 self
2303 }
2304}
2305
2306#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
2308pub struct Question {
2309 pub id: String,
2311 #[serde(skip_serializing_if = "Option::is_none")]
2313 pub prompt: Option<String>,
2314 #[serde(skip_serializing_if = "Option::is_none")]
2316 pub description: Option<String>,
2317 #[serde(skip_serializing_if = "Vec::is_empty")]
2319 pub choices: Vec<QuestionChoice>,
2320 #[serde(skip_serializing_if = "Option::is_none")]
2322 pub multi: Option<bool>,
2323 #[serde(skip_serializing_if = "Option::is_none")]
2325 pub other: Option<OtherAnswer>,
2326 #[serde(skip_serializing_if = "Option::is_none")]
2328 pub required: Option<bool>,
2329}
2330
2331impl Question {
2332 pub fn new(id: impl Into<String>, prompt: impl Into<String>) -> Self {
2334 Self { id: id.into(), prompt: Some(prompt.into()), ..Self::default() }
2335 }
2336
2337 pub fn description(mut self, description: impl Into<String>) -> Self {
2339 self.description = Some(description.into());
2340 self
2341 }
2342
2343 pub fn choice(mut self, choice: impl Into<QuestionChoice>) -> Self {
2345 self.choices.push(choice.into());
2346 self
2347 }
2348
2349 pub const fn multi(mut self, multi: bool) -> Self {
2351 self.multi = Some(multi);
2352 self
2353 }
2354
2355 pub fn other(mut self, other: impl Into<OtherAnswer>) -> Self {
2357 self.other = Some(other.into());
2358 self
2359 }
2360
2361 pub const fn required(mut self, required: bool) -> Self {
2363 self.required = Some(required);
2364 self
2365 }
2366}
2367
2368#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
2370pub struct QuestionChoice {
2371 pub value: String,
2373 #[serde(skip_serializing_if = "Option::is_none")]
2375 pub label: Option<String>,
2376 #[serde(skip_serializing_if = "Option::is_none")]
2378 pub detail: Option<String>,
2379}
2380
2381impl QuestionChoice {
2382 pub fn new(value: impl Into<String>, label: impl Into<String>) -> Self {
2384 Self { value: value.into(), label: Some(label.into()), detail: None }
2385 }
2386
2387 pub fn detail(mut self, detail: impl Into<String>) -> Self {
2389 self.detail = Some(detail.into());
2390 self
2391 }
2392}
2393
2394impl From<&str> for QuestionChoice {
2395 fn from(value: &str) -> Self {
2396 Self { value: value.to_owned(), ..Self::default() }
2397 }
2398}
2399
2400impl From<String> for QuestionChoice {
2401 fn from(value: String) -> Self {
2402 Self { value, ..Self::default() }
2403 }
2404}
2405
2406#[derive(Clone, Debug, PartialEq, Eq)]
2408pub enum OtherAnswer {
2409 Flag(bool),
2411 Placeholder(String),
2413}
2414
2415impl Serialize for OtherAnswer {
2416 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
2417 match self {
2418 Self::Flag(on) => s.serialize_bool(*on),
2419 Self::Placeholder(placeholder) => {
2420 let mut map = s.serialize_map(Some(1))?;
2421 map.serialize_entry("placeholder", placeholder)?;
2422 map.end()
2423 },
2424 }
2425 }
2426}
2427
2428impl From<bool> for OtherAnswer {
2429 fn from(on: bool) -> Self {
2430 Self::Flag(on)
2431 }
2432}
2433
2434impl From<&str> for OtherAnswer {
2435 fn from(placeholder: &str) -> Self {
2436 Self::Placeholder(placeholder.to_owned())
2437 }
2438}
2439
2440impl From<String> for OtherAnswer {
2441 fn from(placeholder: String) -> Self {
2442 Self::Placeholder(placeholder)
2443 }
2444}
2445
2446#[derive(Clone, Debug, PartialEq, Eq)]
2449pub enum QuestionAnswer {
2450 One(String),
2452 Many(Vec<String>),
2454}
2455
2456impl Serialize for QuestionAnswer {
2457 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
2458 match self {
2459 Self::One(value) => s.serialize_str(value),
2460 Self::Many(values) => values.serialize(s),
2461 }
2462 }
2463}
2464
2465impl From<&str> for QuestionAnswer {
2466 fn from(value: &str) -> Self {
2467 Self::One(value.to_owned())
2468 }
2469}
2470
2471impl From<String> for QuestionAnswer {
2472 fn from(value: String) -> Self {
2473 Self::One(value)
2474 }
2475}
2476
2477impl From<Vec<String>> for QuestionAnswer {
2478 fn from(values: Vec<String>) -> Self {
2479 Self::Many(values)
2480 }
2481}