[pdm-devel] [PATCH datacenter-manager] ui: search box: close if user navigated to an entry

Dominik Csapak d.csapak at proxmox.com
Fri Sep 5 09:29:20 CEST 2025


either by clicking or using the keyboard. For this we need to add a new
'on_navigate' callback in the ResourceTree that triggers when the user
navigated away.

While at it, refactor the navigation callbacks into the update method.

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 ui/src/widget/resource_tree.rs | 66 ++++++++++++++++++----------------
 ui/src/widget/search_box.rs    |  6 ++++
 2 files changed, 42 insertions(+), 30 deletions(-)

diff --git a/ui/src/widget/resource_tree.rs b/ui/src/widget/resource_tree.rs
index aefcaf6..708df65 100644
--- a/ui/src/widget/resource_tree.rs
+++ b/ui/src/widget/resource_tree.rs
@@ -4,7 +4,7 @@ use anyhow::Error;
 use gloo_timers::callback::Timeout;
 use serde_json::json;
 use web_sys::window;
-use yew::{virtual_dom::Key, Component};
+use yew::{html::IntoEventCallback, virtual_dom::Key, Component};
 
 use pwt::{
     css::{FlexFit, FontColor},
@@ -48,6 +48,11 @@ pub struct ResourceTree {
     #[builder]
     /// If this is true, we wait with the load until we have a search term
     pub search_only: bool,
+
+    #[prop_or_default]
+    #[builder_cb(IntoEventCallback, into_event_callback, ())]
+    /// Triggered after the user navigated to an entry by clicking or using the keyboard
+    pub on_navigate: Option<Callback<()>>,
 }
 
 impl ResourceTree {
@@ -91,6 +96,7 @@ pub enum Msg {
     Load,
     LoadResult(Result<Vec<RemoteResources>, Error>),
     RemoteListChanged(RemoteList),
+    NavigateToEntry(Key),
 }
 
 pub struct PdmResourceTree {
@@ -193,6 +199,32 @@ impl Component for PdmResourceTree {
                 }
                 true
             }
+            Msg::NavigateToEntry(key) => {
+                let store = self.store.read();
+                let root = store.root().unwrap();
+
+                let mut navigated = false;
+                if let Some(node) = root.find_node_by_key(&key) {
+                    match node.record() {
+                        PdmTreeEntry::Root => {}
+                        PdmTreeEntry::Resource(remote, resource) => {
+                            crate::navigate_to(ctx.link(), remote, Some(resource));
+                            navigated = true;
+                        }
+                        PdmTreeEntry::Remote(remote, _) => {
+                            crate::navigate_to(ctx.link(), remote, None);
+                            navigated = true;
+                        }
+                    }
+                }
+
+                if navigated {
+                    if let Some(cb) = &ctx.props().on_navigate {
+                        cb.emit(());
+                    }
+                }
+                false
+            }
         }
     }
 
@@ -217,30 +249,16 @@ impl Component for PdmResourceTree {
         let table = DataTable::new(columns(ctx.link(), self.store.clone()), self.store.clone())
             .selection(self.selection.clone())
             .on_row_click({
-                let store = self.store.clone();
                 let link = ctx.link().clone();
                 move |event: &mut DataTableMouseEvent| {
-                    let store = store.read();
-                    let root = store.root().unwrap();
-
-                    if let Some(node) = root.find_node_by_key(&event.record_key) {
-                        navigate_to_entry(&link, node.record());
-                    }
+                    link.send_message(Msg::NavigateToEntry(event.record_key.clone()));
                 }
             })
             .on_row_keydown({
-                let store = self.store.clone();
                 let link = ctx.link().clone();
                 move |event: &mut DataTableKeyboardEvent| {
-                    let store = store.read();
-                    let root = store.root().unwrap();
-
-                    if event.key().as_str() != "Enter" {
-                        return;
-                    }
-
-                    if let Some(node) = root.find_node_by_key(&event.record_key) {
-                        navigate_to_entry(&link, node.record());
+                    if let "Enter" | " " = event.key().as_str() {
+                        link.send_message(Msg::NavigateToEntry(event.record_key.clone()))
                     }
                 }
             })
@@ -286,18 +304,6 @@ impl Component for PdmResourceTree {
     }
 }
 
-fn navigate_to_entry(link: &html::Scope<PdmResourceTree>, record: &PdmTreeEntry) {
-    match record {
-        PdmTreeEntry::Root => {}
-        PdmTreeEntry::Resource(remote, resource) => {
-            crate::navigate_to(link, remote, Some(resource));
-        }
-        PdmTreeEntry::Remote(remote, _) => {
-            crate::navigate_to(link, remote, None);
-        }
-    }
-}
-
 fn columns(
     link: &html::Scope<PdmResourceTree>,
     store: TreeStore<PdmTreeEntry>,
diff --git a/ui/src/widget/search_box.rs b/ui/src/widget/search_box.rs
index 52bb156..3a52411 100644
--- a/ui/src/widget/search_box.rs
+++ b/ui/src/widget/search_box.rs
@@ -40,6 +40,7 @@ pub enum Msg {
     ChangeTerm(String, bool), // force value
     FocusChange(bool),
     ToggleFocus,
+    NavigatedToEntry,
 }
 
 pub struct PdmSearchBox {
@@ -105,6 +106,10 @@ impl Component for PdmSearchBox {
                 self.toggle_focus = true;
                 true
             }
+            Msg::NavigatedToEntry => {
+                self.focus = false;
+                true
+            }
         }
     }
 
@@ -126,6 +131,7 @@ impl Component for PdmSearchBox {
             .border(true)
             .width(CssLength::Fraction(0.5))
             .height(400)
+            .on_navigate(ctx.link().callback(|_| Msg::NavigatedToEntry))
             .class("pwt-shadow2");
 
         let clear_trigger_icon = if self.search_term.is_empty() {
-- 
2.47.2





More information about the pdm-devel mailing list