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 704851FF16F for ; Tue, 19 Aug 2025 13:53:27 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 8BDAA134DA; Tue, 19 Aug 2025 13:55:12 +0200 (CEST) Date: Tue, 19 Aug 2025 13:55:09 +0200 Message-Id: To: "Proxmox Datacenter Manager development discussion" , "Dominik Csapak" From: "Lukas Wagner" Mime-Version: 1.0 X-Mailer: aerc 0.20.1-0-g2ecb8770224a References: <20250516133611.3499075-1-d.csapak@proxmox.com> <20250516133611.3499075-17-d.csapak@proxmox.com> In-Reply-To: <20250516133611.3499075-17-d.csapak@proxmox.com> X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1755604467048 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.023 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 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 16/21] ui: widget: add pve realm selector 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 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pdm-devel-bounces@lists.proxmox.com Sender: "pdm-devel" On Fri May 16, 2025 at 3:36 PM CEST, Dominik Csapak wrote: > similar to the general realm selector, but with a hostname/fingerprint > property, so we can query the realms of any PVE instance. > > Signed-off-by: Dominik Csapak > --- > ui/src/widget/mod.rs | 3 + > ui/src/widget/pve_realm_selector.rs | 125 ++++++++++++++++++++++++++++ > 2 files changed, 128 insertions(+) > create mode 100644 ui/src/widget/pve_realm_selector.rs > > diff --git a/ui/src/widget/mod.rs b/ui/src/widget/mod.rs > index ee9e799..9d7840c 100644 > --- a/ui/src/widget/mod.rs > +++ b/ui/src/widget/mod.rs > @@ -13,6 +13,9 @@ pub use pve_storage_selector::PveStorageSelector; > mod pve_migrate_mapping; > pub use pve_migrate_mapping::PveMigrateMap; > > +mod pve_realm_selector; > +pub use pve_realm_selector::PveRealmSelector; > + > mod resource_tree; > pub use resource_tree::ResourceTree; > > diff --git a/ui/src/widget/pve_realm_selector.rs b/ui/src/widget/pve_realm_selector.rs > new file mode 100644 > index 0000000..8025c2d > --- /dev/null > +++ b/ui/src/widget/pve_realm_selector.rs > @@ -0,0 +1,125 @@ > +use anyhow::format_err; > +use std::rc::Rc; > + > +use yew::html::IntoPropValue; > +use yew::prelude::*; > + > +use pwt::props::RenderFn; > +use pwt::state::Store; > +use pwt::widget::data_table::{DataTable, DataTableColumn, DataTableHeader}; > +use pwt::widget::form::{Selector, SelectorRenderArgs, ValidateFn}; > +use pwt::widget::GridPicker; > + > +use proxmox_yew_comp::common_api_types::BasicRealmInfo; > +use proxmox_yew_comp::percent_encoding::percent_encode_component; > + > +use pwt::props::{FieldBuilder, WidgetBuilder}; > +use pwt_macros::{builder, widget}; > + > +#[widget(comp=PdmPveRealmSelector, @input)] > +#[derive(Clone, Properties, PartialEq)] > +#[builder] > +pub struct PveRealmSelector { > + /// The default value. > + #[builder(IntoPropValue, into_prop_value)] > + #[prop_or_default] > + pub default: Option, > + > + pub hostname: AttrValue, > + > + pub fingerprint: Option, > +} > + > +impl PveRealmSelector { > + pub fn new( > + hostname: impl IntoPropValue, > + fingerprint: impl IntoPropValue>, > + ) -> Self { > + yew::props!(Self { > + hostname: hostname.into_prop_value(), > + fingerprint: fingerprint.into_prop_value(), > + }) > + } > +} > + > +pub struct PdmPveRealmSelector { > + store: Store, > + validate: ValidateFn<(String, Store)>, > + picker: RenderFn>>, > +} > + > +impl Component for PdmPveRealmSelector { > + type Message = (); > + type Properties = PveRealmSelector; > + > + fn create(ctx: &Context) -> Self { > + let store = Store::new().on_change(ctx.link().callback(|_| ())); // trigger redraw > + > + let validate = ValidateFn::new(|(realm, store): &(String, Store)| { > + store > + .read() > + .data() > + .iter() > + .find(|item| &item.realm == realm) > + .map(drop) > + .ok_or_else(|| format_err!("no such realm")) Maybe it's just me, but I find if store.read().data().iter().any(|item| &item.realm == realm) { Ok(()) } else { Err(format_err!("no such realm")) } a bit easier to understand here (the `.map(drop)` reads a bit odd to me, that's not something you see a lot) > + }); > + > + let picker = RenderFn::new({ > + let columns = columns(); > + move |args: &SelectorRenderArgs>| { > + let table = DataTable::new(columns.clone(), args.store.clone()).class("pwt-fit"); > + > + GridPicker::new(table) > + .selection(args.selection.clone()) > + .on_select(args.controller.on_select_callback()) > + .into() > + } > + }); > + > + Self { > + store, > + validate, > + picker, > + } > + } > + > + fn view(&self, ctx: &Context) -> Html { > + let props = ctx.props(); > + > + let mut url = format!( > + "/pve/realms?hostname={}", > + percent_encode_component(&props.hostname) > + ); > + if let Some(fp) = &props.fingerprint { > + url.push_str(&format!("&fingerprint={}", percent_encode_component(fp))); > + } > + > + Selector::new(self.store.clone(), self.picker.clone()) > + .with_std_props(&props.std_props) > + .with_input_props(&props.input_props) > + .required(true) > + .default(props.default.as_deref().unwrap_or("pam").to_string()) > + .loader(url) > + .validate(self.validate.clone()) > + .into() > + } > +} > + > +fn columns() -> Rc>> { > + Rc::new(vec![ > + DataTableColumn::new("Realm") > + .width("100px") > + .sort_order(true) > + .show_menu(false) > + .get_property(|record: &BasicRealmInfo| &record.realm) > + .into(), > + DataTableColumn::new("Comment") > + .width("300px") > + .show_menu(false) > + .get_property_owned(|record: &BasicRealmInfo| { > + record.comment.clone().unwrap_or_default() > + }) > + .into(), > + ]) > +} _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel