all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/8] ui: add remote datacenter/node notes panels
@ 2025-11-28 10:18 Dominik Csapak
  2025-11-28 10:18 ` [pdm-devel] [PATCH proxmox 1/2] pve api types: add node config get api call Dominik Csapak
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Dominik Csapak @ 2025-11-28 10:18 UTC (permalink / raw)
  To: pdm-devel

not editable currently. One special thing is how we handle the /cluster/options
api call, see the relevant commits for details

proxmox:

Dominik Csapak (2):
  pve api types: add node config get api call
  pve api types: add cluster options api call

 pve-api-types/generate.pl            |  15 +-
 pve-api-types/src/generated/code.rs  |  36 ++-
 pve-api-types/src/generated/types.rs | 335 ++++++++++++++++++++++++---
 pve-api-types/src/types/verifiers.rs |  28 +++
 4 files changed, 370 insertions(+), 44 deletions(-)


proxmox-yew-comp:

Dominik Csapak (1):
  notes edit: hide toolbar when editing is not possible

 src/notes_view.rs | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)


proxmox-datacenter-manager:

Dominik Csapak (5):
  server: api: add nodes config api
  server: api: pve: add cluster options api call
  ui: pve: rename remote module
  ui: pve: nodes: add panel for notes
  ui: pve: datacenter: add remote notes panel

 server/src/api/pve/mod.rs                    | 24 ++++++
 server/src/api/pve/node.rs                   | 22 ++++-
 ui/src/pve/mod.rs                            | 10 +--
 ui/src/pve/node/mod.rs                       | 25 ++++--
 ui/src/pve/remote/mod.rs                     | 84 ++++++++++++++++++++
 ui/src/pve/{remote.rs => remote_overview.rs} |  0
 6 files changed, 153 insertions(+), 12 deletions(-)
 create mode 100644 ui/src/pve/remote/mod.rs
 rename ui/src/pve/{remote.rs => remote_overview.rs} (100%)


Summary over all repositories:
  11 files changed, 533 insertions(+), 67 deletions(-)

-- 
Generated by git-murpp 0.8.1


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [pdm-devel] [PATCH proxmox 1/2] pve api types: add node config get api call
  2025-11-28 10:18 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/8] ui: add remote datacenter/node notes panels Dominik Csapak
@ 2025-11-28 10:18 ` Dominik Csapak
  2025-11-28 10:18 ` [pdm-devel] [PATCH proxmox 2/2] pve api types: add cluster options " Dominik Csapak
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Dominik Csapak @ 2025-11-28 10:18 UTC (permalink / raw)
  To: pdm-devel

re-implement the ACME regexes here from what is defined in pve-manager,
since the ones we have in proxmox-schema are slightly different.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 pve-api-types/generate.pl            |  12 +-
 pve-api-types/src/generated/code.rs  |  22 +-
 pve-api-types/src/generated/types.rs | 335 ++++++++++++++++++++++++---
 pve-api-types/src/types/verifiers.rs |  28 +++
 4 files changed, 354 insertions(+), 43 deletions(-)

diff --git a/pve-api-types/generate.pl b/pve-api-types/generate.pl
index f72a776a..2caf1cff 100755
--- a/pve-api-types/generate.pl
+++ b/pve-api-types/generate.pl
@@ -42,8 +42,8 @@ Schema2Rust::register_format('CIDRv4' => { code => 'verifiers::verify_cidrv4' })
 Schema2Rust::register_format('CIDRv6' => { code => 'verifiers::verify_cidrv6' });
 Schema2Rust::register_format('ipv4mask' => { code => 'verifiers::verify_ipv4_mask' });
 Schema2Rust::register_format('mac-addr' => { regex => '^(?i)[a-f0-9][02468ace](?::[a-f0-9]{2}){5}$' });
-## Schema2Rust::register_format('pve-acme-alias' => { code => 'verify_pve_acme_alias' });
-## Schema2Rust::register_format('pve-acme-domain' => { code => 'verify_pve_acme_domain' });
+Schema2Rust::register_format('pve-acme-alias' => { code => 'verifiers::verify_pve_acme_alias' });
+Schema2Rust::register_format('pve-acme-domain' => { code => 'verifiers::verify_pve_acme_domain' });
 Schema2Rust::register_format('pve-bridge-id' => { regex => '^'.$BRIDGEID_RE.'$' });
 Schema2Rust::register_format('pve-configid' => { regex => $CONFIGID_RE });
 ## Schema2Rust::register_format('pve-groupid' => { code => 'verify_pve_groupid' });
@@ -213,13 +213,7 @@ Schema2Rust::derive('ClusterResource' => 'Clone', 'PartialEq');
 
 api(GET => '/nodes', 'list_nodes', 'return-name' => 'ClusterNodeIndexResponse');
 Schema2Rust::derive('ClusterNodeIndexResponse' => 'Clone', 'PartialEq');
-# api(
-#     GET => '/nodes/{node}/config',
-#     'get_node_config',
-#     'param-name' => 'GetNodeConfig',
-#     'return-name' => 'NodeConfig',
-#     # 'return-type' => { type => 'object', properties => PVE::NodeConfig::get_nodeconfig_schema() },
-# );
+api(GET => '/nodes/{node}/config', 'node_config', 'return-name' => 'NodeConfig');
 # api(PUT => '/nodes/{node}/config', 'set_node_config', 'param-name' => 'UpdateNodeConfig');
 # subscription api
 #
diff --git a/pve-api-types/src/generated/code.rs b/pve-api-types/src/generated/code.rs
index a74c99e2..0dd6d8e1 100644
--- a/pve-api-types/src/generated/code.rs
+++ b/pve-api-types/src/generated/code.rs
@@ -185,7 +185,6 @@
 /// - /nodes/{node}/certificates/acme/certificate
 /// - /nodes/{node}/certificates/custom
 /// - /nodes/{node}/certificates/info
-/// - /nodes/{node}/config
 /// - /nodes/{node}/disks
 /// - /nodes/{node}/disks/directory
 /// - /nodes/{node}/disks/directory/{name}
@@ -678,6 +677,15 @@ pub trait PveClient {
         Err(Error::Other("migrate_qemu not implemented"))
     }
 
+    /// Get node configuration options.
+    async fn node_config(
+        &self,
+        node: &str,
+        property: Option<NodeConfigProperty>,
+    ) -> Result<NodeConfig, Error> {
+        Err(Error::Other("node_config not implemented"))
+    }
+
     /// Get host firewall options.
     async fn node_firewall_options(&self, node: &str) -> Result<NodeFirewallOptions, Error> {
         Err(Error::Other("node_firewall_options not implemented"))
@@ -1368,6 +1376,18 @@ where
         Ok(self.0.post(url, &params).await?.expect_json()?.data)
     }
 
+    /// Get node configuration options.
+    async fn node_config(
+        &self,
+        node: &str,
+        property: Option<NodeConfigProperty>,
+    ) -> Result<NodeConfig, Error> {
+        let url = &ApiPathBuilder::new(format!("/api2/extjs/nodes/{node}/config"))
+            .maybe_arg("property", &property)
+            .build();
+        Ok(self.0.get(url).await?.expect_json()?.data)
+    }
+
     /// Get host firewall options.
     async fn node_firewall_options(&self, node: &str) -> Result<NodeFirewallOptions, Error> {
         let url = &format!("/api2/extjs/nodes/{node}/firewall/options");
diff --git a/pve-api-types/src/generated/types.rs b/pve-api-types/src/generated/types.rs
index 74f8638f..8963baf9 100644
--- a/pve-api-types/src/generated/types.rs
+++ b/pve-api-types/src/generated/types.rs
@@ -7500,6 +7500,275 @@ pub enum NetworkInterfaceVlanProtocol {
 serde_plain::derive_display_from_serialize!(NetworkInterfaceVlanProtocol);
 serde_plain::derive_fromstr_from_deserialize!(NetworkInterfaceVlanProtocol);
 
+#[api(
+    properties: {
+        acme: {
+            format: &ApiStringFormat::PropertyString(&NodeConfigAcme::API_SCHEMA),
+            optional: true,
+            type: String,
+        },
+        acmedomain: {
+            type: NodeConfigAcmedomainArray,
+        },
+        "ballooning-target": {
+            default: 80,
+            maximum: 100,
+            minimum: 0,
+            optional: true,
+            type: Integer,
+        },
+        description: {
+            max_length: 65536,
+            optional: true,
+            type: String,
+        },
+        digest: {
+            max_length: 40,
+            optional: true,
+            type: String,
+        },
+        "startall-onboot-delay": {
+            default: 0,
+            maximum: 300,
+            minimum: 0,
+            optional: true,
+            type: Integer,
+        },
+        wakeonlan: {
+            format: &ApiStringFormat::PropertyString(&NodeConfigWakeonlan::API_SCHEMA),
+            optional: true,
+            type: String,
+        },
+    },
+)]
+/// Object.
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct NodeConfig {
+    /// Node specific ACME settings.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub acme: Option<String>,
+
+    /// ACME domain and validation plugin
+    #[serde(flatten)]
+    pub acmedomain: NodeConfigAcmedomainArray,
+
+    /// RAM usage target for ballooning (in percent of total memory)
+    #[serde(deserialize_with = "proxmox_serde::perl::deserialize_u8")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "ballooning-target")]
+    pub ballooning_target: Option<u8>,
+
+    /// Description for the Node. Shown in the web-interface node notes panel.
+    /// This is saved as comment inside the configuration file.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub description: Option<String>,
+
+    /// Prevent changes if current configuration file has different SHA1 digest.
+    /// This can be used to prevent concurrent modifications.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub digest: Option<String>,
+
+    /// Initial delay in seconds, before starting all the Virtual Guests with
+    /// on-boot enabled.
+    #[serde(deserialize_with = "proxmox_serde::perl::deserialize_u16")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "startall-onboot-delay")]
+    pub startall_onboot_delay: Option<u16>,
+
+    /// Node specific wake on LAN settings.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub wakeonlan: Option<String>,
+}
+generate_array_field! {
+    NodeConfigAcmedomainArray [ 6 ] :
+    r#"ACME domain and validation plugin"#,
+    String => {
+        description: "ACME domain and validation plugin",
+        format: &ApiStringFormat::PropertyString(&NodeConfigAcmedomain::API_SCHEMA),
+        type: String,
+    }
+    acmedomain
+}
+
+const_regex! {
+
+NODE_CONFIG_ACME_ACCOUNT_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
+
+}
+
+#[test]
+fn test_regex_compilation_16() {
+    use regex::Regex;
+    let _: &Regex = &NODE_CONFIG_ACME_ACCOUNT_RE;
+}
+#[api(
+    properties: {
+        account: {
+            default: "default",
+            format: &ApiStringFormat::Pattern(&NODE_CONFIG_ACME_ACCOUNT_RE),
+            optional: true,
+            type: String,
+        },
+        domains: {
+            format: &ApiStringFormat::VerifyFn(verifiers::verify_pve_acme_domain),
+            optional: true,
+            type: String,
+        },
+    },
+)]
+/// Object.
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct NodeConfigAcme {
+    /// ACME account config file name.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub account: Option<String>,
+
+    /// List of domains for this node's ACME certificate
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub domains: Option<String>,
+}
+
+const_regex! {
+
+NODE_CONFIG_ACMEDOMAIN_PLUGIN_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
+
+}
+
+#[test]
+fn test_regex_compilation_17() {
+    use regex::Regex;
+    let _: &Regex = &NODE_CONFIG_ACMEDOMAIN_PLUGIN_RE;
+}
+#[api(
+    default_key: "domain",
+    properties: {
+        alias: {
+            format: &ApiStringFormat::VerifyFn(verifiers::verify_pve_acme_alias),
+            optional: true,
+            type: String,
+        },
+        domain: {
+            format: &ApiStringFormat::VerifyFn(verifiers::verify_pve_acme_domain),
+            type: String,
+        },
+        plugin: {
+            default: "standalone",
+            format: &ApiStringFormat::Pattern(&NODE_CONFIG_ACMEDOMAIN_PLUGIN_RE),
+            optional: true,
+            type: String,
+        },
+    },
+)]
+/// Object.
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct NodeConfigAcmedomain {
+    /// Alias for the Domain to verify ACME Challenge over DNS
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub alias: Option<String>,
+
+    /// domain for this node's ACME certificate
+    pub domain: String,
+
+    /// The ACME plugin ID
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub plugin: Option<String>,
+}
+
+#[api]
+/// Return only a specific property from the node configuration.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+pub enum NodeConfigProperty {
+    #[serde(rename = "acme")]
+    /// acme.
+    Acme,
+    #[serde(rename = "acmedomain0")]
+    /// acmedomain0.
+    Acmedomain0,
+    #[serde(rename = "acmedomain1")]
+    /// acmedomain1.
+    Acmedomain1,
+    #[serde(rename = "acmedomain2")]
+    /// acmedomain2.
+    Acmedomain2,
+    #[serde(rename = "acmedomain3")]
+    /// acmedomain3.
+    Acmedomain3,
+    #[serde(rename = "acmedomain4")]
+    /// acmedomain4.
+    Acmedomain4,
+    #[serde(rename = "acmedomain5")]
+    /// acmedomain5.
+    Acmedomain5,
+    #[serde(rename = "ballooning-target")]
+    /// ballooning-target.
+    BallooningTarget,
+    #[serde(rename = "description")]
+    /// description.
+    Description,
+    #[serde(rename = "startall-onboot-delay")]
+    /// startall-onboot-delay.
+    StartallOnbootDelay,
+    #[serde(rename = "wakeonlan")]
+    /// wakeonlan.
+    Wakeonlan,
+    /// Unknown variants for forward compatibility.
+    #[serde(untagged)]
+    UnknownEnumValue(FixedString),
+}
+serde_plain::derive_display_from_serialize!(NodeConfigProperty);
+serde_plain::derive_fromstr_from_deserialize!(NodeConfigProperty);
+
+const_regex! {
+
+NODE_CONFIG_WAKEONLAN_BIND_INTERFACE_RE = r##"^[a-zA-Z][a-zA-Z0-9_]{1,20}([:\.]\d+)?$"##;
+NODE_CONFIG_WAKEONLAN_MAC_RE = r##"^(?i)[a-f0-9][02468ace](?::[a-f0-9]{2}){5}$"##;
+
+}
+
+#[test]
+fn test_regex_compilation_18() {
+    use regex::Regex;
+    let _: &Regex = &NODE_CONFIG_WAKEONLAN_BIND_INTERFACE_RE;
+    let _: &Regex = &NODE_CONFIG_WAKEONLAN_MAC_RE;
+}
+#[api(
+    default_key: "mac",
+    properties: {
+        "bind-interface": {
+            default: "The interface carrying the default route",
+            format: &ApiStringFormat::Pattern(&NODE_CONFIG_WAKEONLAN_BIND_INTERFACE_RE),
+            optional: true,
+            type: String,
+        },
+        "broadcast-address": {
+            default: "255.255.255.255",
+            format: &ApiStringFormat::VerifyFn(verifiers::verify_ipv4),
+            optional: true,
+            type: String,
+        },
+        mac: {
+            format: &ApiStringFormat::Pattern(&NODE_CONFIG_WAKEONLAN_MAC_RE),
+            type: String,
+        },
+    },
+)]
+/// Object.
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct NodeConfigWakeonlan {
+    /// Bind to this interface when sending wake on LAN packet
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "bind-interface")]
+    pub bind_interface: Option<String>,
+
+    /// IPv4 broadcast address to use when sending wake on LAN packet
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "broadcast-address")]
+    pub broadcast_address: Option<String>,
+
+    /// MAC address for wake on LAN
+    pub mac: String,
+}
+
 #[api(
     properties: {
         enable: {
@@ -8403,7 +8672,7 @@ PVE_QM_HOSTPCI_MAPPING_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
 }
 
 #[test]
-fn test_regex_compilation_16() {
+fn test_regex_compilation_19() {
     use regex::Regex;
     let _: &Regex = &PVE_QM_HOSTPCI_MAPPING_RE;
 }
@@ -8572,7 +8841,7 @@ PVE_QM_IDE_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_17() {
+fn test_regex_compilation_20() {
     use regex::Regex;
     let _: &Regex = &PVE_QM_IDE_MODEL_RE;
     let _: &Regex = &PVE_QM_IDE_SERIAL_RE;
@@ -9639,7 +9908,7 @@ QEMU_CONFIG_VMSTATESTORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9])$"##;
 }
 
 #[test]
-fn test_regex_compilation_18() {
+fn test_regex_compilation_21() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_AFFINITY_RE;
     let _: &Regex = &QEMU_CONFIG_BOOTDISK_RE;
@@ -10825,7 +11094,7 @@ QEMU_CONFIG_EFIDISK0_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_19() {
+fn test_regex_compilation_22() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_EFIDISK0_SIZE_RE;
 }
@@ -11233,7 +11502,7 @@ QEMU_CONFIG_NET_MACADDR_RE = r##"^(?i)[a-f0-9][02468ace](?::[a-f0-9]{2}){5}$"##;
 }
 
 #[test]
-fn test_regex_compilation_20() {
+fn test_regex_compilation_23() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_NET_BRIDGE_RE;
     let _: &Regex = &QEMU_CONFIG_NET_MACADDR_RE;
@@ -11539,7 +11808,7 @@ QEMU_CONFIG_SATA_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_21() {
+fn test_regex_compilation_24() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_SATA_SERIAL_RE;
     let _: &Regex = &QEMU_CONFIG_SATA_SIZE_RE;
@@ -11872,7 +12141,7 @@ QEMU_CONFIG_SCSI_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_22() {
+fn test_regex_compilation_25() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_SCSI_SERIAL_RE;
     let _: &Regex = &QEMU_CONFIG_SCSI_SIZE_RE;
@@ -12336,7 +12605,7 @@ QEMU_CONFIG_TPMSTATE0_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_23() {
+fn test_regex_compilation_26() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_TPMSTATE0_SIZE_RE;
 }
@@ -12441,7 +12710,7 @@ QEMU_CONFIG_USB_MAPPING_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
 }
 
 #[test]
-fn test_regex_compilation_24() {
+fn test_regex_compilation_27() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_USB_MAPPING_RE;
 }
@@ -12611,7 +12880,7 @@ QEMU_CONFIG_VIRTIO_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_25() {
+fn test_regex_compilation_28() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_VIRTIO_SERIAL_RE;
     let _: &Regex = &QEMU_CONFIG_VIRTIO_SIZE_RE;
@@ -12942,7 +13211,7 @@ QEMU_CONFIG_VIRTIOFS_DIRID_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
 }
 
 #[test]
-fn test_regex_compilation_26() {
+fn test_regex_compilation_29() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_VIRTIOFS_DIRID_RE;
 }
@@ -13237,7 +13506,7 @@ QEMU_MOVE_DISK_STORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9])$"##;
 }
 
 #[test]
-fn test_regex_compilation_27() {
+fn test_regex_compilation_30() {
     use regex::Regex;
     let _: &Regex = &QEMU_MOVE_DISK_STORAGE_RE;
 }
@@ -14837,7 +15106,7 @@ REMOTE_MIGRATE_LXC_TARGET_STORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]):(?i:
 }
 
 #[test]
-fn test_regex_compilation_28() {
+fn test_regex_compilation_31() {
     use regex::Regex;
     let _: &Regex = &REMOTE_MIGRATE_LXC_TARGET_BRIDGE_RE;
     let _: &Regex = &REMOTE_MIGRATE_LXC_TARGET_STORAGE_RE;
@@ -14954,7 +15223,7 @@ REMOTE_MIGRATE_QEMU_TARGET_STORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]):(?i
 }
 
 #[test]
-fn test_regex_compilation_29() {
+fn test_regex_compilation_32() {
     use regex::Regex;
     let _: &Regex = &REMOTE_MIGRATE_QEMU_TARGET_BRIDGE_RE;
     let _: &Regex = &REMOTE_MIGRATE_QEMU_TARGET_STORAGE_RE;
@@ -15271,7 +15540,7 @@ SDN_CONTROLLER_ISIS_NET_RE = r##"^[a-fA-F0-9]{2}(\.[a-fA-F0-9]{4}){3,9}\.[a-fA-F
 }
 
 #[test]
-fn test_regex_compilation_30() {
+fn test_regex_compilation_33() {
     use regex::Regex;
     let _: &Regex = &SDN_CONTROLLER_ISIS_IFACES_RE;
     let _: &Regex = &SDN_CONTROLLER_ISIS_NET_RE;
@@ -15424,7 +15693,7 @@ SDN_CONTROLLER_PENDING_ISIS_NET_RE = r##"^[a-fA-F0-9]{2}(\.[a-fA-F0-9]{4}){3,9}\
 }
 
 #[test]
-fn test_regex_compilation_31() {
+fn test_regex_compilation_34() {
     use regex::Regex;
     let _: &Regex = &SDN_CONTROLLER_PENDING_ISIS_IFACES_RE;
     let _: &Regex = &SDN_CONTROLLER_PENDING_ISIS_NET_RE;
@@ -15725,7 +15994,7 @@ SDN_ZONE_EXITNODES_PRIMARY_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
 }
 
 #[test]
-fn test_regex_compilation_32() {
+fn test_regex_compilation_35() {
     use regex::Regex;
     let _: &Regex = &SDN_ZONE_EXITNODES_RE;
     let _: &Regex = &SDN_ZONE_EXITNODES_PRIMARY_RE;
@@ -16002,7 +16271,7 @@ SDN_ZONE_PENDING_EXITNODES_PRIMARY_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9]
 }
 
 #[test]
-fn test_regex_compilation_33() {
+fn test_regex_compilation_36() {
     use regex::Regex;
     let _: &Regex = &SDN_ZONE_PENDING_EXITNODES_RE;
     let _: &Regex = &SDN_ZONE_PENDING_EXITNODES_PRIMARY_RE;
@@ -16332,7 +16601,7 @@ START_QEMU_TARGETSTORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]):(?i:[a-z][a-z
 }
 
 #[test]
-fn test_regex_compilation_34() {
+fn test_regex_compilation_37() {
     use regex::Regex;
     let _: &Regex = &START_QEMU_MIGRATEDFROM_RE;
     let _: &Regex = &START_QEMU_TARGETSTORAGE_RE;
@@ -16506,7 +16775,7 @@ STOP_QEMU_MIGRATEDFROM_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
 }
 
 #[test]
-fn test_regex_compilation_35() {
+fn test_regex_compilation_38() {
     use regex::Regex;
     let _: &Regex = &STOP_QEMU_MIGRATEDFROM_RE;
 }
@@ -16608,7 +16877,7 @@ STORAGE_INFO_STORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9])$"##;
 }
 
 #[test]
-fn test_regex_compilation_36() {
+fn test_regex_compilation_39() {
     use regex::Regex;
     let _: &Regex = &STORAGE_INFO_STORAGE_RE;
 }
@@ -17046,7 +17315,7 @@ UPDATE_CLUSTER_FIREWALL_OPTIONS_DELETE_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
 }
 
 #[test]
-fn test_regex_compilation_37() {
+fn test_regex_compilation_40() {
     use regex::Regex;
     let _: &Regex = &UPDATE_CLUSTER_FIREWALL_OPTIONS_DELETE_RE;
 }
@@ -17138,7 +17407,7 @@ UPDATE_GUEST_FIREWALL_OPTIONS_DELETE_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
 }
 
 #[test]
-fn test_regex_compilation_38() {
+fn test_regex_compilation_41() {
     use regex::Regex;
     let _: &Regex = &UPDATE_GUEST_FIREWALL_OPTIONS_DELETE_RE;
 }
@@ -17269,7 +17538,7 @@ UPDATE_LXC_CONFIG_TIMEZONE_RE = r##"^.*/.*$"##;
 }
 
 #[test]
-fn test_regex_compilation_39() {
+fn test_regex_compilation_42() {
     use regex::Regex;
     let _: &Regex = &UPDATE_LXC_CONFIG_DELETE_RE;
     let _: &Regex = &UPDATE_LXC_CONFIG_REVERT_RE;
@@ -17648,7 +17917,7 @@ UPDATE_NODE_FIREWALL_OPTIONS_DELETE_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
 }
 
 #[test]
-fn test_regex_compilation_40() {
+fn test_regex_compilation_43() {
     use regex::Regex;
     let _: &Regex = &UPDATE_NODE_FIREWALL_OPTIONS_DELETE_RE;
 }
@@ -17869,7 +18138,7 @@ UPDATE_QEMU_CONFIG_VMSTATESTORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9])$"##;
 }
 
 #[test]
-fn test_regex_compilation_41() {
+fn test_regex_compilation_44() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_AFFINITY_RE;
     let _: &Regex = &UPDATE_QEMU_CONFIG_BOOTDISK_RE;
@@ -18781,7 +19050,7 @@ UPDATE_QEMU_CONFIG_ASYNC_VMSTATESTORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]
 }
 
 #[test]
-fn test_regex_compilation_42() {
+fn test_regex_compilation_45() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_ASYNC_AFFINITY_RE;
     let _: &Regex = &UPDATE_QEMU_CONFIG_ASYNC_BOOTDISK_RE;
@@ -19671,7 +19940,7 @@ UPDATE_QEMU_CONFIG_EFIDISK0_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_43() {
+fn test_regex_compilation_46() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_EFIDISK0_SIZE_RE;
 }
@@ -19756,7 +20025,7 @@ UPDATE_QEMU_CONFIG_IDE_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_44() {
+fn test_regex_compilation_47() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_IDE_MODEL_RE;
     let _: &Regex = &UPDATE_QEMU_CONFIG_IDE_SERIAL_RE;
@@ -20112,7 +20381,7 @@ UPDATE_QEMU_CONFIG_SATA_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_45() {
+fn test_regex_compilation_48() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_SATA_SERIAL_RE;
     let _: &Regex = &UPDATE_QEMU_CONFIG_SATA_SIZE_RE;
@@ -20457,7 +20726,7 @@ UPDATE_QEMU_CONFIG_SCSI_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_46() {
+fn test_regex_compilation_49() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_SCSI_SERIAL_RE;
     let _: &Regex = &UPDATE_QEMU_CONFIG_SCSI_SIZE_RE;
@@ -20857,7 +21126,7 @@ UPDATE_QEMU_CONFIG_TPMSTATE0_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_47() {
+fn test_regex_compilation_50() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_TPMSTATE0_SIZE_RE;
 }
@@ -20920,7 +21189,7 @@ UPDATE_QEMU_CONFIG_VIRTIO_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_48() {
+fn test_regex_compilation_51() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_VIRTIO_SERIAL_RE;
     let _: &Regex = &UPDATE_QEMU_CONFIG_VIRTIO_SIZE_RE;
diff --git a/pve-api-types/src/types/verifiers.rs b/pve-api-types/src/types/verifiers.rs
index 092893b3..462d30ef 100644
--- a/pve-api-types/src/types/verifiers.rs
+++ b/pve-api-types/src/types/verifiers.rs
@@ -24,6 +24,14 @@ pub fn verify_pve_volume_id_or_absolute_path(s: &str) -> Result<(), Error> {
 macro_rules! DNS_NAMERE { () => (r##"([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)"##) }
 #[rustfmt::skip]
 macro_rules! DNS_RE { () => (concat!("(", DNS_NAMERE!(), "\\.)*", DNS_NAMERE!(), "$")) }
+#[rustfmt::skip]
+macro_rules! ACME_NAME_RE { () => (r##"([a-zA-Z0-9]([a-zA-Z0-9_\-]*)?)"##) }
+#[rustfmt::skip]
+macro_rules! ACME_RE { () => (concat!("(", ACME_NAME_RE!(), "\\.)*", ACME_NAME_RE!(), "$")) }
+#[rustfmt::skip]
+macro_rules! ACME_ALIAS_NAME_RE { () => (r##"([a-zA-Z0-9_]([a-zA-Z0-9_\-]*)?)"##) }
+#[rustfmt::skip]
+macro_rules! ACME_ALIAS_RE { () => (concat!("(", ACME_ALIAS_NAME_RE!(), "\\.)*", ACME_ALIAS_NAME_RE!(), "$")) }
 
 const_regex! {
 
@@ -31,6 +39,10 @@ pub VOLUME_ID = r##"^(?i)([a-z][a-z0-9\-\_\.]*[a-z0-9]):(.+)$"##;
 //pub DNS_NAMERE = concat!("^", DNS_NAMERE!(), "$");
 pub DNS_RE = concat!("^", DNS_RE!(), "$");
 
+pub ACME_ALIAS_RE = concat!("^", ACME_ALIAS_RE!(), "$");
+
+pub ACME_RE = concat!("^", ACME_RE!(), "$");
+
 pub FE80_RE = r##"^(?i)fe80:"##;
 
 pub IFACE_RE = r##"^(?i)[a-z][a-z0-9_]{1,20}([:\.]\d+)?$"##;
@@ -282,3 +294,19 @@ pub fn verify_sdn_bgp_rt(s: &str) -> Result<(), Error> {
 
     Ok(())
 }
+
+pub fn verify_pve_acme_domain(s: &str) -> Result<(), Error> {
+    if ACME_RE.is_match(s) {
+        Ok(())
+    } else {
+        bail!("not a valid acme domain");
+    }
+}
+
+pub fn verify_pve_acme_alias(s: &str) -> Result<(), Error> {
+    if ACME_ALIAS_RE.is_match(s) {
+        Ok(())
+    } else {
+        bail!("not a valid acme alias");
+    }
+}
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [pdm-devel] [PATCH proxmox 2/2] pve api types: add cluster options api call
  2025-11-28 10:18 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/8] ui: add remote datacenter/node notes panels Dominik Csapak
  2025-11-28 10:18 ` [pdm-devel] [PATCH proxmox 1/2] pve api types: add node config get api call Dominik Csapak
@ 2025-11-28 10:18 ` Dominik Csapak
  2025-11-28 10:18 ` [pdm-devel] [PATCH yew-comp 1/1] notes edit: hide toolbar when editing is not possible Dominik Csapak
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Dominik Csapak @ 2025-11-28 10:18 UTC (permalink / raw)
  To: pdm-devel

so we can get e.g. the datacenter notes.

The return schema for this is currently not defined and adding it in
pve-manager is rather hard.

The reason for this is that while we have defined the datacenter config
schema for the update call, the properties are all property-strings. In
the GET call however, we parse these and return a nested object.

We'd either have to copy the whole schema and make sure it does not
diverge, or find some more elegant way to modify the return schema to
include the parsed properties (for some properties this even happens
nested, e.g. a list in a property string gets split into an actual
array).

Since this is not feasible at the moment, the easiest way is to simply
use a Value for now.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 pve-api-types/generate.pl           |  3 +++
 pve-api-types/src/generated/code.rs | 14 +++++++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/pve-api-types/generate.pl b/pve-api-types/generate.pl
index 2caf1cff..8d509856 100755
--- a/pve-api-types/generate.pl
+++ b/pve-api-types/generate.pl
@@ -395,6 +395,9 @@ Schema2Rust::register_format('pve-fw-conntrack-helper' => {
 });
 
 # options
+# FIXME: to use a better return value than `Value`, we first must fix the return schema there
+api(GET => '/cluster/options', 'cluster_options', 'output-type' => 'serde_json::Value');
+
 api(GET => '/cluster/firewall/options', 'cluster_firewall_options', 'return-name' => 'ClusterFirewallOptions');
 api(PUT => '/cluster/firewall/options', 'set_cluster_firewall_options', 'param-name' => 'UpdateClusterFirewallOptions');
 
diff --git a/pve-api-types/src/generated/code.rs b/pve-api-types/src/generated/code.rs
index 0dd6d8e1..ae86c93c 100644
--- a/pve-api-types/src/generated/code.rs
+++ b/pve-api-types/src/generated/code.rs
@@ -114,7 +114,6 @@
 /// - /cluster/notifications/targets
 /// - /cluster/notifications/targets/{name}
 /// - /cluster/notifications/targets/{name}/test
-/// - /cluster/options
 /// - /cluster/replication
 /// - /cluster/replication/{id}
 /// - /cluster/sdn/controllers/{controller}
@@ -403,6 +402,12 @@ pub trait PveClient {
         Err(Error::Other("cluster_metrics_export not implemented"))
     }
 
+    /// Get datacenter options. Without 'Sys.Audit' on '/' not all options are
+    /// returned.
+    async fn cluster_options(&self) -> Result<serde_json::Value, Error> {
+        Err(Error::Other("cluster_options not implemented"))
+    }
+
     /// Resources index (cluster wide).
     async fn cluster_resources(
         &self,
@@ -1009,6 +1014,13 @@ where
         Ok(self.0.get(url).await?.expect_json()?.data)
     }
 
+    /// Get datacenter options. Without 'Sys.Audit' on '/' not all options are
+    /// returned.
+    async fn cluster_options(&self) -> Result<serde_json::Value, Error> {
+        let url = "/api2/extjs/cluster/options";
+        Ok(self.0.get(url).await?.expect_json()?.data)
+    }
+
     /// Resources index (cluster wide).
     async fn cluster_resources(
         &self,
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [pdm-devel] [PATCH yew-comp 1/1] notes edit: hide toolbar when editing is not possible
  2025-11-28 10:18 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/8] ui: add remote datacenter/node notes panels Dominik Csapak
  2025-11-28 10:18 ` [pdm-devel] [PATCH proxmox 1/2] pve api types: add node config get api call Dominik Csapak
  2025-11-28 10:18 ` [pdm-devel] [PATCH proxmox 2/2] pve api types: add cluster options " Dominik Csapak
@ 2025-11-28 10:18 ` Dominik Csapak
  2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 1/5] server: api: add nodes config api Dominik Csapak
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Dominik Csapak @ 2025-11-28 10:18 UTC (permalink / raw)
  To: pdm-devel

instead of displaying a disbled button, simply hide it completely,
saving vertical space.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/notes_view.rs | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/src/notes_view.rs b/src/notes_view.rs
index 315163e..6b0a379 100644
--- a/src/notes_view.rs
+++ b/src/notes_view.rs
@@ -163,20 +163,19 @@ impl LoadableComponent for ProxmoxNotesView {
     }
     fn toolbar(&self, ctx: &LoadableComponentContext<Self>) -> Option<Html> {
         let props = ctx.props();
-        let toolbar = Toolbar::new()
-            .class("pwt-w-100")
-            .class("pwt-overflow-hidden")
-            .class("pwt-border-bottom")
-            .with_child(
-                Button::new(tr!("Edit"))
-                    .disabled(props.on_submit.is_none())
-                    .onclick(
+        props.on_submit.is_some().then_some(
+            Toolbar::new()
+                .class("pwt-w-100")
+                .class("pwt-overflow-hidden")
+                .class("pwt-border-bottom")
+                .with_child(
+                    Button::new(tr!("Edit")).on_activate(
                         ctx.link()
                             .change_view_callback(|_| Some(ViewState::EditNotes)),
                     ),
-            );
-
-        Some(toolbar.into())
+                )
+                .into(),
+        )
     }
 
     fn main_view(&self, _ctx: &LoadableComponentContext<Self>) -> Html {
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [pdm-devel] [PATCH datacenter-manager 1/5] server: api: add nodes config api
  2025-11-28 10:18 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/8] ui: add remote datacenter/node notes panels Dominik Csapak
                   ` (2 preceding siblings ...)
  2025-11-28 10:18 ` [pdm-devel] [PATCH yew-comp 1/1] notes edit: hide toolbar when editing is not possible Dominik Csapak
@ 2025-11-28 10:18 ` Dominik Csapak
  2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 2/5] server: api: pve: add cluster options api call Dominik Csapak
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Dominik Csapak @ 2025-11-28 10:18 UTC (permalink / raw)
  To: pdm-devel

just GET for now

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 server/src/api/pve/node.rs | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/server/src/api/pve/node.rs b/server/src/api/pve/node.rs
index 47bd5b31..1f2d889b 100644
--- a/server/src/api/pve/node.rs
+++ b/server/src/api/pve/node.rs
@@ -5,7 +5,7 @@ use proxmox_schema::api;
 use proxmox_sortable_macro::sortable;
 
 use pdm_api_types::{remotes::REMOTE_ID_SCHEMA, NODE_SCHEMA, PRIV_RESOURCE_AUDIT};
-use pve_api_types::StorageContent;
+use pve_api_types::{NodeConfig, StorageContent};
 
 use crate::api::pve::storage;
 
@@ -29,6 +29,7 @@ const SUBDIRS: SubdirMap = &sorted!([
     ),
     ("storage", &STORAGE_ROUTER),
     ("status", &Router::new().get(&API_METHOD_GET_STATUS)),
+    ("config", &Router::new().get(&API_METHOD_GET_CONFIG))
 ]);
 
 const STORAGE_ROUTER: Router = Router::new()
@@ -138,3 +139,22 @@ async fn get_status(remote: String, node: String) -> Result<pve_api_types::NodeS
     let result = client.node_status(&node).await?;
     Ok(result)
 }
+
+#[api(
+    input: {
+        properties: {
+            remote: { schema: REMOTE_ID_SCHEMA },
+            node: { schema: NODE_SCHEMA },
+        },
+    },
+    access: {
+        permission: &Permission::Privilege(&["resource", "{remote}", "node", "{node}"], PRIV_RESOURCE_AUDIT, false),
+    },
+)]
+/// Get config for the node.
+async fn get_config(remote: String, node: String) -> Result<NodeConfig, Error> {
+    let (remotes, _) = pdm_config::remotes::config()?;
+    let client = super::connect_to_remote(&remotes, &remote)?;
+    let result = client.node_config(&node, None).await?;
+    Ok(result)
+}
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [pdm-devel] [PATCH datacenter-manager 2/5] server: api: pve: add cluster options api call
  2025-11-28 10:18 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/8] ui: add remote datacenter/node notes panels Dominik Csapak
                   ` (3 preceding siblings ...)
  2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 1/5] server: api: add nodes config api Dominik Csapak
@ 2025-11-28 10:18 ` Dominik Csapak
  2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 3/5] ui: pve: rename remote module Dominik Csapak
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Dominik Csapak @ 2025-11-28 10:18 UTC (permalink / raw)
  To: pdm-devel

just GET for now.

It returns a `serde_json::Value` since adding the proper return schema
is rather hard at the moment. See the relevant commit in the
pve-api-types crate.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 server/src/api/pve/mod.rs | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/server/src/api/pve/mod.rs b/server/src/api/pve/mod.rs
index 34d9b760..dddb5dc2 100644
--- a/server/src/api/pve/mod.rs
+++ b/server/src/api/pve/mod.rs
@@ -70,6 +70,7 @@ const REMOTE_SUBDIRS: SubdirMap = &sorted!([
     ("lxc", &lxc::ROUTER),
     ("firewall", &firewall::CLUSTER_FW_ROUTER),
     ("nodes", &NODES_ROUTER),
+    ("options", &OPTIONS_ROUTER),
     ("qemu", &qemu::ROUTER),
     ("resources", &RESOURCES_ROUTER),
     ("cluster-status", &STATUS_ROUTER),
@@ -84,6 +85,8 @@ const RESOURCES_ROUTER: Router = Router::new().get(&API_METHOD_CLUSTER_RESOURCES
 
 const STATUS_ROUTER: Router = Router::new().get(&API_METHOD_CLUSTER_STATUS);
 
+const OPTIONS_ROUTER: Router = Router::new().get(&API_METHOD_GET_OPTIONS);
+
 // converts a remote + PveUpid into a RemoteUpid and starts tracking it
 pub async fn new_remote_upid(remote: String, upid: PveUpid) -> Result<RemoteUpid, Error> {
     let remote_upid = remote_tasks::track_running_pve_task(remote, upid).await?;
@@ -498,3 +501,24 @@ pub async fn list_realm_remote_pve(
 
     Ok(list)
 }
+
+#[api(
+    input: {
+        properties: {
+            remote: { schema: REMOTE_ID_SCHEMA },
+        },
+    },
+    access: {
+        permission: &Permission::Privilege(&["resource", "{remote}"], PRIV_RESOURCE_AUDIT, false),
+    },
+)]
+/// Return the remote's cluster options.
+pub async fn get_options(remote: String) -> Result<serde_json::Value, Error> {
+    let (remotes, _) = pdm_config::remotes::config()?;
+
+    let options = connect_to_remote(&remotes, &remote)?
+        .cluster_options()
+        .await?;
+
+    Ok(options)
+}
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [pdm-devel] [PATCH datacenter-manager 3/5] ui: pve: rename remote module
  2025-11-28 10:18 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/8] ui: add remote datacenter/node notes panels Dominik Csapak
                   ` (4 preceding siblings ...)
  2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 2/5] server: api: pve: add cluster options api call Dominik Csapak
@ 2025-11-28 10:18 ` Dominik Csapak
  2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 4/5] ui: pve: nodes: add panel for notes Dominik Csapak
  2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 5/5] ui: pve: datacenter: add remote notes panel Dominik Csapak
  7 siblings, 0 replies; 9+ messages in thread
From: Dominik Csapak @ 2025-11-28 10:18 UTC (permalink / raw)
  To: pdm-devel

we'll need that namespace for the other panels we want to show when
'datacenter' is selected.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 ui/src/pve/mod.rs                            | 4 ++--
 ui/src/pve/{remote.rs => remote_overview.rs} | 0
 2 files changed, 2 insertions(+), 2 deletions(-)
 rename ui/src/pve/{remote.rs => remote_overview.rs} (100%)

diff --git a/ui/src/pve/mod.rs b/ui/src/pve/mod.rs
index 4629077e..efe61af9 100644
--- a/ui/src/pve/mod.rs
+++ b/ui/src/pve/mod.rs
@@ -26,7 +26,7 @@ use pdm_api_types::resource::{PveResource, ResourceType};
 pub mod lxc;
 pub mod node;
 pub mod qemu;
-pub mod remote;
+pub mod remote_overview;
 pub mod storage;
 pub mod utils;
 
@@ -241,7 +241,7 @@ impl LoadableComponent for PveRemoteComp {
                             .padding(4)
                             .class(FlexFit)
                             .gap(4)
-                            .with_child(remote::RemotePanel::new(
+                            .with_child(remote_overview::RemotePanel::new(
                                 remote.clone(),
                                 self.resources.clone(),
                                 self.last_error.clone(),
diff --git a/ui/src/pve/remote.rs b/ui/src/pve/remote_overview.rs
similarity index 100%
rename from ui/src/pve/remote.rs
rename to ui/src/pve/remote_overview.rs
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [pdm-devel] [PATCH datacenter-manager 4/5] ui: pve: nodes: add panel for notes
  2025-11-28 10:18 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/8] ui: add remote datacenter/node notes panels Dominik Csapak
                   ` (5 preceding siblings ...)
  2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 3/5] ui: pve: rename remote module Dominik Csapak
@ 2025-11-28 10:18 ` Dominik Csapak
  2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 5/5] ui: pve: datacenter: add remote notes panel Dominik Csapak
  7 siblings, 0 replies; 9+ messages in thread
From: Dominik Csapak @ 2025-11-28 10:18 UTC (permalink / raw)
  To: pdm-devel

not editable currently.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 ui/src/pve/node/mod.rs | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/ui/src/pve/node/mod.rs b/ui/src/pve/node/mod.rs
index de79185a..9ad967c5 100644
--- a/ui/src/pve/node/mod.rs
+++ b/ui/src/pve/node/mod.rs
@@ -1,11 +1,8 @@
 use std::rc::Rc;
 
 use gloo_utils::window;
-use proxmox_yew_comp::{AptPackageManager, ConsoleType, XTermJs};
-use yew::{
-    virtual_dom::{VComp, VNode},
-    Context,
-};
+use proxmox_yew_comp::{AptPackageManager, ConsoleType, NotesView, XTermJs};
+use yew::virtual_dom::{VComp, VNode};
 
 use pwt::{
     css::{AlignItems, ColorScheme},
@@ -82,6 +79,24 @@ impl yew::Component for PveNodePanelComp {
                     move |_| PveNodeOverviewPanel::new(remote.clone(), node.clone()).into()
                 },
             )
+            .with_item_builder(
+                TabBarItem::new()
+                    .key("notes_view")
+                    .label(tr!("Notes"))
+                    .icon_class("fa fa-sticky-note-o"),
+                {
+                    let remote = props.remote.clone();
+                    let node = props.node.clone();
+                    move |_| {
+                        NotesView::edit_property(
+                            format!("/pve/remotes/{remote}/nodes/{node}/config"),
+                            "description",
+                        )
+                        .on_submit(None)
+                        .into()
+                    }
+                },
+            )
             .with_item_builder(
                 TabBarItem::new()
                     .key("update_view")
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [pdm-devel] [PATCH datacenter-manager 5/5] ui: pve: datacenter: add remote notes panel
  2025-11-28 10:18 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/8] ui: add remote datacenter/node notes panels Dominik Csapak
                   ` (6 preceding siblings ...)
  2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 4/5] ui: pve: nodes: add panel for notes Dominik Csapak
@ 2025-11-28 10:18 ` Dominik Csapak
  7 siblings, 0 replies; 9+ messages in thread
From: Dominik Csapak @ 2025-11-28 10:18 UTC (permalink / raw)
  To: pdm-devel

to have a place for that, move the remote tasks and the notes below a
tab panel, like we do for the guests and nodes.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 ui/src/pve/mod.rs        |  8 ++--
 ui/src/pve/remote/mod.rs | 84 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+), 5 deletions(-)
 create mode 100644 ui/src/pve/remote/mod.rs

diff --git a/ui/src/pve/mod.rs b/ui/src/pve/mod.rs
index efe61af9..5fd964a9 100644
--- a/ui/src/pve/mod.rs
+++ b/ui/src/pve/mod.rs
@@ -26,6 +26,7 @@ use pdm_api_types::resource::{PveResource, ResourceType};
 pub mod lxc;
 pub mod node;
 pub mod qemu;
+pub mod remote;
 pub mod remote_overview;
 pub mod storage;
 pub mod utils;
@@ -33,7 +34,7 @@ pub mod utils;
 mod tree;
 use tree::PveTreeNode;
 
-use crate::{get_deep_url, remotes::RemoteTaskList};
+use crate::get_deep_url;
 
 #[derive(Debug, Eq, PartialEq, Properties)]
 pub struct PveRemote {
@@ -182,10 +183,7 @@ impl LoadableComponent for PveRemoteComp {
         let remote = &props.remote;
 
         let content: Html = match &self.view {
-            PveTreeNode::Root => Panel::new()
-                .title(tr!("Remote Tasks"))
-                .with_child(RemoteTaskList::new().remote(remote.clone()))
-                .into(),
+            PveTreeNode::Root => remote::PveRemotePanel::new(remote.clone()).into(),
             PveTreeNode::Node(node) => {
                 node::PveNodePanel::new(remote.clone(), node.node.clone()).into()
             }
diff --git a/ui/src/pve/remote/mod.rs b/ui/src/pve/remote/mod.rs
new file mode 100644
index 00000000..60ea4ade
--- /dev/null
+++ b/ui/src/pve/remote/mod.rs
@@ -0,0 +1,84 @@
+use std::rc::Rc;
+
+use proxmox_yew_comp::NotesView;
+use yew::virtual_dom::{VComp, VNode};
+
+use pwt::css::{AlignItems, ColorScheme};
+use pwt::prelude::*;
+use pwt::props::{ContainerBuilder, WidgetBuilder};
+use pwt::widget::{Fa, Row, TabBarItem, TabPanel};
+
+use crate::remotes::RemoteTaskList;
+
+#[derive(Clone, Debug, Eq, PartialEq, Properties)]
+pub struct PveRemotePanel {
+    /// The remote to show
+    pub remote: String,
+}
+
+impl PveRemotePanel {
+    pub fn new(remote: String) -> Self {
+        yew::props!(Self { remote })
+    }
+}
+
+impl From<PveRemotePanel> for VNode {
+    fn from(val: PveRemotePanel) -> Self {
+        VComp::new::<PveRemotePanelComp>(Rc::new(val), None).into()
+    }
+}
+
+struct PveRemotePanelComp;
+
+impl yew::Component for PveRemotePanelComp {
+    type Message = ();
+    type Properties = PveRemotePanel;
+
+    fn create(_ctx: &yew::Context<Self>) -> Self {
+        Self
+    }
+
+    fn view(&self, ctx: &yew::Context<Self>) -> yew::Html {
+        let props = ctx.props();
+
+        let title: Html = Row::new()
+            .gap(2)
+            .class(AlignItems::Baseline)
+            .with_child(Fa::new("building"))
+            .with_child(tr! {"Remote '{0}'", props.remote})
+            .into();
+
+        TabPanel::new()
+            .class(pwt::css::FlexFit)
+            .title(title)
+            .class(ColorScheme::Neutral)
+            .with_item_builder(
+                TabBarItem::new()
+                    .key("tasks_view")
+                    .label(tr!("Remote Tasks"))
+                    .icon_class("fa fa-list"),
+                {
+                    let remote = props.remote.clone();
+                    move |_| RemoteTaskList::new().remote(remote.clone()).into()
+                },
+            )
+            .with_item_builder(
+                TabBarItem::new()
+                    .key("notes_view")
+                    .label(tr!("Notes"))
+                    .icon_class("fa fa-sticky-note-o"),
+                {
+                    let remote = props.remote.clone();
+                    move |_| {
+                        NotesView::edit_property(
+                            format!("/pve/remotes/{remote}/options"),
+                            "description",
+                        )
+                        .on_submit(None)
+                        .into()
+                    }
+                },
+            )
+            .into()
+    }
+}
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-11-28 10:19 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-11-28 10:18 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/8] ui: add remote datacenter/node notes panels Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH proxmox 1/2] pve api types: add node config get api call Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH proxmox 2/2] pve api types: add cluster options " Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH yew-comp 1/1] notes edit: hide toolbar when editing is not possible Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 1/5] server: api: add nodes config api Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 2/5] server: api: pve: add cluster options api call Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 3/5] ui: pve: rename remote module Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 4/5] ui: pve: nodes: add panel for notes Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 5/5] ui: pve: datacenter: add remote notes panel Dominik Csapak

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