* [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login
@ 2025-12-01 10:39 Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH yew-comp 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
` (10 more replies)
0 siblings, 11 replies; 12+ messages in thread
From: Dominik Csapak @ 2025-12-01 10:39 UTC (permalink / raw)
To: pdm-devel
This adds subscription checks + popup for
* login
* 'refresh all' for remote update panel
* 'refresh' for single node update panels
special consideration should be given to the patch 4/8 in
proxmox-datacenter-manager, since that exposes a bit more information
for users that don't have access everywhere.
proxmox-yew-comp:
Dominik Csapak (2):
subscription: refactor api subscription check for showing the alert
apt package manager: add optional subscription check on 'Refresh'
button
src/apt_package_manager.rs | 63 ++++++++++++++++++++++++++++++++++++--
src/apt_repositories.rs | 8 ++---
src/subscription_alert.rs | 13 ++++++++
3 files changed, 75 insertions(+), 9 deletions(-)
proxmox-datacenter-manager:
Dominik Csapak (8):
server: api: subscription: fix permission check
server: api: subscription: include basic info about remotes without
permissions
server: api: subscription: add remote type to subscription info
ui: login: enable subscription check
server: api: pve/pbs: node: add subscription api call
ui: pve/pbs: updates: add subscription_url
ui: refactor check_subscription into lib
ui: remote updates: add subscription check on 'Refresh all'
lib/pdm-api-types/src/subscription.rs | 5 +++
server/src/api/pbs/node.rs | 39 +++++++++++++++++++++-
server/src/api/pve/node.rs | 27 +++++++++++++++
server/src/api/resources.rs | 15 ++++++---
ui/src/lib.rs | 40 +++++++++++++++++++++-
ui/src/main.rs | 40 ++++++++--------------
ui/src/pbs/node/mod.rs | 2 ++
ui/src/pve/node/mod.rs | 2 ++
ui/src/remotes/updates.rs | 48 ++++++++++++++++++++++++---
9 files changed, 180 insertions(+), 38 deletions(-)
Summary over all repositories:
12 files changed, 255 insertions(+), 47 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] 12+ messages in thread
* [pdm-devel] [PATCH yew-comp 1/2] subscription: refactor api subscription check for showing the alert
2025-12-01 10:39 [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
@ 2025-12-01 10:39 ` Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH yew-comp 2/2] apt package manager: add optional subscription check on 'Refresh' button Dominik Csapak
` (9 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Dominik Csapak @ 2025-12-01 10:39 UTC (permalink / raw)
To: pdm-devel
so we can reuse that
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
src/apt_repositories.rs | 8 ++------
src/subscription_alert.rs | 13 +++++++++++++
2 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/src/apt_repositories.rs b/src/apt_repositories.rs
index ae582a6..83463c9 100644
--- a/src/apt_repositories.rs
+++ b/src/apt_repositories.rs
@@ -19,6 +19,7 @@ use pwt::widget::data_table::{
};
use pwt::widget::{Button, Column, Container, Fa, Row, Toolbar, Tooltip};
+use crate::subscription_alert::subscription_is_active;
use crate::{
EditWindow, ExistingProduct, LoadableComponent, LoadableComponentContext,
LoadableComponentMaster, ProjectInfo, SubscriptionAlert,
@@ -694,12 +695,7 @@ fn standard_repo_info(
impl ProxmoxAptRepositories {
fn active_subscription(&self) -> bool {
- match &self.subscription_status {
- Some(Ok(data)) => {
- data["status"].as_str().map(|s| s.to_lowercase()).as_deref() == Some("active")
- }
- _ => false,
- }
+ subscription_is_active(&self.subscription_status)
}
fn create_show_subscription_dialog(
diff --git a/src/subscription_alert.rs b/src/subscription_alert.rs
index 2dca3c4..7734123 100644
--- a/src/subscription_alert.rs
+++ b/src/subscription_alert.rs
@@ -1,5 +1,8 @@
use std::rc::Rc;
+use anyhow::Error;
+use serde_json::Value;
+
use yew::html::{IntoEventCallback, IntoPropValue};
use yew::virtual_dom::{VComp, VNode};
@@ -63,3 +66,13 @@ impl From<SubscriptionAlert> for VNode {
VNode::from(comp)
}
}
+
+/// Check if the result of the subscription check returned an active subscription
+pub fn subscription_is_active(result: &Option<Result<Value, Error>>) -> bool {
+ match result {
+ Some(Ok(data)) => {
+ data["status"].as_str().map(|s| s.to_lowercase()).as_deref() == Some("active")
+ }
+ _ => false,
+ }
+}
--
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] 12+ messages in thread
* [pdm-devel] [PATCH yew-comp 2/2] apt package manager: add optional subscription check on 'Refresh' button
2025-12-01 10:39 [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH yew-comp 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
@ 2025-12-01 10:39 ` Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 1/8] server: api: subscription: fix permission check Dominik Csapak
` (8 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Dominik Csapak @ 2025-12-01 10:39 UTC (permalink / raw)
To: pdm-devel
but only if the 'subscription_url' is set on the component.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
src/apt_package_manager.rs | 63 ++++++++++++++++++++++++++++++++++++--
1 file changed, 60 insertions(+), 3 deletions(-)
diff --git a/src/apt_package_manager.rs b/src/apt_package_manager.rs
index d01f275..78e82a0 100644
--- a/src/apt_package_manager.rs
+++ b/src/apt_package_manager.rs
@@ -5,6 +5,7 @@ use std::pin::Pin;
use std::rc::Rc;
use anyhow::Error;
+use serde_json::Value;
use yew::html::IntoEventCallback;
use yew::html::IntoPropValue;
@@ -17,8 +18,11 @@ use pwt::widget::data_table::{
DataTable, DataTableCellRenderArgs, DataTableColumn, DataTableHeader, DataTableHeaderGroup,
};
use pwt::widget::{Button, Container, Toolbar, Tooltip};
+use pwt::AsyncPool;
use crate::percent_encoding::percent_encode_component;
+use crate::subscription_alert::subscription_is_active;
+use crate::SubscriptionAlert;
use crate::{
DataViewWindow, LoadableComponent, LoadableComponentContext, LoadableComponentMaster, XTermJs,
};
@@ -56,6 +60,11 @@ pub struct AptPackageManager {
#[prop_or_default]
#[builder_cb(IntoEventCallback, into_event_callback, ())]
pub on_upgrade: Option<Callback<()>>,
+
+ #[prop_or_default]
+ #[builder(IntoPropValue, into_prop_value)]
+ /// The base url for the subscription check
+ pub subscription_url: Option<AttrValue>,
}
impl Default for AptPackageManager {
@@ -142,12 +151,14 @@ fn update_list_to_tree(updates: &[APTUpdateInfo]) -> SlabTree<TreeEntry> {
#[derive(Clone, PartialEq)]
pub enum ViewState {
ShowChangelog(String),
+ ShowSubscriptionPopup,
}
pub struct ProxmoxAptPackageManager {
tree_store: TreeStore<TreeEntry>,
selection: Selection,
columns: Rc<Vec<DataTableHeader<TreeEntry>>>,
+ async_pool: AsyncPool,
}
impl LoadableComponent for ProxmoxAptPackageManager {
@@ -164,9 +175,33 @@ impl LoadableComponent for ProxmoxAptPackageManager {
tree_store,
selection,
columns,
+ async_pool: AsyncPool::new(),
}
}
+ fn update(&mut self, ctx: &LoadableComponentContext<Self>, _msg: Self::Message) -> bool {
+ let link = ctx.link().clone();
+ let props = ctx.props();
+ let url = props
+ .clone()
+ .subscription_url
+ .unwrap_or("/nodes/localhost/subscription".into());
+ let task_base_url = props.task_base_url.clone();
+ let command = format!("{}/update", props.base_url);
+ self.async_pool.spawn(async move {
+ let data = crate::http_get::<Value>(url.as_str(), None).await;
+ let is_active = subscription_is_active(&Some(data));
+
+ if is_active {
+ link.task_base_url(task_base_url);
+ link.start_task(&command, None, false);
+ } else {
+ link.change_view(Some(ViewState::ShowSubscriptionPopup));
+ }
+ });
+ true
+ }
+
fn load(
&self,
ctx: &LoadableComponentContext<Self>,
@@ -211,13 +246,20 @@ impl LoadableComponent for ProxmoxAptPackageManager {
.class("pwt-w-100")
.class("pwt-overflow-hidden")
.class("pwt-border-bottom")
- .with_child(Button::new(tr!("Refresh")).onclick({
+ .with_child(Button::new(tr!("Refresh")).on_activate({
let link = ctx.link();
-
+ let sub_check = props.subscription_url.is_some();
link.task_base_url(props.task_base_url.clone());
let command = format!("{}/update", props.base_url);
- move |_| link.start_task(&command, None, false)
+
+ move |_| {
+ if sub_check {
+ link.send_message(());
+ } else {
+ link.start_task(&command, None, false);
+ }
+ }
}))
.with_child(
Button::new(tr!("Upgrade"))
@@ -263,6 +305,21 @@ impl LoadableComponent for ProxmoxAptPackageManager {
ViewState::ShowChangelog(package) => {
Some(self.create_show_changelog_dialog(ctx, package))
}
+ ViewState::ShowSubscriptionPopup => {
+ let link = ctx.link().clone();
+ let props = ctx.props();
+ let task_base_url = props.task_base_url.clone();
+ let command = format!("{}/update", props.base_url);
+ Some(
+ SubscriptionAlert::new("notfound")
+ .on_close(move |_| {
+ link.change_view(None);
+ link.task_base_url(task_base_url.clone());
+ link.start_task(&command, None, false);
+ })
+ .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] 12+ messages in thread
* [pdm-devel] [PATCH datacenter-manager 1/8] server: api: subscription: fix permission check
2025-12-01 10:39 [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH yew-comp 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH yew-comp 2/2] apt package manager: add optional subscription check on 'Refresh' button Dominik Csapak
@ 2025-12-01 10:39 ` Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 2/8] server: api: subscription: include basic info about remotes without permissions Dominik Csapak
` (7 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Dominik Csapak @ 2025-12-01 10:39 UTC (permalink / raw)
To: pdm-devel
we have here a 'check_priv' that should return if the permission check
was successful. So instead of wrongly check for 'is_err', rather check
for 'is_ok'.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
server/src/api/resources.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/server/src/api/resources.rs b/server/src/api/resources.rs
index 55056e1c..22871362 100644
--- a/server/src/api/resources.rs
+++ b/server/src/api/resources.rs
@@ -616,7 +616,7 @@ pub async fn get_subscription_status(
PRIV_RESOURCE_AUDIT,
false,
)
- .is_err()
+ .is_ok()
};
for (remote_name, remote) in remotes_config {
--
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] 12+ messages in thread
* [pdm-devel] [PATCH datacenter-manager 2/8] server: api: subscription: include basic info about remotes without permissions
2025-12-01 10:39 [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
` (2 preceding siblings ...)
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 1/8] server: api: subscription: fix permission check Dominik Csapak
@ 2025-12-01 10:39 ` Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 3/8] server: api: subscription: add remote type to subscription info Dominik Csapak
` (6 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Dominik Csapak @ 2025-12-01 10:39 UTC (permalink / raw)
To: pdm-devel
to enable a global permission check that reaches over all remotes,
we have to return (very basic) info about remotes even when the user
don't have permissions for these remotes. In that case, only return the
subscription state, but not the remote name or node details.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
alternatively, we could try to return a different structure with just,
counts, but this would achieve the same effect, but we'd need to handle
two different api calls/return values, this way it's always the same,
and the remote names aren't interesting to us for the checks anyway
server/src/api/resources.rs | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/server/src/api/resources.rs b/server/src/api/resources.rs
index 22871362..6fd96b64 100644
--- a/server/src/api/resources.rs
+++ b/server/src/api/resources.rs
@@ -608,7 +608,7 @@ pub async fn get_subscription_status(
let view = views::get_optional_view(view.as_deref())?;
- let check_priv = |remote_name: &str| -> bool {
+ let check_priv = move |remote_name: &str| -> bool {
user_info
.check_privs(
&auth_id,
@@ -624,11 +624,10 @@ pub async fn get_subscription_status(
if view.can_skip_remote(&remote_name) {
continue;
}
- } else if !allow_all && !check_priv(&remote_name) {
- continue;
}
let view = view.clone();
+ let check_priv = check_priv.clone();
let future = async move {
let (node_status, error) =
@@ -664,6 +663,13 @@ pub async fn get_subscription_status(
RemoteSubscriptionState::Unknown
};
+ let (remote_name, verbose) = if !allow_all && !check_priv(&remote_name) {
+ // prevent info leak
+ ("".to_string(), false)
+ } else {
+ (remote_name, verbose)
+ };
+
Some(RemoteSubscriptions {
remote: remote_name,
error,
--
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] 12+ messages in thread
* [pdm-devel] [PATCH datacenter-manager 3/8] server: api: subscription: add remote type to subscription info
2025-12-01 10:39 [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
` (3 preceding siblings ...)
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 2/8] server: api: subscription: include basic info about remotes without permissions Dominik Csapak
@ 2025-12-01 10:39 ` Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 4/8] ui: login: enable subscription check Dominik Csapak
` (5 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Dominik Csapak @ 2025-12-01 10:39 UTC (permalink / raw)
To: pdm-devel
so we can differentiate between pbs and pve for the subscription check.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
lib/pdm-api-types/src/subscription.rs | 5 +++++
server/src/api/resources.rs | 1 +
2 files changed, 6 insertions(+)
diff --git a/lib/pdm-api-types/src/subscription.rs b/lib/pdm-api-types/src/subscription.rs
index 35910bc7..285aba56 100644
--- a/lib/pdm-api-types/src/subscription.rs
+++ b/lib/pdm-api-types/src/subscription.rs
@@ -6,6 +6,8 @@ use serde::{Deserialize, Serialize};
use proxmox_schema::api;
use proxmox_subscription::SubscriptionStatus;
+use crate::remotes::RemoteType;
+
#[api]
// order is important here, since we use that for determining if a node has a valid subscription
#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
@@ -129,6 +131,9 @@ pub struct RemoteSubscriptions {
/// Remote name
pub remote: String,
+ /// Remote type
+ pub remote_type: RemoteType,
+
/// Any error that occurred when querying remote resources
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
diff --git a/server/src/api/resources.rs b/server/src/api/resources.rs
index 6fd96b64..ec4fdc4a 100644
--- a/server/src/api/resources.rs
+++ b/server/src/api/resources.rs
@@ -672,6 +672,7 @@ pub async fn get_subscription_status(
Some(RemoteSubscriptions {
remote: remote_name,
+ remote_type: remote.ty,
error,
state,
node_status: if verbose { node_status } else { None },
--
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] 12+ messages in thread
* [pdm-devel] [PATCH datacenter-manager 4/8] ui: login: enable subscription check
2025-12-01 10:39 [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
` (4 preceding siblings ...)
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 3/8] server: api: subscription: add remote type to subscription info Dominik Csapak
@ 2025-12-01 10:39 ` Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 5/8] server: api: pve/pbs: node: add subscription api call Dominik Csapak
` (4 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Dominik Csapak @ 2025-12-01 10:39 UTC (permalink / raw)
To: pdm-devel
show popup when:
* amount of remotes <= 5 => when any remote does not have a valid subscription
* amount of remotes >5 => when more than 1 pve or pbs remotes don't have
a subscription
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
ui/src/main.rs | 39 +++++++++++++++++++++++++++++++--------
1 file changed, 31 insertions(+), 8 deletions(-)
diff --git a/ui/src/main.rs b/ui/src/main.rs
index 454a2927..ebf427bf 100644
--- a/ui/src/main.rs
+++ b/ui/src/main.rs
@@ -21,6 +21,7 @@ use proxmox_yew_comp::{
};
//use pbs::MainMenu;
+use pdm_api_types::remotes::RemoteType;
use pdm_api_types::subscription::{RemoteSubscriptionState, RemoteSubscriptions};
use pdm_api_types::views::ViewConfig;
use pdm_ui::{
@@ -67,9 +68,34 @@ async fn check_subscription() -> Msg {
let data: Result<Vec<RemoteSubscriptions>, _> = http_get("/resources/subscription", None).await;
let show_alert = match data {
- Ok(list) => list
- .into_iter()
- .any(|info| info.state == RemoteSubscriptionState::None),
+ Ok(list) => {
+ let mut pve_none = 0;
+ let mut pve_total = 0;
+ let mut pbs_none = 0;
+ let mut pbs_total = 0;
+
+ for info in list {
+ match info.remote_type {
+ RemoteType::Pve => {
+ pve_total += 1;
+ if info.state == RemoteSubscriptionState::None {
+ pve_none += 1
+ }
+ }
+ RemoteType::Pbs => {
+ pbs_total += 1;
+ if info.state == RemoteSubscriptionState::None {
+ pbs_none += 1
+ }
+ }
+ }
+ }
+ if pve_total + pbs_total <= 5 {
+ pve_none + pbs_none > 0
+ } else {
+ pve_none > 1 || pbs_none > 1
+ }
+ }
Err(_) => false,
};
@@ -246,11 +272,8 @@ impl Component for DatacenterManagerApp {
true
}
Msg::ShowSubscriptionAlert => {
- // Disable for alpha and rework for a beta or stable version to avoid friction if a
- // few unsubscribed test instances are present in another subscribed (big) setup.
- // self.show_subscription_alert = Some(true);
- self.subscription_confirmed = true;
- self.show_subscription_alert = Some(false);
+ self.subscription_confirmed = false;
+ self.show_subscription_alert = Some(true);
true
}
Msg::Logout => {
--
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] 12+ messages in thread
* [pdm-devel] [PATCH datacenter-manager 5/8] server: api: pve/pbs: node: add subscription api call
2025-12-01 10:39 [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
` (5 preceding siblings ...)
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 4/8] ui: login: enable subscription check Dominik Csapak
@ 2025-12-01 10:39 ` Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 6/8] ui: pve/pbs: updates: add subscription_url Dominik Csapak
` (3 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Dominik Csapak @ 2025-12-01 10:39 UTC (permalink / raw)
To: pdm-devel
returns the subscription information per node
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
server/src/api/pbs/node.rs | 39 +++++++++++++++++++++++++++++++++++++-
server/src/api/pve/node.rs | 27 ++++++++++++++++++++++++++
2 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/server/src/api/pbs/node.rs b/server/src/api/pbs/node.rs
index cf8cbea5..aafefc2a 100644
--- a/server/src/api/pbs/node.rs
+++ b/server/src/api/pbs/node.rs
@@ -1,6 +1,17 @@
-use proxmox_router::{list_subdirs_api_method, Router, SubdirMap};
+use anyhow::Error;
+
+use proxmox_router::{list_subdirs_api_method, Permission, Router, SubdirMap};
+use proxmox_schema::api;
use proxmox_sortable_macro::sortable;
+use pdm_api_types::remotes::REMOTE_ID_SCHEMA;
+use pdm_api_types::PRIV_RESOURCE_AUDIT;
+
+use pbs_api_types::NODE_SCHEMA;
+
+use crate::connection;
+use crate::pbs_client::get_remote;
+
pub const ROUTER: Router = Router::new()
.get(&list_subdirs_api_method!(SUBDIRS))
.subdirs(SUBDIRS);
@@ -8,6 +19,10 @@ pub const ROUTER: Router = Router::new()
#[sortable]
const SUBDIRS: SubdirMap = &sorted!([
("apt", &crate::api::remote_updates::APT_ROUTER),
+ (
+ "subscription",
+ &Router::new().get(&API_METHOD_GET_SUBSCRIPTION)
+ ),
(
"termproxy",
&Router::new().post(&crate::api::remote_shell::API_METHOD_SHELL_TICKET)
@@ -17,3 +32,25 @@ const SUBDIRS: SubdirMap = &sorted!([
&Router::new().upgrade(&crate::api::remote_shell::API_METHOD_SHELL_WEBSOCKET)
),
]);
+
+#[api(
+ input: {
+ properties: {
+ remote: { schema: REMOTE_ID_SCHEMA },
+ node: { schema: NODE_SCHEMA }, // not used, always localhost
+ },
+ },
+ access: {
+ permission: &Permission::Privilege(&["resource", "{remote}"], PRIV_RESOURCE_AUDIT, false),
+ description: "The user needs to have at least the `Resource.Audit` privilege on `/resource/{remote}`."
+ },
+ returns: { type: proxmox_subscription::SubscriptionInfo }
+)]
+/// Get subscription for the PBS remote
+async fn get_subscription(remote: String) -> Result<proxmox_subscription::SubscriptionInfo, Error> {
+ let (remotes, _) = pdm_config::remotes::config()?;
+ let remote = get_remote(&remotes, &remote)?;
+ Ok(connection::make_pbs_client(remote)?
+ .get_subscription()
+ .await?)
+}
diff --git a/server/src/api/pve/node.rs b/server/src/api/pve/node.rs
index d8690f63..376234c7 100644
--- a/server/src/api/pve/node.rs
+++ b/server/src/api/pve/node.rs
@@ -29,6 +29,10 @@ const SUBDIRS: SubdirMap = &sorted!([
),
("storage", &STORAGE_ROUTER),
("status", &Router::new().get(&API_METHOD_GET_STATUS)),
+ (
+ "subscription",
+ &Router::new().get(&API_METHOD_GET_SUBSCRIPTION)
+ ),
]);
const STORAGE_ROUTER: Router = Router::new()
@@ -153,3 +157,26 @@ 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),
+ },
+ returns: { type: pve_api_types::NodeStatus },
+)]
+/// Get subscription for the node
+async fn get_subscription(
+ remote: String,
+ node: String,
+) -> Result<pve_api_types::NodeSubscriptionInfo, Error> {
+ let (remotes, _) = pdm_config::remotes::config()?;
+ let client = super::connect_to_remote(&remotes, &remote)?;
+ let result = client.get_subscription(&node).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] 12+ messages in thread
* [pdm-devel] [PATCH datacenter-manager 6/8] ui: pve/pbs: updates: add subscription_url
2025-12-01 10:39 [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
` (6 preceding siblings ...)
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 5/8] server: api: pve/pbs: node: add subscription api call Dominik Csapak
@ 2025-12-01 10:39 ` Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 7/8] ui: refactor check_subscription into lib Dominik Csapak
` (2 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Dominik Csapak @ 2025-12-01 10:39 UTC (permalink / raw)
To: pdm-devel
so the 'Refresh' button does a subscription check.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
ui/src/pbs/node/mod.rs | 2 ++
ui/src/pve/node/mod.rs | 2 ++
2 files changed, 4 insertions(+)
diff --git a/ui/src/pbs/node/mod.rs b/ui/src/pbs/node/mod.rs
index 2033bb14..19ddce72 100644
--- a/ui/src/pbs/node/mod.rs
+++ b/ui/src/pbs/node/mod.rs
@@ -89,10 +89,12 @@ impl yew::Component for PbsNodePanelComp {
move |_| {
let base_url = format!("/pbs/remotes/{remote}/nodes/localhost/apt");
let task_base_url = format!("/pbs/remotes/{remote}/tasks");
+ let sub_url = format!("/pbs/remotes/{remote}/nodes/localhost/subscription");
AptPackageManager::new()
.base_url(base_url)
.task_base_url(task_base_url)
+ .subscription_url(sub_url)
.enable_upgrade(true)
.on_upgrade({
let remote = remote.clone();
diff --git a/ui/src/pve/node/mod.rs b/ui/src/pve/node/mod.rs
index 1fcd92eb..332c26a8 100644
--- a/ui/src/pve/node/mod.rs
+++ b/ui/src/pve/node/mod.rs
@@ -86,10 +86,12 @@ impl yew::Component for PveNodePanelComp {
move |_| {
let base_url = format!("/pve/remotes/{remote}/nodes/{node}/apt");
let task_base_url = format!("/pve/remotes/{remote}/tasks");
+ let sub_url = format!("/pve/remotes/{remote}/nodes/{node}/subscription");
AptPackageManager::new()
.base_url(base_url)
.task_base_url(task_base_url)
+ .subscription_url(sub_url)
.enable_upgrade(true)
.on_upgrade({
let remote = remote.clone();
--
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] 12+ messages in thread
* [pdm-devel] [PATCH datacenter-manager 7/8] ui: refactor check_subscription into lib
2025-12-01 10:39 [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
` (7 preceding siblings ...)
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 6/8] ui: pve/pbs: updates: add subscription_url Dominik Csapak
@ 2025-12-01 10:39 ` Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 8/8] ui: remote updates: add subscription check on 'Refresh all' Dominik Csapak
2025-12-01 13:54 ` [pdm-devel] superseded: [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
10 siblings, 0 replies; 12+ messages in thread
From: Dominik Csapak @ 2025-12-01 10:39 UTC (permalink / raw)
To: pdm-devel
so we can reuse the global subscription check logic elsewhere
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
ui/src/lib.rs | 40 +++++++++++++++++++++++++++++++++-
ui/src/main.rs | 59 ++++++++++----------------------------------------
2 files changed, 50 insertions(+), 49 deletions(-)
diff --git a/ui/src/lib.rs b/ui/src/lib.rs
index 27a51084..e0959029 100644
--- a/ui/src/lib.rs
+++ b/ui/src/lib.rs
@@ -1,7 +1,7 @@
use js_sys::{Array, JsString, Object};
use pdm_api_types::remotes::RemoteType;
use pdm_api_types::resource::{PveLxcResource, PveNetworkResource, PveQemuResource};
-use pdm_client::types::Resource;
+use pdm_client::types::{RemoteSubscriptionState, RemoteSubscriptions, Resource};
use serde::{Deserialize, Serialize};
mod administration;
@@ -234,3 +234,41 @@ pub(crate) fn locale_compare(first: String, second: &str, numeric: bool) -> std:
.locale_compare(second, &Array::new(), &options)
.cmp(&0)
}
+
+/// Returns true if the global subscription checks succeeded
+pub async fn check_subscription() -> bool {
+ let data: Result<Vec<RemoteSubscriptions>, _> =
+ proxmox_yew_comp::http_get("/resources/subscription", None).await;
+
+ match data {
+ Ok(list) => {
+ let mut pve_none = 0;
+ let mut pve_total = 0;
+ let mut pbs_none = 0;
+ let mut pbs_total = 0;
+
+ for info in list {
+ match info.remote_type {
+ RemoteType::Pve => {
+ pve_total += 1;
+ if info.state == RemoteSubscriptionState::None {
+ pve_none += 1
+ }
+ }
+ RemoteType::Pbs => {
+ pbs_total += 1;
+ if info.state == RemoteSubscriptionState::None {
+ pbs_none += 1
+ }
+ }
+ }
+ }
+ if pve_total + pbs_total <= 5 {
+ pve_none + pbs_none > 0
+ } else {
+ pve_none > 1 || pbs_none > 1
+ }
+ }
+ Err(_) => false,
+ }
+}
diff --git a/ui/src/main.rs b/ui/src/main.rs
index ebf427bf..7cb3660c 100644
--- a/ui/src/main.rs
+++ b/ui/src/main.rs
@@ -21,12 +21,10 @@ use proxmox_yew_comp::{
};
//use pbs::MainMenu;
-use pdm_api_types::remotes::RemoteType;
-use pdm_api_types::subscription::{RemoteSubscriptionState, RemoteSubscriptions};
use pdm_api_types::views::ViewConfig;
use pdm_ui::{
- register_pve_tasks, MainMenu, RemoteList, RemoteListCacheEntry, SearchProvider, TopNavBar,
- ViewListContext,
+ check_subscription, register_pve_tasks, MainMenu, RemoteList, RemoteListCacheEntry,
+ SearchProvider, TopNavBar, ViewListContext,
};
type MsgRemoteList = Result<RemoteList, Error>;
@@ -64,48 +62,6 @@ struct DatacenterManagerApp {
async_pool: AsyncPool,
}
-async fn check_subscription() -> Msg {
- let data: Result<Vec<RemoteSubscriptions>, _> = http_get("/resources/subscription", None).await;
-
- let show_alert = match data {
- Ok(list) => {
- let mut pve_none = 0;
- let mut pve_total = 0;
- let mut pbs_none = 0;
- let mut pbs_total = 0;
-
- for info in list {
- match info.remote_type {
- RemoteType::Pve => {
- pve_total += 1;
- if info.state == RemoteSubscriptionState::None {
- pve_none += 1
- }
- }
- RemoteType::Pbs => {
- pbs_total += 1;
- if info.state == RemoteSubscriptionState::None {
- pbs_none += 1
- }
- }
- }
- }
- if pve_total + pbs_total <= 5 {
- pve_none + pbs_none > 0
- } else {
- pve_none > 1 || pbs_none > 1
- }
- }
- Err(_) => false,
- };
-
- if show_alert {
- Msg::ShowSubscriptionAlert
- } else {
- Msg::ConfirmSubscription
- }
-}
-
/*
async fn get_fingerprint() -> Option<Msg> {
http_get("/nodes/localhost/status", None)
@@ -122,8 +78,15 @@ impl DatacenterManagerApp {
if self.subscription_confirmed {
ctx.link().send_message(Msg::ConfirmSubscription);
} else {
- self.async_pool
- .send_future(ctx.link().clone(), check_subscription());
+ self.async_pool.send_future(ctx.link().clone(), async move {
+ let show_alert = check_subscription().await;
+
+ if show_alert {
+ Msg::ShowSubscriptionAlert
+ } else {
+ Msg::ConfirmSubscription
+ }
+ });
}
} else {
ctx.link().send_message(Msg::ConfirmSubscription);
--
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] 12+ messages in thread
* [pdm-devel] [PATCH datacenter-manager 8/8] ui: remote updates: add subscription check on 'Refresh all'
2025-12-01 10:39 [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
` (8 preceding siblings ...)
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 7/8] ui: refactor check_subscription into lib Dominik Csapak
@ 2025-12-01 10:39 ` Dominik Csapak
2025-12-01 13:54 ` [pdm-devel] superseded: [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
10 siblings, 0 replies; 12+ messages in thread
From: Dominik Csapak @ 2025-12-01 10:39 UTC (permalink / raw)
To: pdm-devel
in pve/pbs we do a check on refreshing too, so it's only fitting to do
one here as well.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
ui/src/remotes/updates.rs | 48 +++++++++++++++++++++++++++++++++++----
1 file changed, 43 insertions(+), 5 deletions(-)
diff --git a/ui/src/remotes/updates.rs b/ui/src/remotes/updates.rs
index 020a2c4b..5ac4ce75 100644
--- a/ui/src/remotes/updates.rs
+++ b/ui/src/remotes/updates.rs
@@ -19,7 +19,7 @@ use proxmox_deb_version;
use proxmox_yew_comp::{
AptPackageManager, AptRepositories, ExistingProduct, LoadableComponent,
- LoadableComponentContext, LoadableComponentMaster,
+ LoadableComponentContext, LoadableComponentMaster, SubscriptionAlert,
};
use pwt::props::{CssBorderBuilder, CssPaddingBuilder, WidgetStyleBuilder};
use pwt::widget::{Button, Container, Panel, Tooltip};
@@ -35,7 +35,7 @@ use pwt::{
},
};
-use crate::{get_deep_url, get_deep_url_low_level, pdm_client};
+use crate::{check_subscription, get_deep_url, get_deep_url_low_level, pdm_client};
#[derive(PartialEq, Properties)]
pub struct UpdateTree {}
@@ -120,6 +120,7 @@ enum RemoteUpdateTreeMsg {
LoadFinished(UpdateSummary),
KeySelected(Option<Key>),
RefreshAll,
+ CheckSubscription,
}
struct UpdateTreeComponent {
@@ -303,10 +304,15 @@ fn build_store_from_response(update_summary: UpdateSummary) -> SlabTree<UpdateTr
tree
}
+#[derive(PartialEq)]
+enum ViewState {
+ ShowSubscriptionAlert,
+}
+
impl LoadableComponent for UpdateTreeComponent {
type Properties = UpdateTree;
type Message = RemoteUpdateTreeMsg;
- type ViewState = ();
+ type ViewState = ViewState;
fn create(ctx: &LoadableComponentContext<Self>) -> Self {
let link = ctx.link();
@@ -343,6 +349,24 @@ impl LoadableComponent for UpdateTreeComponent {
})
}
+ fn dialog_view(
+ &self,
+ ctx: &LoadableComponentContext<Self>,
+ view_state: &Self::ViewState,
+ ) -> Option<Html> {
+ let link = ctx.link().clone();
+ match view_state {
+ ViewState::ShowSubscriptionAlert => Some(
+ SubscriptionAlert::new("notfound")
+ .on_close(move |_| {
+ link.change_view(None);
+ link.send_message(RemoteUpdateTreeMsg::RefreshAll);
+ })
+ .into(),
+ ),
+ }
+ }
+
fn update(&mut self, ctx: &LoadableComponentContext<Self>, msg: Self::Message) -> bool {
match msg {
Self::Message::LoadFinished(updates) => {
@@ -363,6 +387,18 @@ impl LoadableComponent for UpdateTreeComponent {
return true;
}
}
+ Self::Message::CheckSubscription => {
+ let link = ctx.link();
+
+ link.clone().spawn(async move {
+ let show_alert = check_subscription().await;
+ if show_alert {
+ link.change_view(Some(ViewState::ShowSubscriptionAlert));
+ } else {
+ link.send_message(RemoteUpdateTreeMsg::RefreshAll);
+ }
+ });
+ }
Self::Message::RefreshAll => {
let link = ctx.link();
@@ -407,7 +443,7 @@ impl UpdateTreeComponent {
let refresh_all_button = Button::new(tr!("Refresh all")).on_activate({
let link = ctx.link().clone();
move |_| {
- link.send_message(RemoteUpdateTreeMsg::RefreshAll);
+ link.send_message(RemoteUpdateTreeMsg::CheckSubscription);
}
});
@@ -667,7 +703,9 @@ fn render_version_column(tree_entry: &UpdateTreeEntry, expanded: bool) -> Html {
let (icon, extra) = match remote_entry.mixed_versions {
MixedVersions::None => ("", "".to_string()),
MixedVersions::DifferentMajor => ("times-circle", tr!("major difference")),
- MixedVersions::DifferentMinor => ("exclamation-triangle", tr!("substantial difference")),
+ MixedVersions::DifferentMinor => {
+ ("exclamation-triangle", tr!("substantial difference"))
+ }
MixedVersions::DifferentPatch => ("info-circle", tr!("small difference")),
};
let version_string = remote_entry.product_version.clone().unwrap_or_default();
--
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] 12+ messages in thread
* [pdm-devel] superseded: [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login
2025-12-01 10:39 [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
` (9 preceding siblings ...)
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 8/8] ui: remote updates: add subscription check on 'Refresh all' Dominik Csapak
@ 2025-12-01 13:54 ` Dominik Csapak
10 siblings, 0 replies; 12+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:54 UTC (permalink / raw)
To: pdm-devel
superseded by v2:
https://lore.proxmox.com/pdm-devel/20251201135318.2983539-1-d.csapak@proxmox.com/T/#t
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2025-12-01 13:54 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-01 10:39 [pdm-devel] [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH yew-comp 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH yew-comp 2/2] apt package manager: add optional subscription check on 'Refresh' button Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 1/8] server: api: subscription: fix permission check Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 2/8] server: api: subscription: include basic info about remotes without permissions Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 3/8] server: api: subscription: add remote type to subscription info Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 4/8] ui: login: enable subscription check Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 5/8] server: api: pve/pbs: node: add subscription api call Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 6/8] ui: pve/pbs: updates: add subscription_url Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 7/8] ui: refactor check_subscription into lib Dominik Csapak
2025-12-01 10:39 ` [pdm-devel] [PATCH datacenter-manager 8/8] ui: remote updates: add subscription check on 'Refresh all' Dominik Csapak
2025-12-01 13:54 ` [pdm-devel] superseded: [PATCH datacenter-manager/yew-comp 00/10] add subscription checks to apt repository updates & login Dominik Csapak
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox