balena_cdsl/output/serialization/
ui_object.rs1use std::collections::HashMap;
2use serde::ser::SerializeMap;
3
4use crate::dsl::schema::DocumentRoot;
5use crate::dsl::schema::Schema;
6use crate::dsl::schema::SchemaList;
7use crate::output::UiObject;
8use crate::output::UiObjectProperty;
9use crate::output::UiObjectRoot;
10use serde::Serialize;
11use serde::Serializer;
12use crate::dsl::schema::KeysSchema;
13use crate::output::UiOptions;
14use crate::dsl::schema::Annotations;
15use crate::dsl::schema::Widget;
16use crate::dsl::schema::object_types::RawObjectType;
17
18impl From<DocumentRoot> for UiObjectRoot {
19 fn from(root: DocumentRoot) -> Self {
20 UiObjectRoot(Some(root.schema().into()))
21 }
22}
23
24impl From<SchemaList> for UiObject {
25 fn from(list: SchemaList) -> Self {
26 let ui_object_entries: Vec<(String, UiObjectProperty)> = list
27 .entries()
28 .iter()
29 .filter_map(|entry| {
30 let property: UiObjectProperty = entry.schema.clone().into();
31 if !property.is_empty() {
32 Some((entry.name.clone(), property))
33 } else {
34 None
35 }
36 })
37 .collect();
38
39 let ui_object_entries: HashMap<String, UiObjectProperty> = ui_object_entries.into_iter().collect();
40 UiObject(ui_object_entries)
41 }
42}
43
44impl From<Schema> for UiObjectProperty {
45 fn from(schema: Schema) -> Self {
46 let annotations = schema.annotations.clone();
47 let (help, warning, description) = help_warning_description(&annotations);
48 let widget = widget(&schema);
49 let placeholder = placeholder(&annotations);
50 let readonly = readonly(&annotations);
51 let keys_values = schema.dynamic.map(|keys_values| keys_values.keys);
52
53 let children = schema.children;
54 let children_ui_objects = children.clone().map(|children| children.into());
55 let order = children
56 .clone()
57 .map(|list| list.all_names().iter().map(|name| name.to_string()).collect());
58
59 let ui_options = ui_options(&annotations);
60
61 UiObjectProperty {
62 help,
63 warning,
64 description,
65 placeholder,
66 widget,
67 properties: children_ui_objects,
68 keys: keys_values,
69 ui_options,
70 readonly,
71 order,
72 }
73 }
74}
75
76impl Serialize for KeysSchema {
77 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
78 where
79 S: Serializer,
80 {
81 let mut map = serializer.serialize_map(None)?;
82 if let Some(title) = &self.title {
83 let mut keys_definition = HashMap::new();
84 keys_definition.insert("ui:title", title);
85 map.serialize_entry("ui:keys", &keys_definition)?;
86 }
87 map.end()
88 }
89}
90
91fn ui_options(annotations: &Annotations) -> Option<UiOptions> {
92 let default_ui_options = UiOptions::default();
93 let ui_options = UiOptions {
94 removable: annotations.removable.unwrap_or(default_ui_options.removable),
95 addable: annotations.addable.unwrap_or(default_ui_options.addable),
96 orderable: annotations.orderable.unwrap_or(default_ui_options.orderable),
97 };
98 if ui_options == default_ui_options {
99 None
100 } else {
101 Some(ui_options)
102 }
103}
104
105fn widget(schema: &Schema) -> Option<Widget> {
106 let annotations = &schema.annotations;
107 if let RawObjectType::Password(_) = schema.object_type.inner_raw() {
108 return Some(Widget::Password);
109 }
110 if annotations.writeonly.unwrap_or(false) {
111 return Some(Widget::Password);
112 }
113 if annotations.hidden.unwrap_or(false) {
114 return Some(Widget::Hidden);
115 }
116 annotations.widget.clone()
117}
118
119fn help_warning_description(annotations: &Annotations) -> (Option<String>, Option<String>, Option<String>) {
120 let help = &annotations.help;
121 let warning = &annotations.warning;
122 let description = &annotations.description;
123 (help.clone(), warning.clone(), description.clone())
124}
125
126fn placeholder(annotations: &Annotations) -> Option<String> {
127 let placeholder = &annotations.placeholder;
128 placeholder.clone()
129}
130
131fn readonly(annotations: &Annotations) -> Option<bool> {
132 annotations.readonly
133}