public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view.
@ 2024-04-18 10:16 Lukas Wagner
  2024-04-18 10:16 ` [pbs-devel] [PATCH proxmox-backup v5 01/10] api: garbage collect job status Lukas Wagner
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Lukas Wagner @ 2024-04-18 10:16 UTC (permalink / raw)
  To: pbs-devel

Adopted this patch series since Stefan Lendl left the company. Tested
v4 and did some minor touchups (see changelog).

Original coverletter:

Fix #3217: Addition of a new tab "Prune & GC" in "Datastore" and not in each Datastore created
Fix #4723: add last, next run, status, duration to gc

Extends the garbage collection view to display in addition to the schedule:
* State (of last run)
* Duration (of last run)
* Last Run Date
* Next Run Date (if scheduled)
* Removed Bytes (in last run)
* Pending Bytes (as of last run)

Additionally the api returns the following which is also displayed via CLI:
* Removed Chunks (in last run)
* Pending Chunks (as of last run)

In the Datastore global overview, the prune view is extended to show the same
details for all availible datastores also the ones without a gc-schedule.

Allows editing the schedule, showing the log of the last run and manually
running the gc job. In the global view, by selecting the row of the datastore.

Adds a proxmox-backup-manager cli command to list all gc jobs
`proxmox-backup-manager garbage-collection list`

Changes v4 -> v5:
* Fix eslint warnings
* Pretty print durations/timestamps/bytes in CLI output
* Include refs to bugzilla in 2 commit messages

Changes v3 -> v4:
* Show removed and pending data in bytes instead of number of chunks

Changes v2 -> v3:
* Fixed indentation
* Added git trailers

Changes v1 -> v2:
* Sort imports
* Fix eslint warnings
* Update columns in GC Job view to fill the entire width
* Not include path PruneJobEdit (sent separatly)

This is based on a series from g.goller
Changes to g.goller's series:
* Rename endpoint from gc-info to gc-job-status
* Add list-all-gc-jobs endpoint
* UI uses Grid (table) view instead of model grid
* Implement GC job view in global view

proxmox-backup:

Lukas Wagner (2):
  ui: gcview: fix eslint warnings
  proxmox-backup-mgr: gc jobs: pretty-print bytes/duration/timestamps

Stefan Lendl (8):
  api: garbage collect job status
  fix #3217: ui: global prune and gc job view
  ui: move prune and gc widget to config
  ui: hide datastore column in local gc view
  ui: order Prune & GC before Sync Jobs
  fix #4723: cli: list gc jobs with proxmox-backup-manager
  ui: show removed and pending data of last run in bytes
  ui: configure width and flex on GC Jobs columns

 pbs-api-types/src/datastore.rs    |  46 ++++++
 pbs-tools/src/format.rs           |  14 +-
 src/api2/admin/datastore.rs       | 131 +++++++++++++++-
 src/api2/admin/gc.rs              |  57 +++++++
 src/api2/admin/mod.rs             |   2 +
 src/bin/proxmox-backup-manager.rs |  62 ++++++++
 www/Makefile                      |   4 +-
 www/Utils.js                      |   6 +-
 www/config/GCView.js              | 245 ++++++++++++++++++++++++++++++
 www/config/PruneAndGC.js          |  52 +++++++
 www/datastore/DataStoreList.js    |  11 +-
 www/datastore/Panel.js            |   3 +-
 www/datastore/PruneAndGC.js       | 133 ----------------
 www/window/GCJobEdit.js           |  28 ++++
 14 files changed, 645 insertions(+), 149 deletions(-)
 create mode 100644 src/api2/admin/gc.rs
 create mode 100644 www/config/GCView.js
 create mode 100644 www/config/PruneAndGC.js
 delete mode 100644 www/datastore/PruneAndGC.js
 create mode 100644 www/window/GCJobEdit.js


Summary over all repositories:
  14 files changed, 645 insertions(+), 149 deletions(-)

-- 
Generated by git-murpp 0.7.1


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


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

* [pbs-devel] [PATCH proxmox-backup v5 01/10] api: garbage collect job status
  2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
@ 2024-04-18 10:16 ` Lukas Wagner
  2024-04-18 10:16 ` [pbs-devel] [PATCH proxmox-backup v5 02/10] fix #3217: ui: global prune and gc job view Lukas Wagner
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Lukas Wagner @ 2024-04-18 10:16 UTC (permalink / raw)
  To: pbs-devel

From: Stefan Lendl <s.lendl@proxmox.com>

Adds an api endpoint on the datastore that reports the gc job status
such as:
 - Schedule
 - State (of last run)
 - Duration (of last run)
 - Last Run
 - Next Run (if scheduled)
 - Pending Chunks (of last run)
 - Pending Bytes (of last run)
 - Removed Chunks (of last run)
 - Removed Bytes (of last run)

Adds a dedicated endpoint admin/gc that reports gc job status for all
datastores including the onces without a gc-schedule.

Signed-off-by: Stefan Lendl <s.lendl@proxmox.com>
Originally-by: Gabriel Goller <g.goller@proxmox.com>
Tested-by: Gabriel Goller <g.goller@proxmox.com>
Reviewd-by: Gabriel Goller <g.goller@proxmox.com>
Tested-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
---
 pbs-api-types/src/datastore.rs |  46 ++++++++++++
 src/api2/admin/datastore.rs    | 131 ++++++++++++++++++++++++++++++++-
 src/api2/admin/gc.rs           |  57 ++++++++++++++
 src/api2/admin/mod.rs          |   2 +
 4 files changed, 233 insertions(+), 3 deletions(-)
 create mode 100644 src/api2/admin/gc.rs

diff --git a/pbs-api-types/src/datastore.rs b/pbs-api-types/src/datastore.rs
index 5e13c157..872c4bc7 100644
--- a/pbs-api-types/src/datastore.rs
+++ b/pbs-api-types/src/datastore.rs
@@ -1273,6 +1273,52 @@ pub struct GarbageCollectionStatus {
     pub still_bad: usize,
 }
 
+#[api(
+    properties: {
+        "last-run-upid": {
+            optional: true,
+            type: UPID,
+        },
+    },
+)]
+#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "kebab-case")]
+/// Garbage Collection general info
+pub struct GarbageCollectionJobStatus {
+    /// Datastore
+    pub store: String,
+    /// upid of the last run gc job
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub last_run_upid: Option<String>,
+    /// Sum of removed bytes.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub removed_bytes: Option<u64>,
+    /// Number of removed chunks
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub removed_chunks: Option<usize>,
+    /// Sum of pending bytes
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub pending_bytes: Option<u64>,
+    /// Number of pending chunks
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub pending_chunks: Option<usize>,
+    /// Schedule of the gc job
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub schedule: Option<String>,
+    /// Time of the next gc run
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub next_run: Option<i64>,
+    /// Endtime of the last gc run
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub last_run_endtime: Option<i64>,
+    /// State of the last gc run
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub last_run_state: Option<String>,
+    /// Duration of last gc run
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub duration: Option<i64>,
+}
+
 #[api(
     properties: {
         "gc-status": {
diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs
index 35628c59..77f9fe3d 100644
--- a/src/api2/admin/datastore.rs
+++ b/src/api2/admin/datastore.rs
@@ -27,18 +27,20 @@ use proxmox_sys::fs::{
     file_read_firstline, file_read_optional_string, replace_file, CreateOptions,
 };
 use proxmox_sys::{task_log, task_warn};
+use proxmox_time::CalendarEvent;
 
 use pxar::accessor::aio::Accessor;
 use pxar::EntryKind;
 
 use pbs_api_types::{
     print_ns_and_snapshot, print_store_and_ns, Authid, BackupContent, BackupNamespace, BackupType,
-    Counts, CryptMode, DataStoreListItem, DataStoreStatus, GarbageCollectionStatus, GroupListItem,
+    Counts, CryptMode, DataStoreConfig, DataStoreListItem, DataStoreStatus,
+    GarbageCollectionJobStatus, GarbageCollectionStatus, GroupListItem, JobScheduleStatus,
     KeepOptions, Operation, PruneJobOptions, RRDMode, RRDTimeFrame, SnapshotListItem,
     SnapshotVerifyState, BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, BACKUP_NAMESPACE_SCHEMA,
     BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA, IGNORE_VERIFIED_BACKUPS_SCHEMA,
     MAX_NAMESPACE_DEPTH, NS_MAX_DEPTH_SCHEMA, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
-    PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_PRUNE, PRIV_DATASTORE_READ, PRIV_DATASTORE_VERIFY,
+    PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_PRUNE, PRIV_DATASTORE_READ, PRIV_DATASTORE_VERIFY, UPID,
     UPID_SCHEMA, VERIFICATION_OUTDATED_AFTER_SCHEMA,
 };
 use pbs_client::pxar::{create_tar, create_zip};
@@ -67,7 +69,7 @@ use crate::backup::{
     ListAccessibleBackupGroups, NS_PRIVS_OK,
 };
 
-use crate::server::jobstate::Job;
+use crate::server::jobstate::{compute_schedule_status, Job, JobState};
 
 const GROUP_NOTES_FILE_NAME: &str = "notes";
 
@@ -1238,6 +1240,125 @@ pub fn garbage_collection_status(
     Ok(status)
 }
 
+#[api(
+    input: {
+        properties: {
+            store: {
+                schema: DATASTORE_SCHEMA,
+            },
+        },
+    },
+    returns: {
+        type: GarbageCollectionJobStatus,
+    },
+    access: {
+        permission: &Permission::Privilege(&["datastore", "{store}"], PRIV_DATASTORE_AUDIT, false),
+    },
+)]
+/// Garbage collection status.
+pub fn garbage_collection_job_status(
+    store: String,
+    _info: &ApiMethod,
+    _rpcenv: &mut dyn RpcEnvironment,
+) -> Result<GarbageCollectionJobStatus, Error> {
+    let (config, _) = pbs_config::datastore::config()?;
+    let store_config: DataStoreConfig = config.lookup("datastore", &store)?;
+
+    let mut info = GarbageCollectionJobStatus {
+        store: store.clone(),
+        schedule: store_config.gc_schedule,
+        ..Default::default()
+    };
+
+    let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?;
+    let status_in_memory = datastore.last_gc_status();
+    let state_file = JobState::load("garbage_collection", &store)
+        .map_err(|err| {
+            log::error!(
+                "could not open statefile for {:?}: {}",
+                info.last_run_upid,
+                err
+            )
+        })
+        .ok();
+
+    let mut selected_upid = None;
+    if status_in_memory.upid.is_some() {
+        selected_upid = status_in_memory.upid;
+    } else if let Some(JobState::Finished { upid, .. }) = &state_file {
+        selected_upid = Some(upid.to_owned());
+    }
+
+    info.last_run_upid = selected_upid.clone();
+
+    match selected_upid {
+        Some(upid) => {
+            info.removed_bytes = Some(status_in_memory.removed_bytes);
+            info.removed_chunks = Some(status_in_memory.removed_chunks);
+            info.pending_bytes = Some(status_in_memory.pending_bytes);
+            info.pending_chunks = Some(status_in_memory.pending_chunks);
+
+            let mut computed_schedule: JobScheduleStatus = JobScheduleStatus::default();
+            let mut duration = None;
+            if let Some(state) = state_file {
+                if let Ok(cs) = compute_schedule_status(&state, info.last_run_upid.as_deref()) {
+                    computed_schedule = cs;
+                }
+            }
+
+            if let Some(endtime) = computed_schedule.last_run_endtime {
+                computed_schedule.next_run = info
+                    .schedule
+                    .as_ref()
+                    .and_then(|s| {
+                        s.parse::<CalendarEvent>()
+                            .map_err(|err| log::error!("{err}"))
+                            .ok()
+                    })
+                    .and_then(|e| {
+                        e.compute_next_event(endtime)
+                            .map_err(|err| log::error!("{err}"))
+                            .ok()
+                    })
+                    .and_then(|ne| ne);
+
+                if let Ok(parsed_upid) = upid.parse::<UPID>() {
+                    duration = Some(endtime - parsed_upid.starttime);
+                }
+            }
+
+            info.next_run = computed_schedule.next_run;
+            info.last_run_endtime = computed_schedule.last_run_endtime;
+            info.last_run_state = computed_schedule.last_run_state;
+            info.duration = duration;
+        }
+        None => {
+            if let Some(schedule) = &info.schedule {
+                info.next_run = schedule
+                    .parse::<CalendarEvent>()
+                    .map_err(|err| log::error!("{err}"))
+                    .ok()
+                    .and_then(|e| {
+                        e.compute_next_event(proxmox_time::epoch_i64())
+                            .map_err(|err| log::error!("{err}"))
+                            .ok()
+                    })
+                    .and_then(|ne| ne);
+
+                if let Ok(event) = schedule.parse::<CalendarEvent>() {
+                    if let Ok(next_event) = event.compute_next_event(proxmox_time::epoch_i64()) {
+                        info.next_run = next_event;
+                    }
+                }
+            } else {
+                return Ok(info);
+            }
+        }
+    }
+
+    Ok(info)
+}
+
 #[api(
     returns: {
         description: "List the accessible datastores.",
@@ -2304,6 +2425,10 @@ const DATASTORE_INFO_SUBDIRS: SubdirMap = &[
             .get(&API_METHOD_GARBAGE_COLLECTION_STATUS)
             .post(&API_METHOD_START_GARBAGE_COLLECTION),
     ),
+    (
+        "gc-job-status",
+        &Router::new().get(&API_METHOD_GARBAGE_COLLECTION_JOB_STATUS),
+    ),
     (
         "group-notes",
         &Router::new()
diff --git a/src/api2/admin/gc.rs b/src/api2/admin/gc.rs
new file mode 100644
index 00000000..7535f369
--- /dev/null
+++ b/src/api2/admin/gc.rs
@@ -0,0 +1,57 @@
+use anyhow::Error;
+use pbs_api_types::GarbageCollectionJobStatus;
+
+use proxmox_router::{ApiMethod, Permission, Router, RpcEnvironment};
+use proxmox_schema::api;
+
+use pbs_api_types::DATASTORE_SCHEMA;
+
+use serde_json::Value;
+
+use crate::api2::admin::datastore::{garbage_collection_job_status, get_datastore_list};
+
+#[api(
+    input: {
+        properties: {
+            store: {
+                schema: DATASTORE_SCHEMA,
+                optional: true,
+            },
+        },
+    },
+    returns: {
+        description: "List configured gc jobs and their status",
+        type: Array,
+        items: { type: GarbageCollectionJobStatus },
+    },
+    access: {
+        permission: &Permission::Anybody,
+        description: "Requires Datastore.Audit or Datastore.Modify on datastore.",
+    },
+)]
+/// List all GC jobs (max one per datastore)
+pub fn list_all_gc_jobs(
+    store: Option<String>,
+    _param: Value,
+    _info: &ApiMethod,
+    rpcenv: &mut dyn RpcEnvironment,
+) -> Result<Vec<GarbageCollectionJobStatus>, Error> {
+    let gc_info = match store {
+        Some(store) => {
+            garbage_collection_job_status(store, _info, rpcenv).map(|info| vec![info])?
+        }
+        None => get_datastore_list(Value::Null, _info, rpcenv)?
+            .into_iter()
+            .map(|store_list_item| store_list_item.store)
+            .filter_map(|store| garbage_collection_job_status(store, _info, rpcenv).ok())
+            .collect::<Vec<_>>(),
+    };
+
+    Ok(gc_info)
+}
+
+const GC_ROUTER: Router = Router::new().get(&API_METHOD_LIST_ALL_GC_JOBS);
+
+pub const ROUTER: Router = Router::new()
+    .get(&API_METHOD_LIST_ALL_GC_JOBS)
+    .match_all("store", &GC_ROUTER);
diff --git a/src/api2/admin/mod.rs b/src/api2/admin/mod.rs
index 168dc038..a1c49f8e 100644
--- a/src/api2/admin/mod.rs
+++ b/src/api2/admin/mod.rs
@@ -5,6 +5,7 @@ use proxmox_router::{Router, SubdirMap};
 use proxmox_sortable_macro::sortable;
 
 pub mod datastore;
+pub mod gc;
 pub mod metrics;
 pub mod namespace;
 pub mod prune;
@@ -17,6 +18,7 @@ const SUBDIRS: SubdirMap = &sorted!([
     ("datastore", &datastore::ROUTER),
     ("metrics", &metrics::ROUTER),
     ("prune", &prune::ROUTER),
+    ("gc", &gc::ROUTER),
     ("sync", &sync::ROUTER),
     ("traffic-control", &traffic_control::ROUTER),
     ("verify", &verify::ROUTER),
-- 
2.39.2



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


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

* [pbs-devel] [PATCH proxmox-backup v5 02/10] fix #3217: ui: global prune and gc job view
  2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
  2024-04-18 10:16 ` [pbs-devel] [PATCH proxmox-backup v5 01/10] api: garbage collect job status Lukas Wagner
