From: Lukas Wagner <l.wagner@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [pdm-devel] [PATCH datacenter-manager 08/13] ui: remote updates: show main product version in overview table
Date: Thu, 27 Nov 2025 11:44:42 +0100 [thread overview]
Message-ID: <20251127104447.162951-14-l.wagner@proxmox.com> (raw)
In-Reply-To: <20251127104447.162951-1-l.wagner@proxmox.com>
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---
ui/src/remotes/updates.rs | 79 ++++++++++++++++++++++++++++++++++++---
1 file changed, 74 insertions(+), 5 deletions(-)
diff --git a/ui/src/remotes/updates.rs b/ui/src/remotes/updates.rs
index 895eaa13..e13e3831 100644
--- a/ui/src/remotes/updates.rs
+++ b/ui/src/remotes/updates.rs
@@ -1,4 +1,5 @@
use std::cmp::Ordering;
+use std::collections::BTreeMap;
use std::ops::Deref;
use std::pin::Pin;
use std::rc::Rc;
@@ -53,6 +54,8 @@ impl From<UpdateTree> for VNode {
struct RemoteEntry {
remote: String,
ty: RemoteType,
+ product_version: Option<String>,
+ mixed_versions: bool,
number_of_failed_nodes: u32,
number_of_nodes: u32,
number_of_updatable_nodes: u32,
@@ -125,7 +128,7 @@ impl UpdateTreeComponent {
Rc::new(vec![
DataTableColumn::new(tr!("Name"))
.tree_column(store)
- .flex(1)
+ .flex(2)
.render(|entry: &UpdateTreeEntry| {
let icon = match entry {
UpdateTreeEntry::Remote(_) => Some("server"),
@@ -142,8 +145,16 @@ impl UpdateTreeComponent {
})
.sorter(default_sorter)
.into(),
+ DataTableColumn::new(tr!("Version"))
+ .flex(1)
+ .render_cell(DataTableCellRenderer::new(
+ move |args: &mut DataTableCellRenderArgs<UpdateTreeEntry>| {
+ render_version_column(args.record(), args.is_expanded())
+ },
+ ))
+ .into(),
DataTableColumn::new(tr!("Status"))
- .flex(3)
+ .flex(6)
.render_cell(DataTableCellRenderer::new(
move |args: &mut DataTableCellRenderArgs<UpdateTreeEntry>| match args.record() {
UpdateTreeEntry::Root => {
@@ -184,6 +195,8 @@ fn build_store_from_response(update_summary: UpdateSummary) -> SlabTree<UpdateTr
let mut remote_entry = root.append(UpdateTreeEntry::Remote(RemoteEntry {
remote: remote_name.clone(),
ty: remote_summary.remote_type,
+ product_version: None,
+ mixed_versions: false,
number_of_nodes: 0,
number_of_updatable_nodes: 0,
number_of_failed_nodes: 0,
@@ -191,11 +204,17 @@ fn build_store_from_response(update_summary: UpdateSummary) -> SlabTree<UpdateTr
}));
remote_entry.set_expanded(false);
+ let mut product_version = None;
+ let mut mixed_versions = false;
let number_of_nodes = remote_summary.nodes.len();
let mut number_of_updatable_nodes = 0;
let mut number_of_failed_nodes = 0;
- for (node_name, node_summary) in remote_summary.nodes.deref() {
+ // use a BTreeMap to get a stable order. Can be removed once there is proper version
+ // comparison in place.
+ let nodes = BTreeMap::from_iter(remote_summary.nodes.deref());
+
+ for (node_name, node_summary) in nodes {
match node_summary.status {
NodeUpdateStatus::Success => {
if node_summary.number_of_updates > 0 {
@@ -207,19 +226,35 @@ fn build_store_from_response(update_summary: UpdateSummary) -> SlabTree<UpdateTr
}
}
- remote_entry.append(UpdateTreeEntry::Node(NodeEntry {
+ let entry = NodeEntry {
remote: remote_name.clone(),
node: node_name.clone(),
ty: remote_summary.remote_type,
summary: node_summary.clone(),
flat: false,
- }));
+ };
+
+ if let Some(version) = get_product_version(&entry) {
+ if let Some(product_version) = &product_version {
+ if version != *product_version {
+ mixed_versions = true;
+ }
+ // TODO: Compare versions and report the highest (or lowest). For now we just
+ // report the one of the first node.
+ } else {
+ product_version = Some(version);
+ }
+ }
+
+ remote_entry.append(UpdateTreeEntry::Node(entry));
}
if let UpdateTreeEntry::Remote(info) = remote_entry.record_mut() {
info.number_of_updatable_nodes = number_of_updatable_nodes;
info.number_of_nodes = number_of_nodes as u32;
info.number_of_failed_nodes = number_of_failed_nodes as u32;
+ info.product_version = product_version;
+ info.mixed_versions = mixed_versions;
}
}
@@ -511,6 +546,40 @@ fn render_node_info(entry: &NodeEntry) -> Row {
.with_child(text)
}
+fn render_version_column(tree_entry: &UpdateTreeEntry, expanded: bool) -> Html {
+ let text = match tree_entry {
+ UpdateTreeEntry::Node(node_entry) => {
+ get_product_version(node_entry).unwrap_or_default().into()
+ }
+ UpdateTreeEntry::Remote(remote_entry) => {
+ if !expanded {
+ let version_string = remote_entry.product_version.clone().unwrap_or_default();
+ // TRANSLATORS: The first parameter is a version string (e.g. '9.1.0')
+ tr!("{0} (mixed versions)", version_string)
+ } else {
+ "".to_string()
+ }
+ }
+ _ => "".to_string(),
+ };
+
+ text.into()
+}
+
+fn get_product_version(node_entry: &NodeEntry) -> Option<String> {
+ let package = match node_entry.ty {
+ RemoteType::Pve => "pve-manager",
+ RemoteType::Pbs => "proxmox-backup-server",
+ };
+
+ node_entry
+ .summary
+ .versions
+ .iter()
+ .find(|p| p.package == package)
+ .map(|p| p.version.to_string())
+}
+
enum RemoteSummaryIcon {
UpToDate,
Updatable,
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
next prev parent reply other threads:[~2025-11-27 10:44 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-27 10:44 [pdm-devel] [PATCH datacenter-manager/proxmox{, -yew-comp} 00/18] remote update view: include product version and repository status Lukas Wagner
2025-11-27 10:44 ` [pdm-devel] [PATCH proxmox 1/4] add bindings for /nodes/{node}/apt/versions Lukas Wagner
2025-11-27 20:46 ` [pdm-devel] applied: " Thomas Lamprecht
2025-11-27 10:44 ` [pdm-devel] [PATCH proxmox 2/4] add bindings for /nodes/{node}/apt/repositories Lukas Wagner
2025-11-27 20:46 ` [pdm-devel] applied: " Thomas Lamprecht
2025-11-27 10:44 ` [pdm-devel] [PATCH proxmox 3/4] make refresh Lukas Wagner
2025-11-27 10:44 ` [pdm-devel] [PATCH proxmox 4/4] proxmox-apt-api-types: make APTStandardRepository compatible with PVE's serialization of the type Lukas Wagner
2025-11-27 20:46 ` [pdm-devel] applied: " Thomas Lamprecht
2025-11-27 10:44 ` [pdm-devel] [PATCH proxmox-yew-comp 1/1] apt repositories: add 'status_only' property Lukas Wagner
2025-11-27 21:26 ` [pdm-devel] applied: " Thomas Lamprecht
2025-11-27 10:44 ` [pdm-devel] [PATCH datacenter-manager 01/13] pdm-api-types: reuse APTUpdateInfo from proxmox_apt_api_types Lukas Wagner
2025-11-27 10:44 ` [pdm-devel] [PATCH datacenter-manager 02/13] pbs-client: add bindings for /nodes/localhost/apt/versions Lukas Wagner
2025-11-27 10:44 ` [pdm-devel] [PATCH datacenter-manager 03/13] pbs-client: add bindings for /nodes/localhost/apt/repositories Lukas Wagner
2025-11-27 10:44 ` [pdm-devel] [PATCH datacenter-manager 04/13] remote-updates: include version information in node update summary Lukas Wagner
2025-11-27 10:44 ` [pdm-devel] [PATCH datacenter-manager 05/13] remote updates: include repository status in node summary Lukas Wagner
2025-11-27 10:44 ` [pdm-devel] [PATCH datacenter-manager 06/13] api: pve/pbs: add passthrough endpoint for APT repo configuration Lukas Wagner
2025-11-27 10:44 ` [pdm-devel] [PATCH datacenter-manager 07/13] ui: remote updates: show table header Lukas Wagner
2025-11-27 10:44 ` Lukas Wagner [this message]
2025-11-27 10:44 ` [pdm-devel] [PATCH datacenter-manager 09/13] ui: remote updates: show repository status column Lukas Wagner
2025-11-27 10:44 ` [pdm-devel] [PATCH datacenter-manager 10/13] ui: remote updates: show repo status details when selecting a node Lukas Wagner
2025-11-27 10:44 ` [pdm-devel] [PATCH datacenter-manager 11/13] ui: remote updates: don't attempt to load current status for unavailable nodes Lukas Wagner
2025-11-27 10:44 ` [pdm-devel] [PATCH datacenter-manager 12/13] ui: remote updates: use 'building-o' icon for PBS nodes Lukas Wagner
2025-11-27 10:44 ` [pdm-devel] [PATCH datacenter-manager 13/13] ui: remote updates: use explicit indices for parameters in tr! macro Lukas Wagner
2025-11-27 10:47 ` [pdm-devel] [PATCH datacenter-manager/proxmox{, -yew-comp} 00/18] remote update view: include product version and repository status Lukas Wagner
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=20251127104447.162951-14-l.wagner@proxmox.com \
--to=l.wagner@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox