From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <pdm-devel-bounces@lists.proxmox.com>
Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9])
	by lore.proxmox.com (Postfix) with ESMTPS id E16E51FF190
	for <inbox@lore.proxmox.com>; Fri, 10 Jan 2025 11:22:05 +0100 (CET)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
	by firstgate.proxmox.com (Proxmox) with ESMTP id 79A5F2909E;
	Fri, 10 Jan 2025 11:21:52 +0100 (CET)
From: Dominik Csapak <d.csapak@proxmox.com>
To: pdm-devel@lists.proxmox.com
Date: Fri, 10 Jan 2025 11:21:41 +0100
Message-Id: <20250110102142.1212874-6-d.csapak@proxmox.com>
X-Mailer: git-send-email 2.39.5
In-Reply-To: <20250110102142.1212874-1-d.csapak@proxmox.com>
References: <20250110102142.1212874-1-d.csapak@proxmox.com>
MIME-Version: 1.0
X-SPAM-LEVEL: Spam detection results:  0
 AWL 0.016 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
 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 4/5] ui: generate URLs with
 the option 'web-url' property
X-BeenThere: pdm-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Proxmox Datacenter Manager development discussion
 <pdm-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pdm-devel>, 
 <mailto:pdm-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pdm-devel/>
List-Post: <mailto:pdm-devel@lists.proxmox.com>
List-Help: <mailto:pdm-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel>, 
 <mailto:pdm-devel-request@lists.proxmox.com?subject=subscribe>
Reply-To: Proxmox Datacenter Manager development discussion
 <pdm-devel@lists.proxmox.com>
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: pdm-devel-bounces@lists.proxmox.com
Sender: "pdm-devel" <pdm-devel-bounces@lists.proxmox.com>

This reworks `get_deep_url` so that we use the additional setting for
generating the URL. It still falls back to the previous URL generation
if either the values are not set, or no valid URL can be constructed.

Introduces a helper to extract the node from a resource.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 ui/src/dashboard/top_entities.rs |  6 ++-
 ui/src/lib.rs                    | 75 ++++++++++++++++++++------------
 ui/src/pve/mod.rs                |  4 +-
 ui/src/pve/tree.rs               | 17 ++++++--
 ui/src/widget/resource_tree.rs   | 21 +++++----
 5 files changed, 78 insertions(+), 45 deletions(-)

diff --git a/ui/src/dashboard/top_entities.rs b/ui/src/dashboard/top_entities.rs
index 4bd71b9..af3f853 100644
--- a/ui/src/dashboard/top_entities.rs
+++ b/ui/src/dashboard/top_entities.rs
@@ -21,7 +21,7 @@ use pwt::{
 use pdm_client::types::{Resource, TopEntity};
 
 use crate::{
-    get_deep_url, navigate_to,
+    get_deep_url, get_resource_node, navigate_to,
     renderer::{render_resource_icon, render_resource_name},
 };
 
@@ -131,6 +131,8 @@ impl Component for TopEntitiesComp {
             let rrd = &entity.rrd_data;
             let remote = &entity.remote;
 
+            let node = get_resource_node(resource).map(|n| n.to_string());
+
             let tooltip_anchor = if let Some(info) = self.tooltip_info.as_ref() {
                 if info.id == resource.global_id() {
                     tooltip = Some(create_tooltip(remote, resource, info, &props.metrics_title));
@@ -171,7 +173,7 @@ impl Component for TopEntitiesComp {
                         let remote = remote.clone();
                         let id = resource.id();
                         move |_| {
-                            if let Some(url) = get_deep_url(&link, &remote, &id) {
+                            if let Some(url) = get_deep_url(&link, &remote, node.as_deref(), &id) {
                                 let _ = web_sys::window().unwrap().open_with_url(&url.href());
                             }
                         }
diff --git a/ui/src/lib.rs b/ui/src/lib.rs
index 5a046f6..5c6d076 100644
--- a/ui/src/lib.rs
+++ b/ui/src/lib.rs
@@ -1,4 +1,5 @@
 use pdm_api_types::resource::{PveLxcResource, PveQemuResource};
+use pdm_client::types::Resource;
 use serde::{Deserialize, Serialize};
 
 mod administration;
@@ -78,38 +79,47 @@ pub(crate) fn get_remote<C: yew::Component>(
 pub(crate) fn get_deep_url<C: yew::Component>(
     link: &yew::html::Scope<C>,
     remote: &str,
+    node: Option<&str>,
     id: &str,
 ) -> Option<web_sys::Url> {
     let remote = get_remote(link, remote)?;
-    let (default_port, hash) = match remote.ty {
-        pdm_api_types::remotes::RemoteType::Pve => (
-            "8006",
-            if id.is_empty() {
-                String::new()
-            } else {
-                format!("v1::={id}")
-            },
-        ),
-        pdm_api_types::remotes::RemoteType::Pbs => (
-            "8007",
-            if id.is_empty() {
-                String::new()
-            } else {
-                format!("DataStore-{id}")
-            },
-        ),
+    let hash = match (id, remote.ty) {
+        ("", _) => String::new(),
+        (id, pdm_api_types::remotes::RemoteType::Pve) => format!("v1::={id}"),
+        (id, pdm_api_types::remotes::RemoteType::Pbs) => format!("DataStore-{id}"),
     };
-    let node = remote.nodes.first()?;
-    let url = web_sys::Url::new(&format!("https://{}/", node.hostname));
-    if let Ok(url) = url {
-        if url.port() == "" {
-            url.set_port(default_port);
-        }
-        url.set_hash(&hash);
-        Some(url)
-    } else {
-        None
+
+    let url = match remote.web_url {
+        Some(web_url) => match (web_url.per_node_template.as_deref(), node) {
+            (Some(template), Some(node)) => {
+                web_sys::Url::new(&template.replace("{{nodename}}", node)).ok()
+            }
+            _ => web_url
+                .base_url
+                .as_ref()
+                .map(|url| web_sys::Url::new(url).ok())
+                .flatten(),
+        },
+        None => None,
     }
+    .or_else(|| {
+        let node = remote.nodes.first()?;
+        let url = web_sys::Url::new(&format!("https://{}/", node.hostname));
+        url.ok().map(|url| {
+            if url.port() == "" {
+                let default_port = match remote.ty {
+                    pdm_api_types::remotes::RemoteType::Pve => "8006",
+                    pdm_api_types::remotes::RemoteType::Pbs => "8007",
+                };
+                url.set_port(default_port);
+            }
+            url
+        })
+    });
+    url.map(|url| {
+        url.set_hash(&hash);
+        url
+    })
 }
 
 pub(crate) fn navigate_to<C: yew::Component>(
@@ -135,3 +145,14 @@ pub(crate) fn navigate_to<C: yew::Component>(
         nav.push(&yew_router::AnyRoute::new(format!("/remote-{remote}/{id}")));
     }
 }
+
+pub(crate) fn get_resource_node(resource: &Resource) -> Option<&str> {
+    match resource {
+        Resource::PveStorage(storage) => Some(&storage.node),
+        Resource::PveQemu(qemu) => Some(&qemu.node),
+        Resource::PveLxc(lxc) => Some(&lxc.node),
+        Resource::PveNode(node) => Some(&node.node),
+        Resource::PbsNode(_) => None,
+        Resource::PbsDatastore(_) => None,
+    }
+}
diff --git a/ui/src/pve/mod.rs b/ui/src/pve/mod.rs
index 7925bbf..763e91d 100644
--- a/ui/src/pve/mod.rs
+++ b/ui/src/pve/mod.rs
@@ -181,7 +181,9 @@ impl LoadableComponent for PveRemoteComp {
                                 let link = ctx.link().clone();
                                 let remote = ctx.props().remote.clone();
                                 move |_| {
-                                    if let Some(url) = get_deep_url(&link.yew_link(), &remote, "") {
+                                    if let Some(url) =
+                                        get_deep_url(&link.yew_link(), &remote, None, "")
+                                    {
                                         let _ = window().open_with_url(&url.href());
                                     }
                                 }
diff --git a/ui/src/pve/tree.rs b/ui/src/pve/tree.rs
index 8b1f5ba..50a5ae4 100644
--- a/ui/src/pve/tree.rs
+++ b/ui/src/pve/tree.rs
@@ -574,7 +574,7 @@ fn columns(
         DataTableColumn::new(tr!("Actions"))
             .width("180px")
             .render(move |entry: &PveTreeNode| {
-                let (id, local_id, guest_info) = match entry {
+                let (id, local_id, guest_info, node) = match entry {
                     PveTreeNode::Lxc(r) => {
                         let guest_info = GuestInfo::new(GuestType::Lxc, r.vmid);
                         let local_id = guest_info.local_id();
@@ -582,6 +582,7 @@ fn columns(
                             r.id.as_str(),
                             local_id,
                             Some((guest_info, r.status.as_str())),
+                            Some(r.node.clone()),
                         )
                     }
                     PveTreeNode::Qemu(r) => {
@@ -591,10 +592,16 @@ fn columns(
                             r.id.as_str(),
                             local_id,
                             Some((guest_info, r.status.as_str())),
+                            Some(r.node.clone()),
                         )
                     }
-                    PveTreeNode::Root => ("root", "root".to_string(), None),
-                    PveTreeNode::Node(r) => (r.id.as_str(), format!("node/{}", r.node), None),
+                    PveTreeNode::Root => ("root", "root".to_string(), None, None),
+                    PveTreeNode::Node(r) => (
+                        r.id.as_str(),
+                        format!("node/{}", r.node),
+                        None,
+                        Some(r.node.clone()),
+                    ),
                 };
 
                 Row::new()
@@ -642,7 +649,9 @@ fn columns(
                         let remote = remote.clone();
                         move |()| {
                             // there must be a remote with a connections config if were already here
-                            if let Some(url) = get_deep_url(link.yew_link(), &remote, &local_id) {
+                            if let Some(url) =
+                                get_deep_url(link.yew_link(), &remote, node.as_deref(), &local_id)
+                            {
                                 let _ = window().open_with_url(&url.href());
                             }
                         }
diff --git a/ui/src/widget/resource_tree.rs b/ui/src/widget/resource_tree.rs
index 6c4537d..1b764f7 100644
--- a/ui/src/widget/resource_tree.rs
+++ b/ui/src/widget/resource_tree.rs
@@ -23,7 +23,7 @@ use proxmox_yew_comp::{http_get, Status};
 use pdm_api_types::resource::{RemoteResources, Resource};
 
 use crate::{
-    get_deep_url,
+    get_deep_url, get_resource_node,
     renderer::{render_resource_name, render_status_icon},
     RemoteList,
 };
@@ -321,12 +321,9 @@ fn columns(
             .render(|item: &PdmTreeEntry| {
                 match item {
                     PdmTreeEntry::Root => "",
-                    PdmTreeEntry::Resource(_, resource) => match resource {
-                        Resource::PveStorage(r) => &r.node,
-                        Resource::PveQemu(r) => &r.node,
-                        Resource::PveLxc(r) => &r.node,
-                        _ => "",
-                    },
+                    PdmTreeEntry::Resource(_, resource) => {
+                        get_resource_node(&resource).unwrap_or("")
+                    }
                     PdmTreeEntry::Remote(_, _) => "",
                 }
                 .into()
@@ -338,13 +335,15 @@ fn columns(
             .render({
                 let link = link.clone();
                 move |item: &PdmTreeEntry| {
-                    let (remote, id) = match item {
+                    let (remote, id, node) = match item {
                         PdmTreeEntry::Root => return html! {},
-                        PdmTreeEntry::Resource(remote_id, resource) => (remote_id, resource.id()),
-                        PdmTreeEntry::Remote(remote_id, _) => (remote_id, String::new()),
+                        PdmTreeEntry::Resource(remote_id, resource) => {
+                            (remote_id, resource.id(), get_resource_node(resource))
+                        }
+                        PdmTreeEntry::Remote(remote_id, _) => (remote_id, String::new(), None),
                     };
 
-                    match get_deep_url(&link, remote, &id) {
+                    match get_deep_url(&link, remote, node, &id) {
                         Some(url) => ActionIcon::new("fa fa-external-link")
                             .on_activate(move |()| {
                                 let _ = window().unwrap().open_with_url(&url.href());
-- 
2.39.5



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