[pdm-devel] [PATCH datacenter-manager v5 1/1] ui: add a Node Status tab to the administration panel
Shannon Sterz
s.sterz at proxmox.com
Thu Nov 13 14:32:08 CET 2025
it shows the current node status via the new NodeStatPanel and has
buttons for shutting down and rebooting the node.
Signed-off-by: Shannon Sterz <s.sterz at proxmox.com>
---
ui/Cargo.toml | 1 +
ui/src/administration/mod.rs | 9 +++
ui/src/administration/node_status.rs | 117 +++++++++++++++++++++++++++
3 files changed, 127 insertions(+)
create mode 100644 ui/src/administration/node_status.rs
diff --git a/ui/Cargo.toml b/ui/Cargo.toml
index 780b4ac..4d0da16 100644
--- a/ui/Cargo.toml
+++ b/ui/Cargo.toml
@@ -38,6 +38,7 @@ proxmox-human-byte = "1"
proxmox-login = "1"
proxmox-schema = "5"
proxmox-rrd-api-types = "1"
+proxmox-node-status = "1"
pbs-api-types = "1.0.3"
pdm-api-types = { version = "0.9", path = "../lib/pdm-api-types" }
diff --git a/ui/src/administration/mod.rs b/ui/src/administration/mod.rs
index a9f7ac6..028c84f 100644
--- a/ui/src/administration/mod.rs
+++ b/ui/src/administration/mod.rs
@@ -16,6 +16,8 @@ use pwt_macros::builder;
//mod services;
//pub use services::Services;
+mod node_status;
+
use proxmox_yew_comp::{AptPackageManager, AptRepositories, ExistingProduct, Syslog, Tasks};
#[derive(Clone, PartialEq, Properties)]
@@ -67,6 +69,13 @@ impl Component for PdmServerAdministration {
|_| Services::new().into(),
)
*/
+ .with_item_builder(
+ TabBarItem::new()
+ .key("status")
+ .label(tr!("Node Status"))
+ .icon_class("fa fa-book"),
+ move |_| node_status::NodeStatus::new().into(),
+ )
.with_item_builder(
TabBarItem::new()
.key("updates")
diff --git a/ui/src/administration/node_status.rs b/ui/src/administration/node_status.rs
new file mode 100644
index 0000000..cce3426
--- /dev/null
+++ b/ui/src/administration/node_status.rs
@@ -0,0 +1,117 @@
+use std::rc::Rc;
+
+use anyhow::Error;
+use yew::virtual_dom::{VComp, VNode};
+
+use proxmox_node_status::NodePowerCommand;
+use proxmox_yew_comp::{http_post, ConfirmButton, NodeStatusPanel};
+use pwt::prelude::*;
+use pwt::widget::{Column, Container, Row};
+
+#[derive(Properties, Clone, PartialEq)]
+pub(crate) struct NodeStatus {}
+
+impl NodeStatus {
+ pub(crate) fn new() -> Self {
+ yew::props!(Self {})
+ }
+}
+
+impl From<NodeStatus> for VNode {
+ fn from(value: NodeStatus) -> Self {
+ VComp::new::<PdmNodeStatus>(Rc::new(value), None).into()
+ }
+}
+
+enum Msg {
+ Reload,
+ Error(Error),
+ RebootOrShutdown(NodePowerCommand),
+}
+
+struct PdmNodeStatus {
+ error: Option<Error>,
+}
+
+impl PdmNodeStatus {
+ fn change_power_state(&self, ctx: &yew::Context<Self>, command: NodePowerCommand) {
+ ctx.link().send_future(async move {
+ let data = Some(serde_json::json!({"command": command}));
+
+ match http_post("/nodes/localhost/status", data).await {
+ Ok(()) => Msg::Reload,
+ Err(e) => Msg::Error(e),
+ }
+ });
+ }
+}
+
+impl Component for PdmNodeStatus {
+ type Message = Msg;
+ type Properties = NodeStatus;
+
+ fn create(_ctx: &yew::Context<Self>) -> Self {
+ Self { error: None }
+ }
+
+ fn update(&mut self, ctx: &yew::Context<Self>, msg: Self::Message) -> bool {
+ match msg {
+ Msg::RebootOrShutdown(command) => {
+ self.change_power_state(ctx, command);
+ false
+ }
+ Msg::Error(e) => {
+ self.error = Some(e);
+ true
+ }
+ Msg::Reload => true,
+ }
+ }
+
+ fn view(&self, ctx: &yew::Context<Self>) -> Html {
+ Column::new()
+ .class(pwt::css::FlexFit)
+ .with_child(
+ Container::new()
+ .class("pwt-content-spacer-padding")
+ .class("pwt-content-spacer-colors")
+ .class("pwt-default-colors")
+ .padding_bottom(0)
+ .with_child(
+ Row::new()
+ .gap(1)
+ .with_child(
+ ConfirmButton::new(tr!("Reboot"))
+ .confirm_message(tr!(
+ "Are you sure you want to reboot the node?"
+ ))
+ .on_activate(ctx.link().callback(|_| {
+ Msg::RebootOrShutdown(NodePowerCommand::Reboot)
+ }))
+ .class(pwt::css::ColorScheme::Neutral)
+ .icon_class("fa fa-undo"),
+ )
+ .with_child(
+ ConfirmButton::new(tr!("Shutdown"))
+ .confirm_message(tr!(
+ "Are you sure you want to shut down the node?"
+ ))
+ .on_activate(ctx.link().callback(|_| {
+ Msg::RebootOrShutdown(NodePowerCommand::Shutdown)
+ }))
+ .class(pwt::css::ColorScheme::Neutral)
+ .icon_class("fa fa-power-off"),
+ ),
+ ),
+ )
+ .with_child(
+ Row::new()
+ .class("pwt-content-spacer-padding")
+ .class("pwt-content-spacer-colors")
+ .class("pwt-default-colors")
+ .class(pwt::css::FlexFit)
+ .with_child(NodeStatusPanel::new().status_base_url("/nodes/localhost/status")),
+ )
+ .into()
+ }
+}
--
2.47.3
More information about the pdm-devel
mailing list