diff --git a/src/components/items_list.rs b/src/components/items_list.rs index b988cda..2a8532e 100644 --- a/src/components/items_list.rs +++ b/src/components/items_list.rs @@ -597,59 +597,65 @@ pub fn ItemsList( let set_property_labels = set_property_labels.clone(); let property_cache = property_cache.clone(); let set_property_cache = set_property_cache.clone(); + let set_custom_properties = set_custom_properties.clone(); + let set_selected_properties = set_selected_properties.clone(); + Arc::new(move |property: String| { - // Normalize the property ID - let normalized_property = property.replace("http://www.wikidata.org/prop/", ""); - let normalized_property_clone = normalized_property.clone(); - - // Check if property is empty - if normalized_property.is_empty() { - log!("Attempted to add empty property, ignoring"); - return; - } - - // Check if label already exists - if !property_labels.get().contains_key(&normalized_property) { - spawn_local({ - let normalized_property = normalized_property.clone(); - let set_property_labels = set_property_labels.clone(); - async move { - // Add a placeholder label while fetching - set_property_labels.update(|map| { - map.insert(normalized_property.clone(), normalized_property.clone()); - }); - - match fetch_property_labels(vec![normalized_property.clone()]).await { + // Normalize the property ID + let normalized_property = property.replace("http://www.wikidata.org/prop/", ""); + + // Early return if property is empty + if normalized_property.is_empty() { + log!("Attempted to add empty property, ignoring"); + return; + } + + // Create local copies of all signals to avoid capturing them in closures + let property_labels_snapshot = property_labels.get(); + let selected_properties_snapshot = selected_properties.get(); + let custom_properties_snapshot = custom_properties.get(); + + // Check if label already exists + if !property_labels_snapshot.contains_key(&normalized_property) { + let normalized_property_clone = normalized_property.clone(); + let set_property_labels_clone = set_property_labels.clone(); + + // Add a placeholder label immediately + set_property_labels.update(|map| { + map.insert(normalized_property_clone.clone(), normalized_property_clone.clone()); + }); + + // Fetch the actual label in a separate task + spawn_local(async move { + match fetch_property_labels(vec![normalized_property_clone.clone()]).await { Ok(labels) => { - set_property_labels.update(|map| { + set_property_labels_clone.update(|map| { map.extend(labels); }); }, Err(e) => { log!("Error fetching property labels: {:?}", e); - // Keep the placeholder label } } - } - }); - } - - // Check if property is already selected - if !selected_properties.get().contains_key(&normalized_property) && !normalized_property.is_empty() { - // Add property to selected properties - set_selected_properties.update(|selected| { - selected.insert(normalized_property.clone(), true); - }); - - // Save the selected property to the database - spawn_local({ - let current_url = Rc::clone(¤t_url); - let normalized_property = normalized_property_clone.clone(); - async move { + }); + } + + // Check if property is already selected + if !selected_properties_snapshot.contains_key(&normalized_property) { + // Add property to selected properties + set_selected_properties.update(|selected| { + selected.insert(normalized_property.clone(), true); + }); + + // Save the selected property to the database + let current_url_clone = Rc::clone(¤t_url); + let normalized_property_clone = normalized_property.clone(); + + spawn_local(async move { let response = gloo_net::http::Request::post( - &format!("/api/urls/{}/properties", encode(¤t_url)) + &format!("/api/urls/{}/properties", encode(¤t_url_clone)) ) - .json(&normalized_property) + .json(&normalized_property_clone) .unwrap() .send() .await; @@ -666,85 +672,84 @@ pub fn ItemsList( log!("Error saving property: {:?}", err); } } - } - }); - } - - set_custom_properties.update(|props| { - if !props.contains(&normalized_property) && !normalized_property.is_empty() { - props.push(normalized_property.clone()); - - //update the selected_properties state when a new property is added - set_selected_properties.update(|selected| { - selected.insert(normalized_property.clone(), true); }); - - // Ensure the grid updates reactively + } + + // Update custom properties if not already present + if !custom_properties_snapshot.contains(&normalized_property) { + set_custom_properties.update(|props| { + props.push(normalized_property.clone()); + }); + + // Update items with the new property set_items.update(|items| { for item in items { - // Safely insert the property if it doesn't exist + // Only add if it doesn't exist if !item.custom_properties.contains_key(&normalized_property) { item.custom_properties.insert(normalized_property.clone(), "".to_string()); } - - // Save the updated item to the database - let item_clone = item.clone(); - spawn_local({ - let current_url = Rc::clone(¤t_url); - async move { - save_item_to_db(item_clone, selected_properties, current_url.to_string()).await; - } - }); } }); - - // Use the property label from the property_labels signal - let property_label = property_labels.get().get(&normalized_property).cloned().unwrap_or_else(|| normalized_property.clone()); + + // Save each item to the database + let items_snapshot = items.get(); + for item in items_snapshot { + let item_clone = item.clone(); + let current_url_clone = Rc::clone(¤t_url); + let selected_properties_clone = selected_properties; + + spawn_local(async move { + save_item_to_db(item_clone, selected_properties_clone, current_url_clone.to_string()).await; + }); + } + + // Log the addition + let property_label = property_labels_snapshot + .get(&normalized_property) + .cloned() + .unwrap_or_else(|| normalized_property.clone()); + log!("Added property with label: {}", property_label); - } - }); - // Fetch the relevant value for each item and populate the corresponding cells - set_items.update(|items| { - for item in items { - // Initialize property with empty string if it doesn't exist - item.custom_properties.entry(normalized_property.clone()) - .or_insert_with(|| "".to_string()); - - // Only fetch properties if Wikidata ID exists + + // Fetch Wikidata properties for items with IDs + let items_snapshot = items.get(); + for item in items_snapshot { if let Some(wikidata_id) = &item.wikidata_id { - let wikidata_id = wikidata_id.clone(); - let set_items = set_items.clone(); - let set_fetched_properties = set_fetched_properties.clone(); - let property_clone = normalized_property.clone(); + let wikidata_id_clone = wikidata_id.clone(); + let normalized_property_clone = normalized_property.clone(); + let set_items_clone = set_items.clone(); + let set_property_labels_clone = set_property_labels.clone(); + let property_cache_clone = property_cache.clone(); + let set_property_cache_clone = set_property_cache.clone(); + let property_labels_clone = property_labels.clone(); spawn_local(async move { let properties = fetch_item_properties( - &wikidata_id, - set_property_labels.clone(), - property_cache.clone(), - set_property_cache.clone(), - property_labels.clone() + &wikidata_id_clone, + set_property_labels_clone, + property_cache_clone, + set_property_cache_clone, + property_labels_clone ).await; - - // Update the specific property for this item - if let Some(value) = properties.get(&property_clone) { - set_items.update(|items| { - if let Some(item) = items.iter_mut() - .find(|i| i.wikidata_id.as_ref() == Some(&wikidata_id)) - { - item.custom_properties.insert( - property_clone.clone(), - value.clone() - ); + + if let Some(value) = properties.get(&normalized_property_clone) { + set_items_clone.update(|items| { + for item in items { + if item.wikidata_id.as_ref() == Some(&wikidata_id_clone) { + item.custom_properties.insert( + normalized_property_clone.clone(), + value.clone() + ); + } } }); } }); } } - }); - })}; + }) + }; // Update item fields let update_item = { @@ -835,19 +840,22 @@ pub fn ItemsList(
- {properties.into_iter().map(|property| { - let update_item_cloned = Arc::clone(&update_item); - let current_url_for_closure = Rc::clone(¤t_url); - log!("Rendering property: {}", property); - view! { -