@ 2024-04-18 10:16 ` Lukas Wagner
  2024-04-18 10:16 ` [pbs-devel] [PATCH proxmox-backup v5 03/10] ui: move prune and gc widget to config Lukas Wagner
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Lukas Wagner @ 2024-04-18 10:16 UTC (permalink / raw)
  To: pbs-devel

From: Stefan Lendl <s.lendl@proxmox.com>

In the global datastore view, extend the prune view to display gc job
status as a table.  Use the same widget in the local view and dispaly gc
job status as a single row.

The local PruneAndGC view is parameterized (cbind) with the datastore.
At initialization the only row is selected.  This allows the rest of the
grid to act on selected rows and it requires far less special casing if
the datastore is set on the view or not.

Having a single row always selected and therefore highlighted, is
visually not appealing.  Therefore, highlighting of selected rows is
disabled in the local view.

Moved GCView to different file and enhanced it with last, next run,
status and duration. Added button to show task log.

Changed `render_task_status()` to also take in account upids stored in
other 'columns'.

Signed-off-by: Stefan Lendl <s.lendl@proxmox.com>
  [LW: include ref to bugzilla in commit message]
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
Originally-by: Gabriel Goller <g.goller@proxmox.com>
Tested-by: Gabriel Goller <g.goller@proxmox.com>
Reviewd-by: Gabriel Goller <g.goller@proxmox.com>
Tested-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
---
 www/Makefile                   |   2 +
 www/Utils.js                   |   6 +-
 www/config/GCView.js           | 207 +++++++++++++++++++++++++++++++++
 www/datastore/DataStoreList.js |   4 +-
 www/datastore/Panel.js         |   1 -
 www/datastore/PruneAndGC.js    | 101 ++--------------
 www/window/GCJobEdit.js        |  28 +++++
 7 files changed, 252 insertions(+), 97 deletions(-)
 create mode 100644 www/config/GCView.js
 create mode 100644 www/window/GCJobEdit.js

diff --git a/www/Makefile b/www/Makefile
index 79cb4c04..40111fd1 100644
--- a/www/Makefile
+++ b/www/Makefile
@@ -63,6 +63,7 @@ JSSRC=							\
 	config/SyncView.js				\
 	config/VerifyView.js				\
 	config/PruneView.js				\
+	config/GCView.js				\
 	config/WebauthnView.js				\
 	config/CertificateView.js			\
 	config/NodeOptionView.js			\
@@ -79,6 +80,7 @@ JSSRC=							\
 	window/NotifyOptions.js				\
 	window/SyncJobEdit.js				\
 	window/PruneJobEdit.js				\
+	window/GCJobEdit.js				\
 	window/UserEdit.js				\
 	window/Settings.js				\
 	window/TokenEdit.js				\
diff --git a/www/Utils.js b/www/Utils.js
index 5357949b..acd6e0d8 100644
--- a/www/Utils.js
+++ b/www/Utils.js
@@ -199,12 +199,12 @@ Ext.define('PBS.Utils', {
 	return fingerprint.substring(0, 23);
     },
 
-    render_task_status: function(value, metadata, record) {
-	if (!record.data['last-run-upid']) {
+    render_task_status: function(value, metadata, record, rowIndex, colIndex, store) {
+	if (!record.data['last-run-upid'] && !store.getById('last-run-upid')?.data.value) {
 	    return '-';
 	}
 
-	if (!record.data['last-run-endtime']) {
+	if (!record.data['last-run-endtime'] && !store.getById('last-run-endtime')?.data.value) {
 	    metadata.tdCls = 'x-grid-row-loading';
 	    return '';
 	}
diff --git a/www/config/GCView.js b/www/config/GCView.js
new file mode 100644
index 00000000..6c9e1e23
--- /dev/null
+++ b/www/config/GCView.js
@@ -0,0 +1,207 @@
+Ext.define('pbs-gc-jobs-status', {
+    extend: 'Ext.data.Model',
+    fields: [
+	'store', 'last-run-upid', 'removed-chunks', 'pending-chunks', 'schedule',
+	'next-run', 'last-run-endtime', 'last-run-state',
+	{
+	    name: 'duration',
+	    calculate: function(data) {
+		let endtime = data['last-run-endtime'];
+		if (!endtime) return undefined;
+		let task = Proxmox.Utils.parse_task_upid(data['last-run-upid']);
+		return endtime - task.starttime;
+	    },
+	},
+    ],
+    idProperty: 'store',
+    proxy: {
+	type: 'proxmox',
+	url: '/api2/json/admin/gc',
+    },
+});
+
+Ext.define('PBS.config.GCJobView', {
+    extend: 'Ext.grid.GridPanel',
+    alias: 'widget.pbsGCJobView',
+
+    stateful: true,
+    stateId: 'grid-gc-jobs-v1',
+    allowDeselect: false,
+
+    title: gettext('Garbage Collect Jobs'),
+
+    controller: {
+	xclass: 'Ext.app.ViewController',
+
+	init: function(view) {
+	    let params = {};
+	    let store = view.getStore();
+	    let proxy = store.rstore.getProxy();
+	    if (view.datastore) {
+		params.store = view.datastore;
+
+		// after the store is loaded, select the row to enable the Edit,.. buttons
+		store.rstore.proxy.on({
+		    'afterload': {
+			fn: () => view.getSelectionModel().select(0),
+			single: true,
+		    },
+		});
+
+		// do not highlight the selected row
+		view.items.items[0].selectedItemCls = '';
+		view.items.items[0].overItemCls = '';
+	    }
+	    proxy.setExtraParams(params);
+	    Proxmox.Utils.monStoreErrors(view, store.rstore);
+	},
+
+	getDatastoreName: function() {
+	    return this.getView().getSelection()[0]?.data.store;
+	},
+
+	getData: function() {
+	    let view = this.getView();
+	    let datastore = this.getDatastoreName();
+	    return view.getStore().getById(datastore).data;
+	},
+
+	editGCJob: function() {
+	    let data = this.getData();
+	    Ext.create('PBS.window.GCJobEdit', {
+		datastore: data.store,
+		id: data.store,
+		schedule: data.schedule,
+		listeners: {
+		    destroy: () => this.reload(),
+		},
+	    }).show();
+	},
+
+	garbageCollect: function() {
+	    let datastore = this.getDatastoreName();
+	    Proxmox.Utils.API2Request({
+		url: `/admin/datastore/${datastore}/gc`,
+		method: 'POST',
+		failure: function(response) {
+		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+		},
+		success: function(response, options) {
+		    Ext.create('Proxmox.window.TaskViewer', {
+			upid: response.result.data,
+		    }).show();
+		},
+	    });
+	},
+
+	showTaskLog: function() {
+	    let me = this;
+
+	    let upid = this.getData()['last-run-upid'];
+	    if (!upid) return;
+
+	    Ext.create('Proxmox.window.TaskViewer', { upid }).show();
+	},
+
+	startStore: function() { this.getView().getStore().rstore.startUpdate(); },
+	stopStore: function() { this.getView().getStore().rstore.stopUpdate(); },
+	reload: function() { this.getView().getStore().rstore.load(); },
+
+    },
+
+    listeners: {
+	activate: 'startStore',
+	destroy: 'stopStore',
+	deactivate: 'stopStore',
+	itemdblclick: 'editGCJob',
+    },
+
+    store: {
+	type: 'diff',
+	autoDestroy: true,
+	autoDestroyRstore: true,
+	sorters: 'store',
+	rstore: {
+	    type: 'update',
+	    storeid: 'pbs-gc-jobs-status',
+	    model: 'pbs-gc-jobs-status',
+	    interval: 5000,
+	},
+    },
+
+    tbar: [
+	{
+	    xtype: 'proxmoxButton',
+	    text: gettext('Edit'),
+	    handler: 'editGCJob',
+	    enableFn: (rec) => !!rec,
+	    disabled: true,
+	},
+	'-',
+	{
+	    xtype: 'proxmoxButton',
+	    text: gettext('Show Log'),
+	    handler: 'showTaskLog',
+	    enableFn: (rec) => !!rec.data["last-run-upid"],
+	    disabled: true,
+	},
+	{
+	    xtype: 'proxmoxButton',
+	    text: gettext('Run now'),
+	    handler: 'garbageCollect',
+	    enableFn: (rec) => !!rec,
+	    disabled: true,
+	},
+    ],
+
+    columns: [
+	{
+	    header: gettext('Datastore'),
+	    dataIndex: 'store',
+	    renderer: Ext.String.htmlEncode,
+	    width: 120,
+	    sortable: true,
+	    hideable: false,
+	},
+	{
+	    header: gettext('Schedule'),
+	    dataIndex: 'schedule',
+	    maxWidth: 220,
+	    minWidth: 80,
+	    flex: 1,
+	    sortable: false,
+	    hideable: false,
+	    renderer: (value) => value ? value : Proxmox.Utils.NoneText,
+	},
+	{
+	    header: gettext('Last GC'),
+	    dataIndex: 'last-run-endtime',
+	    renderer: PBS.Utils.render_optional_timestamp,
+	    minWidth: 150,
+	    sortable: true,
+	},
+	{
+	    text: gettext('Duration'),
+	    dataIndex: 'duration',
+	    renderer: Proxmox.Utils.render_duration,
+	    sortable: false,
+	    width: 80,
+	},
+	{
+	    header: gettext('Last Status'),
+	    dataIndex: 'last-run-state',
+	    renderer: PBS.Utils.render_task_status,
+	    sortable: true,
+	    flex: 3,
+	    maxWidth: 100,
+	    minWidth: 80,
+	},
+	{
+	    header: gettext('Next Run'),
+	    dataIndex: 'next-run',
+	    renderer: PBS.Utils.render_next_task_run,
+	    width: 150,
+	    sortable: true,
+	},
+    ],
+});
diff --git a/www/datastore/DataStoreList.js b/www/datastore/DataStoreList.js
index b496bcbc..a4b77dbf 100644
--- a/www/datastore/DataStoreList.js
+++ b/www/datastore/DataStoreList.js
@@ -239,8 +239,8 @@ Ext.define('PBS.datastore.DataStores', {
 	},
 	{
 	    iconCls: 'fa fa-trash-o',
-	    itemId: 'prunejobs',
-	    xtype: 'pbsPruneJobView',
+	    itemId: 'prunegc',
+	    xtype: 'pbsDatastorePruneAndGC',
 	},
 	{
 	    iconCls: 'fa fa-check-circle',
diff --git a/www/datastore/Panel.js b/www/datastore/Panel.js
index fd1b4611..0fc97d14 100644
--- a/www/datastore/Panel.js
+++ b/www/datastore/Panel.js
@@ -58,7 +58,6 @@ Ext.define('PBS.DataStorePanel', {
 	    },
 	},
 	{
-	    title: gettext('Prune & GC'),
 	    xtype: 'pbsDatastorePruneAndGC',
 	    itemId: 'prunegc',
 	    iconCls: 'fa fa-trash-o',
diff --git a/www/datastore/PruneAndGC.js b/www/datastore/PruneAndGC.js
index aab98dad..33ca0108 100644
--- a/www/datastore/PruneAndGC.js
+++ b/www/datastore/PruneAndGC.js
@@ -1,91 +1,8 @@
-Ext.define('PBS.Datastore.GCOptions', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: 'widget.pbsDatastoreGCOpts',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    onlineHelp: 'maintenance_pruning',
-
-    cbindData: function(initial) {
-	let me = this;
-
-	me.datastore = encodeURIComponent(me.datastore);
-	me.url = `/api2/json/config/datastore/${me.datastore}`;
-	me.editorConfig = {
-	    url: `/api2/extjs/config/datastore/${me.datastore}`,
-	};
-	return {};
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	edit: function() { this.getView().run_editor(); },
-
-	garbageCollect: function() {
-	    let me = this;
-	    let view = me.getView();
-	    Proxmox.Utils.API2Request({
-		url: `/admin/datastore/${view.datastore}/gc`,
-		method: 'POST',
-		failure: function(response) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    Ext.create('Proxmox.window.TaskViewer', {
-			upid: response.result.data,
-		    }).show();
-		},
-	    });
-	},
-    },
-
-    tbar: [
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: 'edit',
-	},
-	'-',
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Start Garbage Collection'),
-	    selModel: null,
-	    handler: 'garbageCollect',
-	},
-    ],
-
-    listeners: {
-	activate: function() { this.rstore.startUpdate(); },
-	destroy: function() { this.rstore.stopUpdate(); },
-	deactivate: function() { this.rstore.stopUpdate(); },
-	itemdblclick: 'edit',
-    },
-
-    rows: {
-	"gc-schedule": {
-	    required: true,
-	    defaultValue: Proxmox.Utils.NoneText,
-	    header: gettext('Garbage Collection Schedule'),
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		title: gettext('GC Schedule'),
-		onlineHelp: 'maintenance_gc',
-		items: {
-		    xtype: 'pbsCalendarEvent',
-		    name: 'gc-schedule',
-		    fieldLabel: gettext("GC Schedule"),
-		    emptyText: Proxmox.Utils.noneText,
-		    deleteEmpty: true,
-		},
-	    },
-	},
-    },
-});
-
 Ext.define('PBS.Datastore.PruneAndGC', {
     extend: 'Ext.panel.Panel',
     alias: 'widget.pbsDatastorePruneAndGC',
+    title: gettext('Prune & GC Jobs'),
+
     mixins: ['Proxmox.Mixin.CBind'],
 
     layout: {
@@ -99,9 +16,8 @@ Ext.define('PBS.Datastore.PruneAndGC', {
     },
     items: [
 	{
-	    xtype: 'pbsDatastoreGCOpts',
-	    title: gettext('Garbage Collection'),
-	    itemId: 'datastore-gc',
+	    xtype: 'pbsGCJobView',
+	    itemId: 'gcjobs',
 	    nodename: 'localhost',
 	    cbind: {
 		datastore: '{datastore}',
@@ -110,9 +26,7 @@ Ext.define('PBS.Datastore.PruneAndGC', {
 	{
 	    xtype: 'pbsPruneJobView',
 	    nodename: 'localhost',
-	    itemId: 'datastore-prune-jobs',
-	    flex: 1,
-	    minHeight: 200,
+	    itemId: 'prunejobs',
 	    cbind: {
 		datastore: '{datastore}',
 	    },
@@ -130,4 +44,9 @@ Ext.define('PBS.Datastore.PruneAndGC', {
 	    component.relayEvents(me, ['activate', 'deactivate', 'destroy']);
 	}
     },
+
+    cbindData: function(initalConfig) {
+        let me = this;
+        me.datastore = initalConfig.datastore ? initalConfig.datastore : undefined;
+    },
 });
diff --git a/www/window/GCJobEdit.js b/www/window/GCJobEdit.js
new file mode 100644
index 00000000..de74bf5c
--- /dev/null
+++ b/www/window/GCJobEdit.js
@@ -0,0 +1,28 @@
+Ext.define('PBS.window.GCJobEdit', {
+    extend: 'Proxmox.window.Edit',
+    alias: 'widget.pbsGCJobEdit',
+    mixins: ['Proxmox.Mixin.CBind'],
+
+    userid: undefined,
+    onlineHelp: 'maintenance_gc',
+    isAdd: false,
+
+    subject: gettext('Garbage Collect Schedule'),
+
+    cbindData: function(initial) {
+        let me = this;
+
+        me.datastore = encodeURIComponent(me.datastore);
+	me.url = `/api2/extjs/config/datastore/${me.datastore}`;
+        me.method = 'PUT';
+        me.autoLoad = true;
+	return {};
+    },
+
+    items: {
+	xtype: 'pbsCalendarEvent',
+	name: 'gc-schedule',
+	fieldLabel: gettext("GC Schedule"),
+	emptyText: gettext(Proxmox.Utils.NoneText + " (disabled)"),
+    },
+});
-- 
2.39.2



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


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

* [pbs-devel] [PATCH proxmox-backup v5 03/10] ui: move prune and gc widget to config
  2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
  2024-04-18 10:16 ` [pbs-devel] [PATCH proxmox-backup v5 01/10] api: garbage collect job status Lukas Wagner
  2024-04-18 10:16 ` [pbs-devel] [PATCH proxmox-backup v5 02/10] fix #3217: ui: global prune and gc job view Lukas Wagner
@ 2024-04-18 10:16 ` Lukas Wagner
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 04/10] ui: hide datastore column in local gc view Lukas Wagner
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Lukas Wagner @ 2024-04-18 10:16 UTC (permalink / raw)
  To: pbs-devel

From: Stefan Lendl <s.lendl@proxmox.com>

* move datastore/PruneAndGC to config/PruneAndGC
* renaming the widgets to PBS.config.PruneAndGC

Signed-off-by: Stefan Lendl <s.lendl@proxmox.com>
Tested-by: Gabriel Goller <g.goller@proxmox.com>
Reviewd-by: Gabriel Goller <g.goller@proxmox.com>
Tested-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
---
 www/Makefile                            | 2 +-
 www/{datastore => config}/PruneAndGC.js | 4 ++--
 www/datastore/DataStoreList.js          | 2 +-
 www/datastore/Panel.js                  | 2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)
 rename www/{datastore => config}/PruneAndGC.js (92%)

diff --git a/www/Makefile b/www/Makefile
index 40111fd1..b612a116 100644
--- a/www/Makefile
+++ b/www/Makefile
@@ -68,6 +68,7 @@ JSSRC=							\
 	config/CertificateView.js			\
 	config/NodeOptionView.js			\
 	config/MetricServerView.js			\
+	config/PruneAndGC.js				\
 	window/ACLEdit.js				\
 	window/BackupGroupChangeOwner.js		\
 	window/CreateDirectory.js			\
@@ -106,7 +107,6 @@ JSSRC=							\
 	Subscription.js					\
 	datastore/Summary.js				\
 	datastore/Notes.js				\
-	datastore/PruneAndGC.js				\
 	datastore/Prune.js				\
 	datastore/Content.js				\
 	datastore/OptionView.js				\
diff --git a/www/datastore/PruneAndGC.js b/www/config/PruneAndGC.js
similarity index 92%
rename from www/datastore/PruneAndGC.js
rename to www/config/PruneAndGC.js
index 33ca0108..a1163402 100644
--- a/www/datastore/PruneAndGC.js
+++ b/www/config/PruneAndGC.js
@@ -1,6 +1,6 @@
-Ext.define('PBS.Datastore.PruneAndGC', {
+Ext.define('PBS.config.PruneAndGC', {
     extend: 'Ext.panel.Panel',
-    alias: 'widget.pbsDatastorePruneAndGC',
+    alias: 'widget.pbsPruneAndGC',
     title: gettext('Prune & GC Jobs'),
 
     mixins: ['Proxmox.Mixin.CBind'],
diff --git a/www/datastore/DataStoreList.js b/www/datastore/DataStoreList.js
index a4b77dbf..a31a9b4b 100644
--- a/www/datastore/DataStoreList.js
+++ b/www/datastore/DataStoreList.js
@@ -240,7 +240,7 @@ Ext.define('PBS.datastore.DataStores', {
 	{
 	    iconCls: 'fa fa-trash-o',
 	    itemId: 'prunegc',
-	    xtype: 'pbsDatastorePruneAndGC',
+	    xtype: 'pbsPruneAndGC',
 	},
 	{
 	    iconCls: 'fa fa-check-circle',
diff --git a/www/datastore/Panel.js b/www/datastore/Panel.js
index 0fc97d14..0ee38a1b 100644
--- a/www/datastore/Panel.js
+++ b/www/datastore/Panel.js
@@ -58,7 +58,7 @@ Ext.define('PBS.DataStorePanel', {
 	    },
 	},
 	{
-	    xtype: 'pbsDatastorePruneAndGC',
+	    xtype: 'pbsPruneAndGC',
 	    itemId: 'prunegc',
 	    iconCls: 'fa fa-trash-o',
 	    cbind: {
-- 
2.39.2



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


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

* [pbs-devel] [PATCH proxmox-backup v5 04/10] ui: hide datastore column in local gc view
  2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
                   ` (2 preceding siblings ...)
  2024-04-18 10:16 ` [pbs-devel] [PATCH proxmox-backup v5 03/10] ui: move prune and gc widget to config Lukas Wagner
@ 2024-04-18 10:17 ` Lukas Wagner
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 05/10] ui: order Prune & GC before Sync Jobs Lukas Wagner
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Lukas Wagner @ 2024-04-18 10:17 UTC (permalink / raw)
  To: pbs-devel

From: Stefan Lendl <s.lendl@proxmox.com>

Signed-off-by: Stefan Lendl <s.lendl@proxmox.com>
Tested-by: Gabriel Goller <g.goller@proxmox.com>
Reviewd-by: Gabriel Goller <g.goller@proxmox.com>
Tested-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
---
 www/config/GCView.js | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/www/config/GCView.js b/www/config/GCView.js
index 6c9e1e23..63e84111 100644
--- a/www/config/GCView.js
+++ b/www/config/GCView.js
@@ -204,4 +204,18 @@ Ext.define('PBS.config.GCJobView', {
 	    sortable: true,
 	},
     ],
+
+    initComponent: function() {
+	let me = this;
+	let hideLocalDatastore = !!me.datastore;
+
+	for (let column of me.columns) {
+	    if (column.dataIndex === 'store') {
+		column.hidden = hideLocalDatastore;
+		break;
+	    }
+	}
+
+	me.callParent();
+    },
 });
-- 
2.39.2



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


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

* [pbs-devel] [PATCH proxmox-backup v5 05/10] ui: order Prune & GC before Sync Jobs
  2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
                   ` (3 preceding siblings ...)
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 04/10] ui: hide datastore column in local gc view Lukas Wagner
@ 2024-04-18 10:17 ` Lukas Wagner
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 06/10] fix #4723: cli: list gc jobs with proxmox-backup-manager Lukas Wagner
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Lukas Wagner @ 2024-04-18 10:17 UTC (permalink / raw)
  To: pbs-devel

From: Stefan Lendl <s.lendl@proxmox.com>

Make the order identical to local datastore view.

Signed-off-by: Stefan Lendl <s.lendl@proxmox.com>
Tested-by: Gabriel Goller <g.goller@proxmox.com>
Reviewd-by: Gabriel Goller <g.goller@proxmox.com>
Tested-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
---
 www/datastore/DataStoreList.js | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/www/datastore/DataStoreList.js b/www/datastore/DataStoreList.js
index a31a9b4b..fc68cfc1 100644
--- a/www/datastore/DataStoreList.js
+++ b/www/datastore/DataStoreList.js
@@ -231,17 +231,16 @@ Ext.define('PBS.datastore.DataStores', {
 	    xtype: 'pbsDataStoreList',
 	    iconCls: 'fa fa-book',
 	},
-
-	{
-	    iconCls: 'fa fa-refresh',
-	    itemId: 'syncjobs',
-	    xtype: 'pbsSyncJobView',
-	},
 	{
 	    iconCls: 'fa fa-trash-o',
 	    itemId: 'prunegc',
 	    xtype: 'pbsPruneAndGC',
 	},
+	{
+	    iconCls: 'fa fa-refresh',
+	    itemId: 'syncjobs',
+	    xtype: 'pbsSyncJobView',
+	},
 	{
 	    iconCls: 'fa fa-check-circle',
 	    itemId: 'verifyjobs',
-- 
2.39.2



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


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

* [pbs-devel] [PATCH proxmox-backup v5 06/10] fix #4723: cli: list gc jobs with proxmox-backup-manager
  2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
                   ` (4 preceding siblings ...)
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 05/10] ui: order Prune & GC before Sync Jobs Lukas Wagner
@ 2024-04-18 10:17 ` Lukas Wagner
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 07/10] ui: show removed and pending data of last run in bytes Lukas Wagner
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Lukas Wagner @ 2024-04-18 10:17 UTC (permalink / raw)
  To: pbs-devel

From: Stefan Lendl <s.lendl@proxmox.com>

proxmox-backup-manager garbage-collection list
  to list the garbage collection job status for all datastores,
  including datastores without gc jobs.

Signed-off-by: Stefan Lendl <s.lendl@proxmox.com>
  [LW: add ref to bugzilla issue to commit message]
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
Tested-by: Gabriel Goller <g.goller@proxmox.com>
Reviewd-by: Gabriel Goller <g.goller@proxmox.com>
Tested-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
---
 src/bin/proxmox-backup-manager.rs | 33 +++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/src/bin/proxmox-backup-manager.rs b/src/bin/proxmox-backup-manager.rs
index 115207f3..94fc6b2f 100644
--- a/src/bin/proxmox-backup-manager.rs
+++ b/src/bin/proxmox-backup-manager.rs
@@ -93,6 +93,35 @@ async fn garbage_collection_status(param: Value) -> Result<Value, Error> {
     Ok(Value::Null)
 }
 
+#[api(
+   input: {
+        properties: {
+            "output-format": {
+                schema: OUTPUT_FORMAT,
+                optional: true,
+            },
+        }
+   }
+)]
+/// List garbage collection job status for all datastores, including datastores without gc jobs.
+async fn garbage_collection_list_jobs(param: Value) -> Result<Value, Error> {
+    let output_format = get_output_format(&param);
+
+    let client = connect_to_localhost()?;
+
+    let path = "api2/json/admin/gc";
+
+    let mut result = client.get(&path, None).await?;
+    let mut data = result["data"].take();
+    let return_type = &api2::admin::gc::API_METHOD_LIST_ALL_GC_JOBS.returns;
+
+    let options = default_table_format_options();
+
+    format_and_print_result_full(&mut data, return_type, &output_format, &options);
+
+    Ok(Value::Null)
+}
+
 fn garbage_collection_commands() -> CommandLineInterface {
     let cmd_def = CliCommandMap::new()
         .insert(
@@ -106,6 +135,10 @@ fn garbage_collection_commands() -> CommandLineInterface {
             CliCommand::new(&API_METHOD_START_GARBAGE_COLLECTION)
                 .arg_param(&["store"])
                 .completion_cb("store", pbs_config::datastore::complete_datastore_name),
+        )
+        .insert(
+            "list",
+            CliCommand::new(&API_METHOD_GARBAGE_COLLECTION_LIST_JOBS),
         );
 
     cmd_def.into()
-- 
2.39.2



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


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

* [pbs-devel] [PATCH proxmox-backup v5 07/10] ui: show removed and pending data of last run in bytes
  2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
                   ` (5 preceding siblings ...)
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 06/10] fix #4723: cli: list gc jobs with proxmox-backup-manager Lukas Wagner
@ 2024-04-18 10:17 ` Lukas Wagner
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 08/10] ui: configure width and flex on GC Jobs columns Lukas Wagner
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Lukas Wagner @ 2024-04-18 10:17 UTC (permalink / raw)
  To: pbs-devel

From: Stefan Lendl <s.lendl@proxmox.com>

Show the removed and pending data of the last run formatted with
Proxmox.Utils.format_size for better readability identically to data
display in the overview tab.

Signed-off-by: Stefan Lendl <s.lendl@proxmox.com>
Tested-by: Gabriel Goller <g.goller@proxmox.com>
Reviewd-by: Gabriel Goller <g.goller@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
Suggested-by: Lukas Wagner <l.wagner@proxmox.com>
---
 www/config/GCView.js | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/www/config/GCView.js b/www/config/GCView.js
index 63e84111..6e1a6d06 100644
--- a/www/config/GCView.js
+++ b/www/config/GCView.js
@@ -1,7 +1,7 @@
 Ext.define('pbs-gc-jobs-status', {
     extend: 'Ext.data.Model',
     fields: [
-	'store', 'last-run-upid', 'removed-chunks', 'pending-chunks', 'schedule',
+	'store', 'last-run-upid', 'removed-bytes', 'pending-bytes', 'schedule',
 	'next-run', 'last-run-endtime', 'last-run-state',
 	{
 	    name: 'duration',
@@ -203,6 +203,20 @@ Ext.define('PBS.config.GCJobView', {
 	    width: 150,
 	    sortable: true,
 	},
+	{
+	    header: gettext('Removed Data'),
+	    dataIndex: 'removed-bytes',
+	    renderer: (value) => value !== undefined ?
+		Proxmox.Utils.format_size(value, true) : "-",
+	    sortable: false,
+	},
+	{
+	    header: gettext('Pending Data'),
+	    dataIndex: 'pending-bytes',
+	    renderer: (value) => value !== undefined ?
+		Proxmox.Utils.format_size(value, true) : "-",
+	    sortable: false,
+	},
     ],
 
     initComponent: function() {
-- 
2.39.2



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


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

* [pbs-devel] [PATCH proxmox-backup v5 08/10] ui: configure width and flex on GC Jobs columns
  2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
                   ` (6 preceding siblings ...)
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 07/10] ui: show removed and pending data of last run in bytes Lukas Wagner
@ 2024-04-18 10:17 ` Lukas Wagner
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 09/10] ui: gcview: fix eslint warnings Lukas Wagner
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Lukas Wagner @ 2024-04-18 10:17 UTC (permalink / raw)
  To: pbs-devel

From: Stefan Lendl <s.lendl@proxmox.com>

table expands to the full width and relevant data is still visible on a
narrow screen.

Signed-off-by: Stefan Lendl <s.lendl@proxmox.com>
Tested-by: Gabriel Goller <g.goller@proxmox.com>
Reviewd-by: Gabriel Goller <g.goller@proxmox.com>
Tested-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
---
 www/config/GCView.js | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/www/config/GCView.js b/www/config/GCView.js
index 6e1a6d06..75bf60a4 100644
--- a/www/config/GCView.js
+++ b/www/config/GCView.js
@@ -159,49 +159,55 @@ Ext.define('PBS.config.GCJobView', {
 	    header: gettext('Datastore'),
 	    dataIndex: 'store',
 	    renderer: Ext.String.htmlEncode,
-	    width: 120,
 	    sortable: true,
 	    hideable: false,
+	    width: 150,
+	    minWidth: 120,
+	    maxWidth: 300,
+	    flex: 2,
 	},
 	{
 	    header: gettext('Schedule'),
 	    dataIndex: 'schedule',
-	    maxWidth: 220,
-	    minWidth: 80,
-	    flex: 1,
 	    sortable: false,
 	    hideable: false,
 	    renderer: (value) => value ? value : Proxmox.Utils.NoneText,
+	    width: 85,
+	    minWidth: 85,
+	    flex: 1,
 	},
 	{
 	    header: gettext('Last GC'),
 	    dataIndex: 'last-run-endtime',
 	    renderer: PBS.Utils.render_optional_timestamp,
-	    minWidth: 150,
 	    sortable: true,
+	    minWidth: 150,
+	    flex: 1,
 	},
 	{
 	    text: gettext('Duration'),
 	    dataIndex: 'duration',
 	    renderer: Proxmox.Utils.render_duration,
 	    sortable: false,
-	    width: 80,
+	    minWidth: 80,
+	    flex: 1,
 	},
 	{
 	    header: gettext('Last Status'),
 	    dataIndex: 'last-run-state',
 	    renderer: PBS.Utils.render_task_status,
 	    sortable: true,
-	    flex: 3,
-	    maxWidth: 100,
+	    width: 100,
 	    minWidth: 80,
+	    flex: 1,
 	},
 	{
 	    header: gettext('Next Run'),
 	    dataIndex: 'next-run',
 	    renderer: PBS.Utils.render_next_task_run,
-	    width: 150,
 	    sortable: true,
+	    minWidth: 150,
+	    flex: 1,
 	},
 	{
 	    header: gettext('Removed Data'),
@@ -209,6 +215,8 @@ Ext.define('PBS.config.GCJobView', {
 	    renderer: (value) => value !== undefined ?
 		Proxmox.Utils.format_size(value, true) : "-",
 	    sortable: false,
+	    minWidth: 85,
+	    flex: 1,
 	},
 	{
 	    header: gettext('Pending Data'),
@@ -216,6 +224,8 @@ Ext.define('PBS.config.GCJobView', {
 	    renderer: (value) => value !== undefined ?
 		Proxmox.Utils.format_size(value, true) : "-",
 	    sortable: false,
+	    minWidth: 80,
+	    flex: 3,
 	},
     ],
 
-- 
2.39.2



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


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

* [pbs-devel] [PATCH proxmox-backup v5 09/10] ui: gcview: fix eslint warnings
  2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
                   ` (7 preceding siblings ...)
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 08/10] ui: configure width and flex on GC Jobs columns Lukas Wagner
@ 2024-04-18 10:17 ` Lukas Wagner
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 10/10] proxmox-backup-mgr: gc jobs: pretty-print bytes/duration/timestamps Lukas Wagner
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Lukas Wagner @ 2024-04-18 10:17 UTC (permalink / raw)
  To: pbs-devel

The ternary ? operator should be at the start of the line if the
the expression is split into multiple lines.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---
 www/config/GCView.js | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/www/config/GCView.js b/www/config/GCView.js
index 75bf60a4..852dca5d 100644
--- a/www/config/GCView.js
+++ b/www/config/GCView.js
@@ -212,8 +212,8 @@ Ext.define('PBS.config.GCJobView', {
 	{
 	    header: gettext('Removed Data'),
 	    dataIndex: 'removed-bytes',
-	    renderer: (value) => value !== undefined ?
-		Proxmox.Utils.format_size(value, true) : "-",
+	    renderer: (value) => value !== undefined
+		? Proxmox.Utils.format_size(value, true) : "-",
 	    sortable: false,
 	    minWidth: 85,
 	    flex: 1,
@@ -221,8 +221,8 @@ Ext.define('PBS.config.GCJobView', {
 	{
 	    header: gettext('Pending Data'),
 	    dataIndex: 'pending-bytes',
-	    renderer: (value) => value !== undefined ?
-		Proxmox.Utils.format_size(value, true) : "-",
+	    renderer: (value) => value !== undefined
+		? Proxmox.Utils.format_size(value, true) : "-",
 	    sortable: false,
 	    minWidth: 80,
 	    flex: 3,
-- 
2.39.2



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


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

* [pbs-devel] [PATCH proxmox-backup v5 10/10] proxmox-backup-mgr: gc jobs: pretty-print bytes/duration/timestamps
  2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
                   ` (8 preceding siblings ...)
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 09/10] ui: gcview: fix eslint warnings Lukas Wagner
@ 2024-04-18 10:17 ` Lukas Wagner
  2024-04-18 12:11 ` [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Gabriel Goller
  2024-04-23 12:37 ` [pbs-devel] applied-series: " Fabian Grünbichler
  11 siblings, 0 replies; 13+ messages in thread
From: Lukas Wagner @ 2024-04-18 10:17 UTC (permalink / raw)
  To: pbs-devel

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---
 pbs-tools/src/format.rs           | 14 +++++++++++++-
 src/bin/proxmox-backup-manager.rs | 31 ++++++++++++++++++++++++++++++-
 2 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/pbs-tools/src/format.rs b/pbs-tools/src/format.rs
index c208d8cb..bc9f20a8 100644
--- a/pbs-tools/src/format.rs
+++ b/pbs-tools/src/format.rs
@@ -1,9 +1,11 @@
 use std::borrow::Borrow;
+use std::time::Duration;
 
-use anyhow::Error;
+use anyhow::{Context, Error};
 use serde_json::Value;
 
 use proxmox_human_byte::HumanByte;
+use proxmox_time::TimeSpan;
 
 pub fn strip_server_file_extension(name: &str) -> &str {
     if name.ends_with(".didx") || name.ends_with(".fidx") || name.ends_with(".blob") {
@@ -64,3 +66,13 @@ pub fn render_bytes_human_readable(value: &Value, _record: &Value) -> Result<Str
     };
     Ok(text)
 }
+
+pub fn render_duration(val: &Value, _record: &Value) -> Result<String, Error> {
+    if val.is_null() {
+        return Ok(String::new());
+    }
+    let duration = val.as_u64().context("not a number")?;
+    let time_span = TimeSpan::from(Duration::from_secs(duration));
+
+    Ok(format!("{time_span}"))
+}
diff --git a/src/bin/proxmox-backup-manager.rs b/src/bin/proxmox-backup-manager.rs
index 94fc6b2f..28271cb4 100644
--- a/src/bin/proxmox-backup-manager.rs
+++ b/src/bin/proxmox-backup-manager.rs
@@ -115,7 +115,36 @@ async fn garbage_collection_list_jobs(param: Value) -> Result<Value, Error> {
     let mut data = result["data"].take();
     let return_type = &api2::admin::gc::API_METHOD_LIST_ALL_GC_JOBS.returns;
 
-    let options = default_table_format_options();
+    use pbs_tools::format::{render_bytes_human_readable, render_duration, render_epoch};
+    let options = default_table_format_options()
+        .column(ColumnConfig::new("store"))
+        .column(
+            ColumnConfig::new("last-run-endtime")
+                .right_align(false)
+                .renderer(render_epoch),
+        )
+        .column(
+            ColumnConfig::new("duration")
+                .right_align(false)
+                .renderer(render_duration),
+        )
+        .column(
+            ColumnConfig::new("removed-bytes")
+                .right_align(false)
+                .renderer(render_bytes_human_readable),
+        )
+        .column(
+            ColumnConfig::new("pending-bytes")
+                .right_align(false)
+                .renderer(render_bytes_human_readable),
+        )
+        .column(ColumnConfig::new("last-run-state"))
+        .column(ColumnConfig::new("schedule"))
+        .column(
+            ColumnConfig::new("next-run")
+                .right_align(false)
+                .renderer(render_epoch),
+        );
 
     format_and_print_result_full(&mut data, return_type, &output_format, &options);
 
-- 
2.39.2



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


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

* Re: [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view.
  2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
                   ` (9 preceding siblings ...)
  2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 10/10] proxmox-backup-mgr: gc jobs: pretty-print bytes/duration/timestamps Lukas Wagner
@ 2024-04-18 12:11 ` Gabriel Goller
  2024-04-23 12:37 ` [pbs-devel] applied-series: " Fabian Grünbichler
  11 siblings, 0 replies; 13+ messages in thread
From: Gabriel Goller @ 2024-04-18 12:11 UTC (permalink / raw)
  To: Proxmox Backup Server development discussion

LGTM!
This works really well and looks nice. The table's cells are also spaced
out correctly and responsive!

Consider:
Tested-by: Gabriel Goller <g.goller@proxmox.com>



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


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

* [pbs-devel] applied-series: [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view.
  2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
                   ` (10 preceding siblings ...)
  2024-04-18 12:11 ` [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Gabriel Goller
@ 2024-04-23 12:37 ` Fabian Grünbichler
  11 siblings, 0 replies; 13+ messages in thread
From: Fabian Grünbichler @ 2024-04-23 12:37 UTC (permalink / raw)
  To: Proxmox Backup Server development discussion

with Dominik's and my follow-ups

On April 18, 2024 12:16 pm, Lukas Wagner wrote:
> Adopted this patch series since Stefan Lendl left the company. Tested
> v4 and did some minor touchups (see changelog).
> 
> Original coverletter:
> 
> Fix #3217: Addition of a new tab "Prune & GC" in "Datastore" and not in each Datastore created
> Fix #4723: add last, next run, status, duration to gc
> 
> Extends the garbage collection view to display in addition to the schedule:
> * State (of last run)
> * Duration (of last run)
> * Last Run Date
> * Next Run Date (if scheduled)
> * Removed Bytes (in last run)
> * Pending Bytes (as of last run)
> 
> Additionally the api returns the following which is also displayed via CLI:
> * Removed Chunks (in last run)
> * Pending Chunks (as of last run)
> 
> In the Datastore global overview, the prune view is extended to show the same
> details for all availible datastores also the ones without a gc-schedule.
> 
> Allows editing the schedule, showing the log of the last run and manually
> running the gc job. In the global view, by selecting the row of the datastore.
> 
> Adds a proxmox-backup-manager cli command to list all gc jobs
> `proxmox-backup-manager garbage-collection list`
> 
> Changes v4 -> v5:
> * Fix eslint warnings
> * Pretty print durations/timestamps/bytes in CLI output
> * Include refs to bugzilla in 2 commit messages
> 
> Changes v3 -> v4:
> * Show removed and pending data in bytes instead of number of chunks
> 
> Changes v2 -> v3:
> * Fixed indentation
> * Added git trailers
> 
> Changes v1 -> v2:
> * Sort imports
> * Fix eslint warnings
> * Update columns in GC Job view to fill the entire width
> * Not include path PruneJobEdit (sent separatly)
> 
> This is based on a series from g.goller
> Changes to g.goller's series:
> * Rename endpoint from gc-info to gc-job-status
> * Add list-all-gc-jobs endpoint
> * UI uses Grid (table) view instead of model grid
> * Implement GC job view in global view
> 
> proxmox-backup:
> 
> Lukas Wagner (2):
>   ui: gcview: fix eslint warnings
>   proxmox-backup-mgr: gc jobs: pretty-print bytes/duration/timestamps
> 
> Stefan Lendl (8):
>   api: garbage collect job status
>   fix #3217: ui: global prune and gc job view
>   ui: move prune and gc widget to config
>   ui: hide datastore column in local gc view
>   ui: order Prune & GC before Sync Jobs
>   fix #4723: cli: list gc jobs with proxmox-backup-manager
>   ui: show removed and pending data of last run in bytes
>   ui: configure width and flex on GC Jobs columns
> 
>  pbs-api-types/src/datastore.rs    |  46 ++++++
>  pbs-tools/src/format.rs           |  14 +-
>  src/api2/admin/datastore.rs       | 131 +++++++++++++++-
>  src/api2/admin/gc.rs              |  57 +++++++
>  src/api2/admin/mod.rs             |   2 +
>  src/bin/proxmox-backup-manager.rs |  62 ++++++++
>  www/Makefile                      |   4 +-
>  www/Utils.js                      |   6 +-
>  www/config/GCView.js              | 245 ++++++++++++++++++++++++++++++
>  www/config/PruneAndGC.js          |  52 +++++++
>  www/datastore/DataStoreList.js    |  11 +-
>  www/datastore/Panel.js            |   3 +-
>  www/datastore/PruneAndGC.js       | 133 ----------------
>  www/window/GCJobEdit.js           |  28 ++++
>  14 files changed, 645 insertions(+), 149 deletions(-)
>  create mode 100644 src/api2/admin/gc.rs
>  create mode 100644 www/config/GCView.js
>  create mode 100644 www/config/PruneAndGC.js
>  delete mode 100644 www/datastore/PruneAndGC.js
>  create mode 100644 www/window/GCJobEdit.js
> 
> 
> Summary over all repositories:
>   14 files changed, 645 insertions(+), 149 deletions(-)
> 
> -- 
> Generated by git-murpp 0.7.1
> 
> 
> _______________________________________________
> pbs-devel mailing list
> pbs-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel
> 
> 
> 


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


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

end of thread, other threads:[~2024-04-23 12:37 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-18 10:16 [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Lukas Wagner
2024-04-18 10:16 ` [pbs-devel] [PATCH proxmox-backup v5 01/10] api: garbage collect job status Lukas Wagner
2024-04-18 10:16 ` [pbs-devel] [PATCH proxmox-backup v5 02/10] fix #3217: ui: global prune and gc job view Lukas Wagner
2024-04-18 10:16 ` [pbs-devel] [PATCH proxmox-backup v5 03/10] ui: move prune and gc widget to config Lukas Wagner
2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 04/10] ui: hide datastore column in local gc view Lukas Wagner
2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 05/10] ui: order Prune & GC before Sync Jobs Lukas Wagner
2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 06/10] fix #4723: cli: list gc jobs with proxmox-backup-manager Lukas Wagner
2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 07/10] ui: show removed and pending data of last run in bytes Lukas Wagner
2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 08/10] ui: configure width and flex on GC Jobs columns Lukas Wagner
2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 09/10] ui: gcview: fix eslint warnings Lukas Wagner
2024-04-18 10:17 ` [pbs-devel] [PATCH proxmox-backup v5 10/10] proxmox-backup-mgr: gc jobs: pretty-print bytes/duration/timestamps Lukas Wagner
2024-04-18 12:11 ` [pbs-devel] [PATCH proxmox-backup v5 00/10] Add GC job status to datastore and global prune job view Gabriel Goller
2024-04-23 12:37 ` [pbs-devel] applied-series: " Fabian Grünbichler

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal