From 08821aaaaf8638ca038be0aacf562ff0ae63e6ae Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 3 Jan 2025 14:15:17 +0300 Subject: [PATCH] feat(items-list): enable dynamic custom properties - Edited ItemsList to support dynamic custom properties for each item, managed via HashMap. - Introduced a UI input for users to add new properties dynamically. --- src/components/items_list.rs | 116 ++++++++++++++++++++++++++--------- src/models/item.rs | 3 +- 2 files changed, 90 insertions(+), 29 deletions(-) diff --git a/src/components/items_list.rs b/src/components/items_list.rs index 557373a..3f9f2f6 100644 --- a/src/components/items_list.rs +++ b/src/components/items_list.rs @@ -5,7 +5,9 @@ use serde::Deserialize; use uuid::Uuid; use leptos::logging::log; use crate::models::item::Item; +use std::collections::HashMap; use std::sync::{Arc, Mutex}; +use wasm_bindgen::JsCast; #[derive(Deserialize, Clone, Debug)] struct WikidataSuggestion { @@ -19,6 +21,8 @@ pub fn ItemsList( items: ReadSignal>, set_items: WriteSignal>, ) -> impl IntoView { + // State to manage dynamic property names + let (custom_properties, set_custom_properties) = create_signal(Vec::::new()); // Ensure there's an initial empty row set_items.set(vec![Item { @@ -28,6 +32,7 @@ pub fn ItemsList( tags: vec![], reviews: vec![], wikidata_id: None, + custom_properties: HashMap::new(), }]); let (wikidata_suggestions, set_wikidata_suggestions) = @@ -69,7 +74,10 @@ pub fn ItemsList( "description" => { item.description = value.clone(); } - _ => (), + _ => { + // Update custom property + item.custom_properties.insert(field.to_string(), value.clone()); + } } } @@ -82,11 +90,21 @@ pub fn ItemsList( tags: vec![], reviews: vec![], wikidata_id: None, + custom_properties: HashMap::new(), }); } }); }; + // Add a new custom property + let add_property = move |property: String| { + set_custom_properties.update(|props| { + if !props.contains(&property) && !property.is_empty() { + props.push(property); + } + }); + }; + // Add a new tag to an item let add_tag = move |index: usize, key: String, value: String| { set_items.update(|items| { @@ -100,7 +118,7 @@ pub fn ItemsList( let remove_tag = move |item_index: usize, tag_index: usize| { set_items.update(|items| { if let Some(item) = items.get_mut(item_index) { - item.tags.remove(tag_index); + item.tags.remove(tag_index); } }); }; @@ -108,7 +126,7 @@ pub fn ItemsList( // Remove an item let remove_item = move |index: usize| { set_items.update(|items| { - items.remove(index); + items.remove(index); }); }; @@ -135,16 +153,16 @@ pub fn ItemsList( { property } {move || items.get().iter().enumerate().map(|(index, item)| { - view! { - + view! { + {match property { "Name" => view! { - -
    + /> +
      {move || { let suggestions = wikidata_suggestions.get().to_vec(); suggestions.into_iter().map(|suggestion| { @@ -160,37 +178,37 @@ pub fn ItemsList( ("wikidata_id".to_string(), id.clone()), ]; - view! { -
    • + } + }); + }> { format!("{} - {}", label_for_display, description_for_display) } -
    • - } + + } }).collect::>() }} -
    +
}.into_view(), "Description" => view! { - + /> }.into_view(), "Tags" => view! { - + /> }.into_view(), "Actions" => view! { @@ -199,14 +217,56 @@ pub fn ItemsList( { "" } }.into_view(), }} - - } + + } }).collect::>()} } - }).collect::>()} + }).collect::>()} + // Dynamically adding custom properties as columns + {move || { + let custom_props = custom_properties.get().clone(); + custom_props.into_iter().map(move |property| { + let property_clone = property.clone(); + view! { + + { property } + {move || { + let property_clone = property_clone.clone(); // Clone `property_clone` again for the inner closure + items.get().iter().enumerate().map(move |(index, item)| { + let property_clone_for_closure = property_clone.clone(); + view! { + + + + } + }).collect::>() + }} + + } + }).collect::>() + }} +
+ + +
} } diff --git a/src/models/item.rs b/src/models/item.rs index efb9d2f..6b031a2 100644 --- a/src/models/item.rs +++ b/src/models/item.rs @@ -1,7 +1,7 @@ /// Represents an Item in CompareWare. /// Each item has metadata and key-value tags for categorization. use serde::{Deserialize, Serialize}; - +use std::collections::HashMap; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Item { pub id: String, @@ -10,6 +10,7 @@ pub struct Item { pub tags: Vec<(String, String)>, pub reviews: Vec, pub wikidata_id: Option, + pub custom_properties: HashMap, } #[derive(Serialize, Deserialize, Debug, Clone)]