[pdm-devel] [PATCH yew-comp 1/1] form: add helpers for property strings

Dominik Csapak d.csapak at proxmox.com
Fri Jan 10 11:21:37 CET 2025


when handling property strings in edit windows/input panels, we want to
have a consistent and easy way to handle them.

This introduces two helpers for parsing the property string into
separate parts (`flatten_property_string`) and one to generate the
property string again from parts (`property_string_from_parts`)

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 src/form/mod.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/lib.rs      |  2 ++
 2 files changed, 75 insertions(+)
 create mode 100644 src/form/mod.rs

diff --git a/src/form/mod.rs b/src/form/mod.rs
new file mode 100644
index 0000000..9661c28
--- /dev/null
+++ b/src/form/mod.rs
@@ -0,0 +1,73 @@
+use serde::{de::DeserializeOwned, Serialize};
+use serde_json::{json, Value};
+
+use proxmox_schema::{ApiType, ObjectSchemaType, Schema};
+
+#[inline]
+fn format_property(name: &str, part: &str) -> String {
+    format!("_{name}_{part}")
+}
+
+/// Convert a property string to separate properties
+///
+/// This is useful for use in an [`crate::EditWindow`] when editing parts of a property string.
+/// Takes the `name` property from `data`, parses it a s property string, and sets it back to
+/// `data` as `_{name}_{key}` so this should be used as a field. If it's not desired
+/// to expose a property to the UI, simply add a hidden field to the form.
+pub fn flatten_property_string(data: &mut Value, name: &str, schema: &'static Schema) {
+    if let Some(prop_str) = data[name].as_str() {
+        if let Ok(Value::Object(map)) = schema.parse_property_string(&prop_str) {
+            for (part, v) in map {
+                data[format_property(name, &part)] = v;
+            }
+        }
+    }
+}
+
+/// Uses an [`proxmox_schema::ObjectSchema`] to generate a property string from separate properties.
+///
+/// This is useful for use in an [`crate::EditWindow`] when editing parts of a property string.
+/// Takes the single properties from `data` and adds it as a property string as `name`.
+pub fn property_string_from_parts<T: ApiType + Serialize + DeserializeOwned>(
+    data: &mut Value,
+    name: &str,
+    skip_empty_values: bool,
+) {
+    let props = match T::API_SCHEMA {
+        Schema::Object(object_schema) => object_schema.properties(),
+        _ => return, // not supported
+    };
+
+    if let Value::Object(map) = data {
+        let mut value = json!({});
+
+        let mut has_parts = false;
+        for (part, _, _) in props {
+            if let Some(v) = map.remove(&format_property(name, part)) {
+                has_parts = true;
+                let is_empty = match &v {
+                    Value::String(s) => s.is_empty(),
+                    _ => false,
+                };
+                if !(skip_empty_values && is_empty) {
+                    value[part] = v;
+                }
+            }
+        }
+
+        if !has_parts {
+            return;
+        }
+
+        let parsed: Option<T> = serde_json::from_value(value).ok();
+
+        if let Some(parsed) = parsed {
+            match proxmox_schema::property_string::print(&parsed) {
+                Ok(prop_string) => data[name] = prop_string.into(),
+                Err(err) => log::error!("error during property string print for {name}: {err}"),
+            }
+        } else {
+            data[name] = "".into();
+        }
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index a4d68c4..091cb72 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -45,6 +45,8 @@ pub use confirm_button::{ConfirmButton, ProxmoxConfirmButton};
 mod data_view_window;
 pub use data_view_window::{DataViewWindow, ProxmoxDataViewWindow};
 
+pub mod form;
+
 pub mod gauge;
 pub use gauge::{Gauge, ProxmoxGauge};
 
-- 
2.39.5





More information about the pdm-devel mailing list