all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Dominik Csapak <d.csapak@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [PATCH datacenter-manager 1/4] lib/api/ui: add location property to remote config
Date: Mon,  4 May 2026 14:44:52 +0200	[thread overview]
Message-ID: <20260504124515.2956574-6-d.csapak@proxmox.com> (raw)
In-Reply-To: <20260504124515.2956574-1-d.csapak@proxmox.com>

this will be used to show the remote on a map in a custom view.
Let's the user simply enter the longitude and latitude in the remote
edit window.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 lib/pdm-api-types/src/remotes.rs | 22 ++++++++++++++++++++-
 server/src/api/pbs/mod.rs        |  2 ++
 server/src/api/pve/mod.rs        |  2 ++
 server/src/api/remotes/mod.rs    |  9 +++++++++
 ui/src/remotes/edit_remote.rs    | 34 +++++++++++++++++++++++++++-----
 5 files changed, 63 insertions(+), 6 deletions(-)

diff --git a/lib/pdm-api-types/src/remotes.rs b/lib/pdm-api-types/src/remotes.rs
index b226d190..d879fcfb 100644
--- a/lib/pdm-api-types/src/remotes.rs
+++ b/lib/pdm-api-types/src/remotes.rs
@@ -4,7 +4,7 @@ use http::Uri;
 use serde::{Deserialize, Serialize};
 
 use proxmox_schema::property_string::PropertyString;
-use proxmox_schema::{api, ApiType, Schema, StringSchema, Updater};
+use proxmox_schema::{api, ApiType, Schema, StringSchema, Updater, UpdaterType};
 use proxmox_section_config::typed::ApiSectionDataEntry;
 use proxmox_section_config::{SectionConfig, SectionConfigPlugin};
 
@@ -66,6 +66,17 @@ impl RemoteType {
 serde_plain::derive_display_from_serialize!(RemoteType);
 serde_plain::derive_fromstr_from_deserialize!(RemoteType);
 
+#[api]
+#[derive(Clone, Debug, Deserialize, Serialize, UpdaterType, PartialEq)]
+#[serde(rename_all = "kebab-case")]
+/// A location using the geographic coordinate system.
+pub struct RemoteLocation {
+    /// The latitude of the remote location.
+    pub latitude: f64,
+    /// The longitude of the remote location.
+    pub longitude: f64,
+}
+
 #[api(
     properties: {
         "id": { schema: REMOTE_ID_SCHEMA },
@@ -81,6 +92,10 @@ serde_plain::derive_fromstr_from_deserialize!(RemoteType);
             type: String,
             optional: true,
         },
+        "location": {
+            type: String,
+            optional: true,
+        },
     },
 )]
 /// The information required to connect to a remote instance.
@@ -120,6 +135,11 @@ pub struct Remote {
         skip_serializing_if = "Option::is_none"
     )]
     pub web_url: Option<Uri>,
+
+    /// The remotes physical location
+    #[updater(serde(skip_serializing_if = "Option::is_none"))]
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub location: Option<PropertyString<RemoteLocation>>,
 }
 
 impl ApiSectionDataEntry for Remote {
diff --git a/server/src/api/pbs/mod.rs b/server/src/api/pbs/mod.rs
index 32e6bf84..50161488 100644
--- a/server/src/api/pbs/mod.rs
+++ b/server/src/api/pbs/mod.rs
@@ -275,6 +275,7 @@ pub async fn scan_remote_pbs(
         authid: authid.clone(),
         token,
         web_url: None,
+        location: None,
     };
 
     let _client = connect_or_login(&remote)
@@ -327,6 +328,7 @@ pub async fn list_realm_remote_pbs(
         authid: "root@pam".parse()?,
         token: String::new(),
         web_url: None,
+        location: None,
     };
 
     let client = connection::make_pbs_client(&remote)?;
diff --git a/server/src/api/pve/mod.rs b/server/src/api/pve/mod.rs
index 20892f38..96aaf80d 100644
--- a/server/src/api/pve/mod.rs
+++ b/server/src/api/pve/mod.rs
@@ -460,6 +460,7 @@ pub async fn scan_remote_pve(
         authid: authid.clone(),
         token,
         web_url: None,
+        location: None,
     };
 
     let client = connect_or_login(&remote)
@@ -551,6 +552,7 @@ pub async fn list_realm_remote_pve(
         authid: "root@pam".parse()?,
         token: String::new(),
         web_url: None,
+        location: None,
     };
 
     let client = connection::make_pve_client(&remote)?;
diff --git a/server/src/api/remotes/mod.rs b/server/src/api/remotes/mod.rs
index a91ec97d..69a4e3af 100644
--- a/server/src/api/remotes/mod.rs
+++ b/server/src/api/remotes/mod.rs
@@ -340,6 +340,8 @@ pub async fn add_remote(mut entry: Remote, create_token: Option<String>) -> Resu
 pub enum DeletableProperty {
     /// Delete the web-url property.
     WebUrl,
+    /// Delete the location property.
+    Location,
 }
 
 // FIXME: Support `OneOf` in schema so we can use a derived Updater for all product types?
@@ -390,6 +392,9 @@ pub fn update_remote(
                 DeletableProperty::WebUrl => {
                     entry.web_url = None;
                 }
+                DeletableProperty::Location => {
+                    entry.location = None;
+                }
             }
         }
     }
@@ -408,6 +413,10 @@ pub fn update_remote(
         entry.web_url = updater.web_url;
     }
 
+    if updater.location.is_some() {
+        entry.location = updater.location;
+    }
+
     pdm_config::remotes::save_config(remotes)?;
 
     Ok(())
diff --git a/ui/src/remotes/edit_remote.rs b/ui/src/remotes/edit_remote.rs
index 925d11ad..5db1b81f 100644
--- a/ui/src/remotes/edit_remote.rs
+++ b/ui/src/remotes/edit_remote.rs
@@ -7,10 +7,12 @@ use yew::virtual_dom::{VComp, VNode};
 
 use pwt::css::FlexFit;
 use pwt::prelude::*;
-use pwt::widget::form::{DisplayField, Field, FormContext, InputType};
+use pwt::widget::form::{DisplayField, Field, FormContext, InputType, Number};
 use pwt::widget::{Container, InputPanel};
 
-use proxmox_yew_comp::form::delete_empty_values;
+use proxmox_yew_comp::form::{
+    delete_empty_values, flatten_property_string, property_string_from_parts,
+};
 use proxmox_yew_comp::percent_encoding::percent_encode_component;
 use proxmox_yew_comp::{EditWindow, SchemaValidation};
 
@@ -21,6 +23,8 @@ use super::NodeUrlList;
 
 use pwt_macros::builder;
 
+use pdm_api_types::remotes::RemoteLocation;
+
 #[derive(PartialEq, Properties)]
 #[builder]
 pub struct EditRemote {
@@ -42,7 +46,13 @@ impl EditRemote {
 pub struct PdmEditRemote {}
 
 async fn load_remote(url: AttrValue) -> Result<ApiResponseData<Value>, Error> {
-    proxmox_yew_comp::http_get_full(&*url, None).await
+    let mut res = proxmox_yew_comp::http_get_full(&*url, None).await;
+
+    if let Ok(data) = res.as_mut() {
+        flatten_property_string::<RemoteLocation>(&mut data.data, "coordinates")?;
+    }
+
+    res
 }
 
 impl Component for PdmEditRemote {
@@ -76,9 +86,15 @@ impl Component for PdmEditRemote {
                 move |form_ctx: FormContext| {
                     let url = url.clone();
                     async move {
-                        let data = form_ctx.get_submit_data();
+                        let mut data = form_ctx.get_submit_data();
+
+                        property_string_from_parts::<RemoteLocation>(
+                            &mut data,
+                            "coordinates",
+                            true,
+                        )?;
 
-                        let data = delete_empty_values(&data, &["web-url"], true);
+                        let data = delete_empty_values(&data, &["web-url", "coordinates"], true);
 
                         proxmox_yew_comp::http_put(&url, Some(data)).await
                     }
@@ -120,6 +136,14 @@ fn edit_remote_input_panel(_form_ctx: &FormContext, remote_id: &str) -> Html {
                 .name("web-url")
                 .placeholder(tr!("Use first endpoint.")),
         )
+        .with_field(
+            tr!("Location Latitude"),
+            Number::new().name("_lat").min(-90.0).max(90.0),
+        )
+        .with_field(
+            tr!("Location Longitude"),
+            Number::new().name("_long").min(-180.0).max(180.0),
+        )
         .with_custom_child(
             Container::new()
                 .key("nodes-title")
-- 
2.47.3





  parent reply	other threads:[~2026-05-04 12:45 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-04 12:44 [PATCH datacenter-manager/yew-widget-toolkit/yew-widget-toolkit-assets 0/8] add a new map widget for custom views Dominik Csapak
2026-05-04 12:44 ` [PATCH yew-widget-toolkit 1/3] js-helper: add client-to-svg-coordinate conversion helper Dominik Csapak
2026-05-04 12:44 ` [PATCH yew-widget-toolkit 2/3] widget: charts: add interactive Map with zoom/pan and clustering Dominik Csapak
2026-05-04 12:44 ` [PATCH yew-widget-toolkit 3/3] widget: charts: add WorldMap with GeoJSON rendering Dominik Csapak
2026-05-04 12:44 ` [PATCH yew-widget-toolkit-assets 1/1] charts: add necessary classes for Map Dominik Csapak
2026-05-04 12:44 ` Dominik Csapak [this message]
2026-05-04 12:44 ` [PATCH datacenter-manager 2/4] lib/api: add new 'remote-list' info to the resource status Dominik Csapak
2026-05-04 12:44 ` [PATCH datacenter-manager 4/4] ui: views: add map component Dominik Csapak
2026-05-04 12:49 ` [PATCH datacenter-manager/yew-widget-toolkit/yew-widget-toolkit-assets 0/8] add a new map widget for custom views Dominik Csapak
2026-05-05  8:28   ` Thomas Lamprecht
2026-05-05  8:39     ` Dominik Csapak
2026-05-05  8:51       ` Thomas Lamprecht
2026-05-05  7:38 ` superseded: " Dominik Csapak

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=20260504124515.2956574-6-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.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal