[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