fix #3217: ui: global prune and gc job view
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>
This commit is contained in:
parent
fe1d34d2e4
commit
db3fd2132d
@ -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 \
|
||||
|
@ -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 '';
|
||||
}
|
||||
|
207
www/config/GCView.js
Normal file
207
www/config/GCView.js
Normal file
@ -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,
|
||||
},
|
||||
],
|
||||
});
|
@ -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',
|
||||
|
@ -58,7 +58,6 @@ Ext.define('PBS.DataStorePanel', {
|
||||
},
|
||||
},
|
||||
{
|
||||
title: gettext('Prune & GC'),
|
||||
xtype: 'pbsDatastorePruneAndGC',
|
||||
itemId: 'prunegc',
|
||||
iconCls: 'fa fa-trash-o',
|
||||
|
@ -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;
|
||||
},
|
||||
});
|
||||
|
28
www/window/GCJobEdit.js
Normal file
28
www/window/GCJobEdit.js
Normal file
@ -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)"),
|
||||
},
|
||||
});
|
Loading…
Reference in New Issue
Block a user