From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 1CD861FF183 for ; Wed, 17 Dec 2025 15:39:33 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 66C426D7D; Wed, 17 Dec 2025 15:40:20 +0100 (CET) From: Lukas Wagner To: pdm-devel@lists.proxmox.com Date: Wed, 17 Dec 2025 15:39:43 +0100 Message-ID: <20251217143943.273183-1-l.wagner@proxmox.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1765982376021 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.967 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 KAM_MAILER 2 Automated Mailer Tag Left in Email 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] ui: add task descriptions for PBS tasks X-BeenThere: pdm-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Datacenter Manager development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Datacenter Manager development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pdm-devel-bounces@lists.proxmox.com Sender: "pdm-devel" Tried to match the JS-implementation as exactly as possible. Some of the definitions could definitely be improved, but this should be done in tandem with the JS code. Maybe we could could even attempt to have a canonical definition somewhere and then generate both the Rust and JS implementations from that - but not sure if this is worth the effort. Signed-off-by: Lukas Wagner --- This patch requires https://lore.proxmox.com/pdm-devel/20251216131518.241022-7-l.wagner@proxmox.com/T/#u to be applied first. This patch is pretty much independent of the series it is contained in, so it could be applied ahead of the rest. ui/Cargo.toml | 2 + ui/src/tasks.rs | 162 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) diff --git a/ui/Cargo.toml b/ui/Cargo.toml index 1b4f0a23..735a31ac 100644 --- a/ui/Cargo.toml +++ b/ui/Cargo.toml @@ -18,6 +18,7 @@ http = "1" js-sys = "0.3.69" log = "0.4.6" percent-encoding = "2.1" +regex = "1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" wasm-bindgen = "0.2.92" @@ -42,6 +43,7 @@ proxmox-schema = "5" proxmox-subscription = { version = "1.0.1", features = ["api-types"], default-features = false } proxmox-rrd-api-types = "1" proxmox-node-status = "1" +proxmox-time = "2.1" pbs-api-types = { version = "1.0.3", features = [ "enum-fallback" ] } pdm-api-types = { version = "1.0", path = "../lib/pdm-api-types" } diff --git a/ui/src/tasks.rs b/ui/src/tasks.rs index 7e40863d..964ba47c 100644 --- a/ui/src/tasks.rs +++ b/ui/src/tasks.rs @@ -6,6 +6,7 @@ use yew::virtual_dom::Key; pub fn register_tasks() { register_pve_tasks(); + register_pbs_tasks(); register_pdm_tasks(); } @@ -112,6 +113,96 @@ fn register_pve_tasks() { register_task_description("zfsremove", ("ZFS Pool", tr!("Remove"))); } +pub fn register_pbs_tasks() { + register_task_description("acme-deativate", |_ty, id: Option| { + let id = id.unwrap_or_else(|| "default".to_string()); + tr!("Deactivate ACME Account - {0}", id) + }); + register_task_description("acme-register", |_ty, id: Option| { + let id = id.unwrap_or_else(|| "default".to_string()); + tr!("Register ACME Account - {0}", id) + }); + register_task_description("acme-update", |_ty, id: Option| { + let id = id.unwrap_or_else(|| "default".to_string()); + tr!("Update ACME Account - {0}", id) + }); + register_task_description("acme-new-cert", ("", tr!("Order Certificate"))); + register_task_description("acme-renew-cert", ("", tr!("Renew Certificate"))); + register_task_description("acme-revoke-cert", ("", tr!("Revoke Certificate"))); + register_task_description("backup", |_ty, id: Option| { + render_datastore_worker_id(&id.unwrap_or_default(), &tr!("Backup")) + }); + register_task_description("barcode-label-media", ("Drive", tr!("Barcode-Label Media"))); + register_task_description("catalog-media", ("Drive", tr!("Catalog Media"))); + register_task_description( + "create-datastore", + (tr!("Datastore"), tr!("Create Datastore")), + ); + register_task_description( + "delete-datastore", + (tr!("Datastore"), tr!("Remove Datastore")), + ); + register_task_description( + "delete-namespace", + (tr!("Namespace"), tr!("Remove Namespace")), + ); + register_task_description("dircreate", (tr!("Directory Storage"), tr!("Create"))); + register_task_description("dirremove", (tr!("Directory Storage"), tr!("Remove"))); + register_task_description("eject-media", (tr!("Drive"), tr!("Eject Media"))); + register_task_description("format-media", (tr!("Drive"), tr!("Format Media"))); + register_task_description("forget-group", (tr!("Group"), tr!("Remove Group"))); + register_task_description( + "garbage_collection", + (tr!("Datastore"), tr!("Garbage Collect")), + ); + register_task_description("realm-sync", ("Realm", tr!("User Sync"))); + register_task_description("inventory-update", (tr!("Drive"), tr!("Inventory Update"))); + register_task_description("label-media", (tr!("Drive"), tr!("Label Media"))); + register_task_description("load-media", |_ty, id: Option| { + render_drive_load_media_id(&id.unwrap_or_default(), &tr!("Load Media")) + }); + register_task_description("logrotate", tr!("Log Rotation")); + register_task_description("mount-device", (tr!("Datastore"), tr!("Mount Device"))); + register_task_description( + "mount-sync-jobs", + ( + tr!("Datastore"), + tr!("sync jobs handler triggered by mount"), + ), + ); + register_task_description("prune", |_ty, id: Option| { + render_datastore_worker_id(&id.unwrap_or_default(), "Prune") + }); + register_task_description("prunejob", |_ty, id: Option| { + render_prune_job_worker_id(&id.unwrap_or_default(), &tr!("Prune Job")) + }); + register_task_description("reader", |_ty, id: Option| { + render_datastore_worker_id(&id.unwrap_or_default(), &tr!("Read Objects")) + }); + register_task_description("rewind-media", (tr!("Drive"), tr!("Rewind Media"))); + register_task_description("s3-refresh", (tr!("Datastore"), tr!("S3 Refresh"))); + register_task_description("sync", (tr!("Datastore"), tr!("Remote Sync"))); + register_task_description("syncjob", (tr!("Sync Job"), tr!("Remote Sync"))); + register_task_description("tape-backup", |_ty, id: Option| { + render_tape_backup_id(&id.unwrap_or_default(), &tr!("Tape Backup")) + }); + register_task_description("tape-backup-job", |_ty, id: Option| { + render_tape_backup_id(&id.unwrap_or_default(), &tr!("Tape Backup Job")) + }); + register_task_description("tape-restore", (tr!("Datastore"), tr!("Tape Restore"))); + register_task_description("unload-media", (tr!("Drive"), tr!("Unload Media"))); + register_task_description("unmount-device", (tr!("Datastore"), tr!("Unmount Device"))); + register_task_description( + "verificationjob", + (tr!("Verify Job"), tr!("Scheduled Verification")), + ); + register_task_description("verify", (tr!("Datastore"), tr!("Verification"))); + register_task_description("verify_group", (tr!("Group"), tr!("Verification"))); + register_task_description("verify_snapshot", (tr!("Snapshot"), tr!("Verification"))); + register_task_description("wipedisk", (tr!("Device"), tr!("Wipe Disk"))); + register_task_description("zfscreate", (tr!("ZFS Storage"), tr!("Create"))); +} + fn register_pdm_tasks() { register_task_description("logrotate", tr!("Log Rotation")); register_task_description( @@ -124,6 +215,77 @@ fn register_pdm_tasks() { ); } +proxmox_schema::const_regex! { + DATASTORE_WORKER_ID_REGEX = r"^(\S+?):(\S+?)/(\S+?)(/(.+))?$"; +} + +fn render_datastore_worker_id(id: &str, what: &str) -> String { + if let Some(caps) = DATASTORE_WORKER_ID_REGEX.captures(id) { + let datastore = &caps[1]; + let backup_group = format!("{}/{}", &caps[2], &caps[3]); + + if caps.get(4).is_some() { + if let Some(hex_ts) = caps.get(5) { + if let Ok(seconds) = u64::from_str_radix(hex_ts.as_str(), 16) { + let utctime = + proxmox_time::epoch_to_rfc3339_utc(seconds as i64).unwrap_or_default(); + + return format!("Datastore {datastore} {what} {backup_group}/{utctime}"); + } + } + } + + return format!("Datastore {datastore} {what} {backup_group}"); + } + + format!("Datastore {what} {id}") +} + +proxmox_schema::const_regex! { + PRUNE_JOB_WORKER_ID_REGEX = r"^(\S+?):(\S+)$"; +} + +fn render_prune_job_worker_id(id: &str, what: &str) -> String { + if let Some(caps) = PRUNE_JOB_WORKER_ID_REGEX.captures(id) { + let datastore = &caps[1]; + let namespace = &caps[2]; + + return format!("{what} on Datastore {datastore} Namespace {namespace}",); + } + + format!("{what} on Datastore {id}") +} + +proxmox_schema::const_regex! { + TAPE_WORKER_ID_REGEX = r"^(\S+?):(\S+?):(\S+?)(:(.+))?$"; +} + +fn render_tape_backup_id(id: &str, what: &str) -> String { + if let Some(caps) = TAPE_WORKER_ID_REGEX.captures(id) { + let datastore = &caps[1]; + let pool = &caps[2]; + let drive = &caps[3]; + + return format!("{what} {datastore} (pool {pool}, drive {drive})"); + } + + format!("{what} {id}") +} + +proxmox_schema::const_regex! { + DRIVE_LOAD_WORKER_ID_REGEX = r"^(\S+?):(\S+?)$"; +} + +fn render_drive_load_media_id(id: &str, what: &str) -> String { + if let Some(caps) = DRIVE_LOAD_WORKER_ID_REGEX.captures(id) { + let drive = &caps[1]; + let label = &caps[2]; + return format!("{} {drive} - {what} '{label}'", tr!("Drive")); + } + + format!("{what} {id}") +} + /// Format a UPID that is either [`RemoteUpid`] or a [`UPID`] /// If it's a [`RemoteUpid`], prefixes it with the remote name pub fn format_optional_remote_upid(upid: &str, include_remote: bool) -> String { -- 2.47.3 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel