From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 985691FF165 for ; Thu, 23 Oct 2025 13:19:07 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 1B3A37CF2; Thu, 23 Oct 2025 13:19:35 +0200 (CEST) Mime-Version: 1.0 Date: Thu, 23 Oct 2025 13:19:00 +0200 Message-Id: To: "Dominik Csapak" X-Mailer: aerc 0.20.0 References: <20251023083253.1038119-1-d.csapak@proxmox.com> <20251023083253.1038119-2-d.csapak@proxmox.com> In-Reply-To: <20251023083253.1038119-2-d.csapak@proxmox.com> From: "Shannon Sterz" X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1761218332800 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.055 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: Re: [pdm-devel] [PATCH datacenter-manager v2 01/16] ui: dashboard: refactor guest panel creation to its own module X-BeenThere: pdm-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Datacenter Manager development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Datacenter Manager development discussion Cc: Proxmox Datacenter Manager development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pdm-devel-bounces@lists.proxmox.com Sender: "pdm-devel" On Thu Oct 23, 2025 at 10:28 AM CEST, Dominik Csapak wrote: > so we can more easily reuse it. For this, also make the 'create_title_with_icon' > a freestanding function that is public so we can reuse it outside the > dashboard struct. > > Signed-off-by: Dominik Csapak > --- > ui/src/dashboard/guest_panel.rs | 75 +++++++++++++++++++++++++-------- > ui/src/dashboard/mod.rs | 66 ++++++++++++----------------- > 2 files changed, 84 insertions(+), 57 deletions(-) > > diff --git a/ui/src/dashboard/guest_panel.rs b/ui/src/dashboard/guest_panel.rs > index 814ecfa5..3197feb4 100644 > --- a/ui/src/dashboard/guest_panel.rs > +++ b/ui/src/dashboard/guest_panel.rs > @@ -1,30 +1,32 @@ > use std::rc::Rc; > > -use pdm_api_types::resource::{GuestStatusCount, ResourceType}; > +use pdm_api_types::resource::{GuestStatusCount, ResourceType, ResourcesStatus}; > use pdm_search::{Search, SearchTerm}; > use proxmox_yew_comp::GuestState; > use pwt::{ > css::{self, TextAlign}, > prelude::*, > - widget::{Container, Fa, List, ListTile}, > + widget::{Container, Fa, List, ListTile, Panel}, > }; > use yew::{ > virtual_dom::{VComp, VNode}, > Properties, > }; > > -use crate::{pve::GuestType, search_provider::get_search_provider}; > +use crate::{ > + dashboard::create_title_with_icon, pve::GuestType, search_provider::get_search_provider, > +}; > > use super::loading_column; > > #[derive(PartialEq, Clone, Properties)] > pub struct GuestPanel { > - guest_type: GuestType, > - status: Option, > + guest_type: Option, > + status: Option, > } > > impl GuestPanel { > - pub fn new(guest_type: GuestType, status: Option) -> Self { > + pub fn new(guest_type: Option, status: Option) -> Self { > yew::props!(Self { guest_type, status }) would be nice to have a comment here that explains that passing `guest_type` as `None` will render a panel that includes both guest types. > } > } > @@ -63,7 +65,16 @@ impl yew::Component for PdmGuestPanel { > let props = ctx.props(); > let guest_type = props.guest_type; > let status = match &props.status { > - Some(status) => status, > + Some(status) => match guest_type { > + Some(GuestType::Qemu) => status.qemu.clone(), > + Some(GuestType::Lxc) => status.lxc.clone(), > + None => GuestStatusCount { > + running: status.qemu.running + status.lxc.running, > + stopped: status.qemu.stopped + status.lxc.stopped, > + template: status.qemu.template + status.lxc.template, > + unknown: status.qemu.unknown + status.lxc.unknown, > + }, > + }, > None => return loading_column().into(), > }; > > @@ -93,7 +104,7 @@ impl yew::Component for PdmGuestPanel { > > fn create_list_tile( > link: &html::Scope, > - guest_type: GuestType, > + guest_type: Option, > status_row: StatusRow, > ) -> Option { > let (icon, text, count, status, template) = match status_row { > @@ -129,7 +140,13 @@ fn create_list_tile( > None, > ), > }, > - StatusRow::All(count) => (Fa::from(guest_type), tr!("All"), count, None, None), > + StatusRow::All(count) => ( > + Fa::from(guest_type.unwrap_or(GuestType::Qemu)), > + tr!("All"), > + count, > + None, > + None, > + ), > }; > > Some( > @@ -158,19 +175,29 @@ fn create_list_tile( > } > > fn create_guest_search_term( > - guest_type: GuestType, > + guest_type: Option, > status: Option<&'static str>, > template: Option, > ) -> Search { > - let resource_type: ResourceType = guest_type.into(); > - if status.is_none() && template.is_none() { > - return Search::with_terms(vec![ > - SearchTerm::new(resource_type.as_str()).category(Some("type")) > - ]); > + let mut terms = Vec::new(); > + match guest_type { > + Some(guest_type) => { > + let resource_type: ResourceType = guest_type.into(); > + terms.push(SearchTerm::new(resource_type.as_str()).category(Some("type"))); > + } > + None => { > + terms.push( > + SearchTerm::new(ResourceType::PveQemu.as_str()) > + .category(Some("type")) > + .optional(true), > + ); > + terms.push( > + SearchTerm::new(ResourceType::PveLxc.as_str()) > + .category(Some("type")) > + .optional(true), > + ); > + } > } > - > - let mut terms = vec![SearchTerm::new(resource_type.as_str()).category(Some("type"))]; > - > if let Some(template) = template { > terms.push(SearchTerm::new(template.to_string()).category(Some("template"))); > } > @@ -179,3 +206,15 @@ fn create_guest_search_term( > } > Search::with_terms(terms) > } > + > +pub fn create_guest_panel(guest_type: Option, status: Option) -> Panel { nit: a doc comment explaining what the parameters do would be nice on a public function > + let (icon, title) = match guest_type { > + Some(GuestType::Qemu) => ("desktop", tr!("Virtual Machines")), > + Some(GuestType::Lxc) => ("cubes", tr!("Linux Container")), > + None => ("desktop", tr!("Guests")), > + }; > + Panel::new() > + .title(create_title_with_icon(icon, title)) > + .border(true) > + .with_child(GuestPanel::new(guest_type, status)) > +} > diff --git a/ui/src/dashboard/mod.rs b/ui/src/dashboard/mod.rs > index f54c509c..602c8a3b 100644 > --- a/ui/src/dashboard/mod.rs > +++ b/ui/src/dashboard/mod.rs > @@ -46,7 +46,7 @@ mod remote_panel; > use remote_panel::RemotePanel; > > mod guest_panel; > -use guest_panel::GuestPanel; > +pub use guest_panel::create_guest_panel; > > mod sdn_zone_panel; > use sdn_zone_panel::SdnZonePanel; > @@ -149,15 +149,6 @@ pub struct PdmDashboard { > } > > impl PdmDashboard { > - fn create_title_with_icon(&self, icon: &str, title: String) -> Html { > - Row::new() > - .class(AlignItems::Center) > - .gap(2) > - .with_child(Fa::new(icon)) > - .with_child(title) > - .into() > - } > - > fn create_node_panel(&self, ctx: &yew::Context, icon: &str, title: String) -> Panel { > let mut search_terms = vec![SearchTerm::new("node").category(Some("type"))]; > let (status_icon, text): (Fa, String) = match &self.status { > @@ -203,7 +194,7 @@ impl PdmDashboard { > Panel::new() > .flex(1.0) > .width(300) > - .title(self.create_title_with_icon(icon, title)) > + .title(create_title_with_icon(icon, title)) > .border(true) > .with_child( > Column::new() > @@ -233,34 +224,13 @@ impl PdmDashboard { > ) > } > > - fn create_guest_panel(&self, guest_type: GuestType) -> Panel { > - let (icon, title, status) = match guest_type { > - GuestType::Qemu => ( > - "desktop", > - tr!("Virtual Machines"), > - self.status.as_ref().map(|s| s.qemu.clone()), > - ), > - GuestType::Lxc => ( > - "cubes", > - tr!("Linux Container"), > - self.status.as_ref().map(|s| s.lxc.clone()), > - ), > - }; > - Panel::new() > - .flex(1.0) > - .width(300) > - .title(self.create_title_with_icon(icon, title)) > - .border(true) > - .with_child(GuestPanel::new(guest_type, status)) > - } > - > fn create_sdn_panel(&self) -> Panel { > let sdn_zones_status = self.status.as_ref().map(|status| status.sdn_zones.clone()); > > Panel::new() > .flex(1.0) > .width(200) > - .title(self.create_title_with_icon("sdn", tr!("SDN Zones"))) > + .title(create_title_with_icon("sdn", tr!("SDN Zones"))) > .border(true) > .with_child(SdnZonePanel::new( > (!self.loading).then_some(sdn_zones_status).flatten(), > @@ -281,7 +251,7 @@ impl PdmDashboard { > .flex(1.0) > .width(500) > .border(true) > - .title(self.create_title_with_icon("list", title)) > + .title(create_title_with_icon("list", title)) > .with_child( > Container::new() > .class(FlexFit) > @@ -318,7 +288,7 @@ impl PdmDashboard { > .width(500) > .min_width(400) > .border(true) > - .title(self.create_title_with_icon(icon, title)) > + .title(create_title_with_icon(icon, title)) > .with_optional_child( > entities > .map(|entities| TopEntities::new(entities.clone(), metrics_title, threshold)), > @@ -537,7 +507,7 @@ impl Component for PdmDashboard { > .padding_top(0) > .with_child( > Panel::new() > - .title(self.create_title_with_icon("server", tr!("Remotes"))) > + .title(create_title_with_icon("server", tr!("Remotes"))) > .flex(1.0) > //.border(true) > .width(300) > @@ -568,8 +538,16 @@ impl Component for PdmDashboard { > "building", > tr!("Virtual Environment Nodes"), > )) > - .with_child(self.create_guest_panel(GuestType::Qemu)) > - .with_child(self.create_guest_panel(GuestType::Lxc)) > + .with_child( > + create_guest_panel(Some(GuestType::Qemu), self.status.clone()) > + .flex(1.0) > + .width(300), > + ) > + .with_child( > + create_guest_panel(Some(GuestType::Lxc), self.status.clone()) > + .flex(1.0) > + .width(300), > + ) > // FIXME: add PBS support > //.with_child(self.create_node_panel( > // "building-o", > @@ -580,7 +558,7 @@ impl Component for PdmDashboard { > // Panel::new() > // .flex(1.0) > // .width(300) > - // .title(self.create_title_with_icon( > + // .title(create_title_with_icon( > // "floppy-o", > // tr!("Backup Server Datastores"), > // )) > @@ -777,3 +755,13 @@ fn loading_column() -> Column { > .class(AlignItems::Center) > .with_child(html! {}) > } > + > +/// Create a consistent title component for the given title and icon > +pub fn create_title_with_icon(icon: &str, title: String) -> Html { > + Row::new() > + .class(AlignItems::Center) > + .gap(2) > + .with_child(Fa::new(icon)) > + .with_child(title) > + .into() > +} _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel