From: Dominik Csapak <d.csapak@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [pdm-devel] [PATCH datacenter-manager] ui: add download button for system report
Date: Wed, 10 Dec 2025 14:59:59 +0100 [thread overview]
Message-ID: <20251210140008.3046928-1-d.csapak@proxmox.com> (raw)
by simply setting the 'href' of an 'a' tag to be the report as inline
data, like we do on PVE/PBS with a slight difference:
in PVE/PBS we create an 'a' tag dynamically on button click, but here we
create the a tag when we have the data and wrap a button without click
handler, so the click on the button triggers the download of the 'a'
tag.
Refactor the `get_nodename` function to another place where we can
access it from here.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
ui/Cargo.toml | 1 +
ui/src/administration/node_status.rs | 45 +++++++++++++++++++++++-----
ui/src/lib.rs | 16 ++++++++++
ui/src/remotes/wizard_page_info.rs | 16 +---------
4 files changed, 56 insertions(+), 22 deletions(-)
diff --git a/ui/Cargo.toml b/ui/Cargo.toml
index 1b4f0a23..9bbde7d1 100644
--- a/ui/Cargo.toml
+++ b/ui/Cargo.toml
@@ -41,6 +41,7 @@ proxmox-login = "1"
proxmox-schema = "5"
proxmox-subscription = { version = "1.0.1", features = ["api-types"], default-features = false }
proxmox-rrd-api-types = "1"
+proxmox-time = "2"
proxmox-node-status = "1"
pbs-api-types = { version = "1.0.3", features = [ "enum-fallback" ] }
diff --git a/ui/src/administration/node_status.rs b/ui/src/administration/node_status.rs
index 26b6c958..a61f25a2 100644
--- a/ui/src/administration/node_status.rs
+++ b/ui/src/administration/node_status.rs
@@ -4,12 +4,16 @@ use anyhow::Error;
use yew::virtual_dom::{VComp, VNode};
use proxmox_node_status::NodePowerCommand;
-use proxmox_yew_comp::utils::copy_text_to_clipboard;
+use proxmox_time::epoch_i64;
+use proxmox_yew_comp::percent_encoding::percent_encode_component;
+use proxmox_yew_comp::utils::{copy_text_to_clipboard, render_epoch};
use proxmox_yew_comp::{http_post, ConfirmButton, NodeStatusPanel};
use pwt::prelude::*;
use pwt::widget::{Button, Column, Container, Row};
use pwt::AsyncAbortGuard;
+use crate::get_nodename;
+
#[derive(Properties, Clone, PartialEq)]
pub(crate) struct NodeStatus {}
@@ -74,12 +78,39 @@ impl PdmNodeStatus {
.with_child(&report),
)
.with_child(
- Row::new().padding(2).with_flex_spacer().with_child(
- Button::new(tr!("Copy to clipboard"))
- .icon_class("fa fa-clipboard")
- .class(pwt::css::ColorScheme::Primary)
- .on_activate(move |_| copy_text_to_clipboard(&report)),
- ),
+ Row::new()
+ .padding(2)
+ .gap(1)
+ .with_flex_spacer()
+ .with_child(
+ Button::new(tr!("Copy to clipboard"))
+ .icon_class("fa fa-clipboard")
+ .class(pwt::css::ColorScheme::Primary)
+ .on_activate({
+ let report = report.clone();
+ move |_| copy_text_to_clipboard(&report)
+ }),
+ )
+ .with_child({
+ let button = Button::new(tr!("Download"))
+ .icon_class("fa fa-download")
+ .class(pwt::css::ColorScheme::Primary);
+
+ let data = format!(
+ "data:text/plain;charset=utf-8,{}",
+ percent_encode_component(&report)
+ );
+ let timestamp = render_epoch(epoch_i64());
+
+ let filename = match get_nodename() {
+ Some(nodename) => {
+ format!("{nodename}-pdm-report-{timestamp}.txt")
+ }
+ None => format!("pdm-report-{timestamp}.txt"),
+ };
+
+ html! { <a href={data} download={filename}>{button}</a> }
+ }),
)
.into()
})
diff --git a/ui/src/lib.rs b/ui/src/lib.rs
index 1aac7571..e693ee76 100644
--- a/ui/src/lib.rs
+++ b/ui/src/lib.rs
@@ -1,3 +1,5 @@
+use gloo_utils::format::JsValueSerdeExt;
+use gloo_utils::window;
use js_sys::{Array, JsString, Object};
use pdm_api_types::remote_updates::RemoteUpdateSummary;
use pdm_api_types::remotes::RemoteType;
@@ -37,6 +39,7 @@ pub use search_provider::SearchProvider;
mod dashboard;
+use wasm_bindgen::JsValue;
use yew::html::IntoEventCallback;
use yew::Html;
use yew_router::prelude::RouterScopeExt;
@@ -303,3 +306,16 @@ pub fn extract_package_version(
version.parse().ok()
}
+
+#[derive(Deserialize)]
+struct ProxmoxServerConfig {
+ #[serde(alias = "NodeName")]
+ pub node_name: String,
+}
+
+/// Returns the nodename from the index if set
+pub fn get_nodename() -> Option<String> {
+ let value = js_sys::Reflect::get(&window(), &JsValue::from_str("Proxmox")).ok()?;
+ let config: ProxmoxServerConfig = JsValueSerdeExt::into_serde(&value).ok()?;
+ Some(config.node_name)
+}
diff --git a/ui/src/remotes/wizard_page_info.rs b/ui/src/remotes/wizard_page_info.rs
index fbe57d63..4551212e 100644
--- a/ui/src/remotes/wizard_page_info.rs
+++ b/ui/src/remotes/wizard_page_info.rs
@@ -1,10 +1,8 @@
use std::rc::Rc;
use anyhow::Error;
-use gloo_utils::{format::JsValueSerdeExt, window};
use html::IntoEventCallback;
use serde::{Deserialize, Serialize};
-use wasm_bindgen::JsValue;
use yew::virtual_dom::{Key, VComp, VNode};
use proxmox_schema::property_string::PropertyString;
@@ -25,7 +23,7 @@ use pdm_api_types::remotes::{NodeUrl, Remote, RemoteType, REMOTE_ID_SCHEMA};
use pwt_macros::builder;
use super::wizard_page_connect::ConnectParams;
-use crate::widget::PveRealmSelector;
+use crate::{get_nodename, widget::PveRealmSelector};
#[derive(Clone, PartialEq, Properties)]
#[builder]
@@ -414,15 +412,3 @@ impl From<WizardPageInfo> for VNode {
VNode::from(comp)
}
}
-
-#[derive(Deserialize)]
-struct ProxmoxServerConfig {
- #[serde(alias = "NodeName")]
- pub node_name: String,
-}
-
-fn get_nodename() -> Option<String> {
- let value = js_sys::Reflect::get(&window(), &JsValue::from_str("Proxmox")).ok()?;
- let config: ProxmoxServerConfig = JsValueSerdeExt::into_serde(&value).ok()?;
- Some(config.node_name)
-}
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
next reply other threads:[~2025-12-10 14:00 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-10 13:59 Dominik Csapak [this message]
2025-12-16 13:50 ` 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=20251210140008.3046928-1-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.