public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Stefan Lendl <s.lendl@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH v4 proxmox-backup 2/8] ui: global prune and gc job view
Date: Thu,  4 Apr 2024 15:50:30 +0200	[thread overview]
Message-ID: <20240404135028.373407-11-s.lendl@proxmox.com> (raw)
In-Reply-To: <20240404135028.373407-2-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>
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.44.0





  parent reply	other threads:[~2024-04-04 13:52 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-04 13:50 [pbs-devel] [PATCH v4 proxmox-backup 0/8] Add GC job status to datastore and global prune " Stefan Lendl
2024-04-04 13:50 ` [pbs-devel] [PATCH v4 proxmox-backup 1/8] api: garbage collect job status Stefan Lendl
2024-04-04 13:50 ` Stefan Lendl [this message]
2024-04-04 13:50 ` [pbs-devel] [PATCH v4 proxmox-backup 3/8] ui: move prune and gc widget to config Stefan Lendl
2024-04-04 13:50 ` [pbs-devel] [PATCH v4 proxmox-backup 4/8] ui: hide datastore column in local gc view Stefan Lendl
2024-04-04 13:50 ` [pbs-devel] [PATCH v4 proxmox-backup 5/8] ui: order Prune & GC before Sync Jobs Stefan Lendl
2024-04-04 13:50 ` [pbs-devel] [PATCH v4 proxmox-backup 6/8] cli: list gc jobs with proxmox-backup-manager Stefan Lendl
2024-04-04 13:50 ` [pbs-devel] [PATCH v4 proxmox-backup 7/8] ui: show removed and pending data of last run in bytes Stefan Lendl
2024-04-04 13:50 ` [pbs-devel] [PATCH v4 proxmox-backup 8/8] ui: configure width and flex on GC Jobs columns Stefan Lendl

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240404135028.373407-11-s.lendl@proxmox.com \
    --to=s.lendl@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is 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