all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Dominik Csapak <d.csapak@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [pdm-devel] [PATCH datacenter-manager 2/3] ui: dashboard/views: add subscription notice in status row
Date: Wed,  3 Dec 2025 10:59:38 +0100	[thread overview]
Message-ID: <20251203095945.1459122-2-d.csapak@proxmox.com> (raw)
In-Reply-To: <20251203095945.1459122-1-d.csapak@proxmox.com>

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 <d.csapak@proxmox.com>
---
 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<PdmSubscriptionInfo, Error>),
     Edit(EditingMessage),
 }
 
@@ -59,6 +68,9 @@ pub struct PdmDashboardStatusRow {
     _interval: Interval,
     loading: bool,
     edit: bool,
+
+    async_pool: AsyncPool,
+    subscription_info: LoadResult<PdmSubscriptionInfo, Error>,
 }
 
 impl PdmDashboardStatusRow {
@@ -73,6 +85,13 @@ impl PdmDashboardStatusRow {
 
         _interval
     }
+
+    fn load_subscription(&self, ctx: &yew::Context<Self>) {
+        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 {
-        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<Self>, 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<Self>) -> 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<PdmSubscriptionInfo, Error>,
+) -> Option<Tooltip> {
+    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


  reply	other threads:[~2025-12-03  9:59 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-12-03  9:59 [pdm-devel] [PATCH datacenter-manager 1/3] ui: mark subscription check as active if no remotes are configured Dominik Csapak
2025-12-03  9:59 ` Dominik Csapak [this message]
2025-12-03  9:59 ` [pdm-devel] [PATCH datacenter-manager 3/3] ui: views: make Subscription panel not required anymore Dominik Csapak
2025-12-03 12:08 ` [pdm-devel] [PATCH datacenter-manager 1/3] ui: mark subscription check as active if no remotes are configured Thomas Lamprecht

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251203095945.1459122-2-d.csapak@proxmox.com \
    --to=d.csapak@proxmox.com \
    --cc=pdm-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal