From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id A30E71FF183 for ; Wed, 8 Oct 2025 17:20:05 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 5C0C4C154; Wed, 8 Oct 2025 17:20:11 +0200 (CEST) From: Shannon Sterz To: yew-devel@lists.proxmox.com Date: Wed, 8 Oct 2025 17:19:35 +0200 Message-ID: <20251008151936.386950-2-s.sterz@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20251008151936.386950-1-s.sterz@proxmox.com> References: <20251008151936.386950-1-s.sterz@proxmox.com> MIME-Version: 1.0 X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1759936746377 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.056 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 URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [props.mobile] Subject: [yew-devel] [PATCH yew-comp 1/2] login_panel/realm_selector: use default realm provided by api X-BeenThere: yew-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Yew framework devel list at Proxmox List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Yew framework devel list at Proxmox Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: yew-devel-bounces@lists.proxmox.com Sender: "yew-devel" when a user has not previously safed their username and realm, use the default realm provided via the api. if no realm has been specified at all, still fall back to "pam". Signed-off-by: Shannon Sterz --- src/login_panel.rs | 10 +++---- src/realm_selector.rs | 65 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/login_panel.rs b/src/login_panel.rs index 0b835e7..6c3aaa7 100644 --- a/src/login_panel.rs +++ b/src/login_panel.rs @@ -29,9 +29,9 @@ pub struct LoginPanel { pub on_login: Option>, /// Default realm. - #[prop_or(AttrValue::from("pam"))] + #[prop_or_default] #[builder] - pub default_realm: AttrValue, + pub default_realm: Option, /// Mobile Layout /// @@ -125,16 +125,16 @@ impl ProxmoxLoginPanel { }); } - fn get_defaults(&self, props: &LoginPanel) -> (String, String) { + fn get_defaults(&self, props: &LoginPanel) -> (String, Option) { let mut default_username = String::from("root"); - let mut default_realm = props.default_realm.to_string(); + let mut default_realm = props.default_realm.clone(); if props.mobile || *self.save_username { let last_userid: String = (*self.last_username).to_string(); if !last_userid.is_empty() { if let Some((user, realm)) = last_userid.rsplit_once('@') { default_username = user.to_owned(); - default_realm = realm.to_owned().into(); + default_realm = Some(AttrValue::from(realm.to_owned())); } } } diff --git a/src/realm_selector.rs b/src/realm_selector.rs index 0c57bf6..b11e924 100644 --- a/src/realm_selector.rs +++ b/src/realm_selector.rs @@ -1,4 +1,4 @@ -use anyhow::format_err; +use anyhow::{format_err, Error}; use std::rc::Rc; use yew::html::IntoPropValue; @@ -61,18 +61,36 @@ impl RealmSelector { } } -pub struct ProxmoxRealmSelector { +struct ProxmoxRealmSelector { store: Store, validate: ValidateFn<(String, Store)>, picker: RenderFn>>, + loaded_default_realm: Option, +} + +impl ProxmoxRealmSelector { + async fn load_realms(url: AttrValue) -> Msg { + let response: Result<_, Error> = crate::http_get_full(url.to_string(), None).await; + + match response { + Ok(data) => Msg::LoadComplete(data.data), + Err(_) => Msg::LoadFailed, + } + } +} + +enum Msg { + LoadComplete(Vec), + LoadFailed, } impl Component for ProxmoxRealmSelector { - type Message = (); + type Message = Msg; type Properties = RealmSelector; fn create(ctx: &Context) -> Self { - let store = Store::new().on_change(ctx.link().callback(|_| ())); // trigger redraw + let store = Store::new(); + let url = ctx.props().path.clone(); let validate = ValidateFn::new(|(realm, store): &(String, Store)| { store @@ -94,23 +112,58 @@ impl Component for ProxmoxRealmSelector { .into() }); + ctx.link().send_future(Self::load_realms(url)); + Self { store, validate, picker, + loaded_default_realm: None, + } + } + + fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { + match msg { + Msg::LoadComplete(mut data) => { + data.sort_by(|a, b| a.realm.cmp(&b.realm)); + + let realm = ctx + .props() + .default + .as_ref() + .and_then(|d| data.iter().find(|r| &r.realm == d)) + .or_else(|| data.iter().find(|r| r.default.unwrap_or_default())) + .or_else(|| data.iter().find(|r| r.ty == "pam")) + .map(|r| AttrValue::from(r.realm.clone())); + + self.loaded_default_realm = realm; + self.store.set_data(data); + true + } + // not much we can do here, so just don't re-render + Msg::LoadFailed => false, } } fn view(&self, ctx: &Context) -> Html { let props = ctx.props(); + let store = self.store.clone(); + + let default = props + .default + .clone() + .or_else(|| self.loaded_default_realm.clone()) + .unwrap_or(AttrValue::from("pam")); 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(props.path.clone()) + .default(&default) .validate(self.validate.clone()) + // force re-render of the selector after load; returning `true` in update does not + // re-render the selector by itself + .key(format!("realm-selector-{default}")) .into() } } -- 2.47.3 _______________________________________________ yew-devel mailing list yew-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/yew-devel