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 8EBEF1FF178 for ; Mon, 1 Dec 2025 15:20:22 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 98A371EB53; Mon, 1 Dec 2025 15:20:46 +0100 (CET) From: Dominik Csapak To: pdm-devel@lists.proxmox.com Date: Mon, 1 Dec 2025 15:19:29 +0100 Message-ID: <20251201142013.3186537-1-d.csapak@proxmox.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.029 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: [pdm-devel] [PATCH datacenter-manager v2] ui: subscription_info: add subscription counts 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" count the subscriptions we know of and show them in a tabular style. Showing each product as a single line with each subscription type as a column. Signed-off-by: Dominik Csapak --- changes from v1: * use one line per product, integrates much nicer, and does not get so tall, but takes up more horizontal space. ui/src/dashboard/subscription_info.rs | 109 ++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 6 deletions(-) diff --git a/ui/src/dashboard/subscription_info.rs b/ui/src/dashboard/subscription_info.rs index 6c94b8ef..f9e8c33f 100644 --- a/ui/src/dashboard/subscription_info.rs +++ b/ui/src/dashboard/subscription_info.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::rc::Rc; use anyhow::Error; @@ -7,16 +8,18 @@ use yew::{ }; use proxmox_yew_comp::Status; +use pwt::css::{AlignItems, AlignSelf, Display, FlexFit, JustifyContent, TextAlign}; use pwt::prelude::*; +use pwt::props::PwtSpace; +use pwt::state::SharedState; use pwt::widget::{Button, Column, Container, Dialog, Fa, Panel, Row}; -use pwt::{ - css::{AlignItems, FlexFit, JustifyContent, TextAlign}, - state::SharedState, -}; -use pdm_api_types::subscription::{RemoteSubscriptionState, RemoteSubscriptions}; +use pdm_api_types::remotes::RemoteType; +use pdm_api_types::subscription::{ + NodeSubscriptionInfo, RemoteSubscriptionState, RemoteSubscriptions, SubscriptionLevel, +}; -use crate::{dashboard::SubscriptionsList, LoadResult}; +use crate::{dashboard::SubscriptionsList, get_remote_list, LoadResult, RemoteList}; #[derive(Properties, PartialEq)] pub struct SubscriptionInfo { @@ -31,6 +34,97 @@ impl SubscriptionInfo { struct PdmSubscriptionInfo; +#[derive(Default)] +struct SubCount { + community: u32, + basic: u32, + standard: u32, + premium: u32, + none: u32, +} + +impl SubCount { + fn count_subs(&mut self, subscriptions: &HashMap>) { + for info in subscriptions.values().flatten() { + match info.level { + SubscriptionLevel::None => self.none += 1, + SubscriptionLevel::Unknown => {} + SubscriptionLevel::Community => self.community += 1, + SubscriptionLevel::Basic => self.basic += 1, + SubscriptionLevel::Standard => self.standard += 1, + SubscriptionLevel::Premium => self.premium += 1, + } + } + } + + fn total(&self) -> u32 { + self.community + self.basic + self.standard + self.none + } +} + +fn render_subscription_list(remotes: RemoteList, subs: &[RemoteSubscriptions]) -> Container { + let mut pve = SubCount::default(); + let mut pbs = SubCount::default(); + + for sub in subs { + if let Some(remote_type) = remotes + .iter() + .find_map(|remote| (remote.id == sub.remote).then_some(remote.ty)) + { + if let Some(hash) = sub.node_status.as_ref() { + match remote_type { + RemoteType::Pve => pve.count_subs(hash), + RemoteType::Pbs => pbs.count_subs(hash), + } + } + } + } + + fn render_right_aligned(text: impl Into) -> Container { + Container::new().class(TextAlign::Right).with_child(text) + } + + fn render_product(count: SubCount, title: &str) -> Vec { + vec![ + Container::new().with_child(title), + render_right_aligned(count.community), + render_right_aligned(count.basic), + render_right_aligned(count.standard), + render_right_aligned(count.premium), + render_right_aligned(count.none), + ] + } + + let mut list = vec![ + Container::new().with_child(tr!("Product")), + render_right_aligned("Community"), + render_right_aligned("Basic"), + render_right_aligned("Standard"), + render_right_aligned("Premium"), + render_right_aligned(tr!("None")), + ]; + + if pve.total() > 0 { + list.append(&mut render_product(pve, "Proxmox VE")); + } + if pbs.total() > 0 { + list.append(&mut render_product(pbs, "Proxmox Backup Server")); + } + + if list.is_empty() { + return Container::new(); + } + + Container::new() + .padding_x(4) + .padding_bottom(4) + .class(Display::Grid) + .class(AlignSelf::Stretch) + .style("grid-template-columns", "1fr repeat(5, 100px)") + .style("gap", PwtSpace::Pwt(2)) + .children(list.into_iter().map(|c| c.into())) +} + fn render_subscription_status(subs: &[RemoteSubscriptions]) -> Row { let mut none = 0; let mut mixed = 0; @@ -122,6 +216,9 @@ impl Component for PdmSubscriptionInfo { .as_ref() .map(|subs| render_subscription_status(subs)), ) + .with_optional_child(props.subs.as_ref().and_then(|subs| { + get_remote_list(ctx.link()).map(|remotes| render_subscription_list(remotes, subs)) + })) .into() } } -- 2.47.3 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel