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 F17071FF183 for ; Wed, 3 Dec 2025 10:59:52 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 1464455D5; Wed, 3 Dec 2025 11:00:19 +0100 (CET) From: Dominik Csapak To: pdm-devel@lists.proxmox.com Date: Wed, 3 Dec 2025 10:59:38 +0100 Message-ID: <20251203095945.1459122-2-d.csapak@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20251203095945.1459122-1-d.csapak@proxmox.com> References: <20251203095945.1459122-1-d.csapak@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.030 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. [subscriptions.data] Subject: [pdm-devel] [PATCH datacenter-manager 2/3] ui: dashboard/views: add subscription notice in status row 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" This adds a short subscription notice to the status row. It will be loaded together with the normal refresh. It currently only shows the following states: * No remotes configured (warning) * No valid subscriptions (error) * Valid subscriptions (good) It reuses the pdm backend subscription check for this. If there is a message or an error from the api call, show that as tooltip. A click on the notice routes to the subscriptions panel of PDM, where more info about the statistics is outlined. Downside of this approach is that we might load the subscription info twice on a fresh login, once for the login popup check, and once for the dashboard/view if one is open after login. Signed-off-by: Dominik Csapak --- ui/Cargo.toml | 1 + ui/src/dashboard/status_row.rs | 86 ++++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/ui/Cargo.toml b/ui/Cargo.toml index 12c1ff45..d5124340 100644 --- a/ui/Cargo.toml +++ b/ui/Cargo.toml @@ -39,6 +39,7 @@ proxmox-client = "1" proxmox-human-byte = "1" proxmox-login = "1" proxmox-schema = "5" +proxmox-subscription = { version = "1.0.1", features = ["api-types"], default-features = false } proxmox-rrd-api-types = "1" proxmox-node-status = "1" pbs-api-types = { version = "1.0.3", features = [ "enum-fallback" ] } diff --git a/ui/src/dashboard/status_row.rs b/ui/src/dashboard/status_row.rs index e1af6697..582a9b87 100644 --- a/ui/src/dashboard/status_row.rs +++ b/ui/src/dashboard/status_row.rs @@ -1,19 +1,27 @@ +use anyhow::Error; use gloo_timers::callback::Interval; use yew::html::IntoPropValue; use yew::{Component, Properties}; +use yew_router::prelude::RouterScopeExt; +use yew_router::AnyRoute; -use pwt::css; use pwt::prelude::*; use pwt::state::SharedState; +use pwt::{css, AsyncPool}; use pwt::{ css::AlignItems, widget::{ActionIcon, Container, Row, Tooltip}, }; use pwt_macros::{builder, widget}; +use proxmox_subscription::SubscriptionStatus; +use proxmox_yew_comp::subscription_icon; use proxmox_yew_comp::utils::render_epoch; +use pdm_api_types::subscription::PdmSubscriptionInfo; + use crate::dashboard::view::EditingMessage; +use crate::LoadResult; #[widget(comp=PdmDashboardStatusRow)] #[derive(Properties, PartialEq, Clone)] @@ -51,6 +59,7 @@ impl DashboardStatusRow { pub enum Msg { /// The bool denotes if the reload comes from the click or the timer. Reload(bool), + SubscriptionInfoLoaded(Result), Edit(EditingMessage), } @@ -59,6 +68,9 @@ pub struct PdmDashboardStatusRow { _interval: Interval, loading: bool, edit: bool, + + async_pool: AsyncPool, + subscription_info: LoadResult, } impl PdmDashboardStatusRow { @@ -73,6 +85,13 @@ impl PdmDashboardStatusRow { _interval } + + fn load_subscription(&self, ctx: &yew::Context) { + self.async_pool.send_future(ctx.link().clone(), async move { + let res = proxmox_yew_comp::http_get("/nodes/localhost/subscription", None).await; + Msg::SubscriptionInfoLoaded(res) + }); + } } impl Component for PdmDashboardStatusRow { @@ -80,11 +99,15 @@ impl Component for PdmDashboardStatusRow { type Properties = DashboardStatusRow; fn create(ctx: &yew::Context) -> Self { - Self { + let this = Self { _interval: Self::create_interval(ctx), loading: false, edit: false, - } + async_pool: AsyncPool::new(), + subscription_info: LoadResult::new(), + }; + this.load_subscription(ctx); + this } fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { @@ -92,6 +115,7 @@ impl Component for PdmDashboardStatusRow { match msg { Msg::Reload(clicked) => { props.on_reload.emit(clicked); + self.load_subscription(ctx); self.loading = true; true } @@ -102,6 +126,10 @@ impl Component for PdmDashboardStatusRow { } true } + Msg::SubscriptionInfoLoaded(res) => { + self.subscription_info.update(res); + true + } } } @@ -116,7 +144,8 @@ impl Component for PdmDashboardStatusRow { fn view(&self, ctx: &yew::Context) -> yew::Html { let props = ctx.props(); - let is_loading = props.last_refresh.is_none() || self.loading; + let is_loading = + props.last_refresh.is_none() || self.loading || !self.subscription_info.has_data(); let on_settings_click = props.on_settings_click.clone(); Row::new() .gap(1) @@ -141,6 +170,18 @@ impl Component for PdmDashboardStatusRow { } None => tr!("Now refreshing"), })) + .with_optional_child(create_subscription_notice(&self.subscription_info).map( + |element| { + element.class("pwt-pointer").onclick({ + let link = ctx.link().clone(); + move |_| { + if let Some(nav) = link.navigator() { + nav.push(&AnyRoute::new("/subscription")); + } + } + }) + }, + )) .with_flex_spacer() .with_optional_child(props.editing_state.clone().and_then(|_| { (!self.edit).then_some({ @@ -190,3 +231,40 @@ impl Component for PdmDashboardStatusRow { .into() } } + +fn create_subscription_notice( + subscriptions: &LoadResult, +) -> Option { + if !subscriptions.has_data() { + return None; + } + let mut text = tr!("No valid subscriptions"); + let mut icon = subscription_icon(&SubscriptionStatus::NotFound.to_string()); + let mut tooltip = None; + + if let Some(subscriptions) = &subscriptions.data { + if subscriptions.statistics.total_nodes == 0 { + text = tr!("No remotes configured"); + icon = subscription_icon("unknown"); + } else if let SubscriptionStatus::Active = subscriptions.info.status { + text = tr!("Valid subscriptions"); + icon = subscription_icon(&subscriptions.info.status.to_string()); + } else if let Some(msg) = &subscriptions.info.message { + tooltip = Some(msg.clone()); + } + } else if let Some(err) = &subscriptions.error { + tooltip = Some(err.to_string()) + } + + Some( + Tooltip::new( + Row::new() + .padding_x(2) + .gap(2) + .class(css::AlignItems::Center) + .with_child(icon.large()) + .with_child(Container::new().with_child(text)), + ) + .tip(tooltip), + ) +} -- 2.47.3 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel