From 86e432b0b8042a998ae6219454c482ec471ed581 Mon Sep 17 00:00:00 2001 From: Dominik Csapak Date: Fri, 29 May 2020 10:53:42 +0200 Subject: [PATCH] ui: add SyncView shows a nice overview of sync jobs (incl status of last run, estimated next run, etc.) with options to add/edit/remove and also show the log of the last run and manually run it now Signed-off-by: Dominik Csapak --- www/Makefile | 1 + www/NavigationTree.js | 6 + www/config/SyncView.js | 251 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 258 insertions(+) create mode 100644 www/config/SyncView.js diff --git a/www/Makefile b/www/Makefile index 3f0063e4..51de6fb2 100644 --- a/www/Makefile +++ b/www/Makefile @@ -11,6 +11,7 @@ JSSRC= \ config/UserView.js \ config/RemoteView.js \ config/ACLView.js \ + config/SyncView.js \ window/UserEdit.js \ window/RemoteEdit.js \ window/SyncJobEdit.js \ diff --git a/www/NavigationTree.js b/www/NavigationTree.js index 6d4d2455..57b46dae 100644 --- a/www/NavigationTree.js +++ b/www/NavigationTree.js @@ -36,6 +36,12 @@ Ext.define('PBS.store.NavigationStore', { path: 'pbsRemoteView', leaf: true, }, + { + text: gettext('Sync Jobs'), + iconCls: 'fa fa-refresh', + path: 'pbsSyncJobView', + leaf: true, + }, { text: gettext('Data Store'), iconCls: 'fa fa-archive', diff --git a/www/config/SyncView.js b/www/config/SyncView.js new file mode 100644 index 00000000..5c5d044a --- /dev/null +++ b/www/config/SyncView.js @@ -0,0 +1,251 @@ +Ext.define('pbs-sync-jobs-status', { + extend: 'Ext.data.Model', + fields: [ + 'id', 'remote', 'remote-store', 'store', 'schedule', + 'next-run', 'last-run-upid', 'last-run-state', 'last-run-endtime', + { + 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: 'id', + proxy: { + type: 'proxmox', + url: '/api2/json/admin/sync', + }, +}); + +Ext.define('PBS.config.SyncJobView', { + extend: 'Ext.grid.GridPanel', + alias: 'widget.pbsSyncJobView', + + stateful: true, + stateId: 'grid-sync-jobs', + + title: gettext('Sync Jobs'), + + controller: { + xclass: 'Ext.app.ViewController', + + addSyncJob: function() { + let me = this; + Ext.create('PBS.window.SyncJobEdit', { + listeners: { + destroy: function() { + me.reload(); + }, + }, + }).show(); + }, + + editSyncJob: function() { + let me = this; + let view = me.getView(); + let selection = view.getSelection(); + if (selection.length < 1) return; + + Ext.create('PBS.window.SyncJobEdit', { + id: selection[0].data.id, + listeners: { + destroy: function() { + me.reload(); + }, + }, + }).show(); + }, + + openTaskLog: function() { + let me = this; + let view = me.getView(); + let selection = view.getSelection(); + if (selection.length < 1) return; + + let upid = selection[0].data['last-run-upid']; + if (!upid) return; + + Ext.create('Proxmox.window.TaskViewer', { + upid + }).show(); + }, + + runSyncJob: function() { + let me = this; + let view = me.getView(); + let selection = view.getSelection(); + if (selection.length < 1) return; + + let id = selection[0].data.id; + Proxmox.Utils.API2Request({ + method: 'POST', + url: `/admin/sync/${id}/run`, + success: function(response, opt) { + Ext.create('Proxmox.window.TaskViewer', { + upid: response.result.data, + taskDone: function(success) { + me.reload(); + }, + }).show(); + }, + failure: function(response, opt) { + Ext.Msg.alert(gettext('Error'), response.htmlStatus); + }, + }); + }, + + render_sync_status: function(value, metadata, record) { + if (!record.data['last-run-upid']) { + return '-'; + } + + if (!record.data['last-run-endtime']) { + metadata.tdCls = 'x-grid-row-loading'; + return ''; + } + + if (value === 'OK') { + return ` ${gettext("OK")}`; + } + + return ` ${gettext("Error")}:${value}`; + }, + + render_optional_timestamp: function(value) { + if (!value) return '-'; + return Proxmox.Utils.render_timestamp(value); + }, + + reload: function() { this.getView().getStore().rstore.load(); }, + + init: function(view) { + Proxmox.Utils.monStoreErrors(view, view.getStore().rstore); + }, + }, + + listeners: { + activate: 'reload', + itemdblclick: 'editSyncJob', + }, + + store: { + type: 'diff', + autoDestroy: true, + autoDestroyRstore: true, + sorters: 'id', + rstore: { + type: 'update', + storeid: 'pbs-sync-jobs-status', + model: 'pbs-sync-jobs-status', + autoStart: true, + interval: 5000, + }, + }, + + tbar: [ + { + xtype: 'proxmoxButton', + text: gettext('Add'), + handler: 'addSyncJob', + selModel: false, + }, + { + xtype: 'proxmoxButton', + text: gettext('Edit'), + handler: 'editSyncJob', + disabled: true, + }, + { + xtype: 'proxmoxStdRemoveButton', + baseurl: '/config/sync/', + callback: 'reload', + }, + '-', + { + xtype: 'proxmoxButton', + text: gettext('Log'), + handler: 'openTaskLog', + enableFn: (rec) => !!rec.data['last-run-upid'], + disabled: true, + }, + { + xtype: 'proxmoxButton', + text: gettext('Run now'), + handler: 'runSyncJob', + disabled: true, + }, + ], + + viewConfig: { + trackOver: false, + }, + + columns: [ + { + header: gettext('Sync Job'), + width: 200, + sortable: true, + renderer: Ext.String.htmlEncode, + dataIndex: 'id', + }, + { + header: gettext('Remote'), + width: 200, + sortable: true, + dataIndex: 'remote', + }, + { + header: gettext('Remote Store'), + width: 200, + sortable: true, + dataIndex: 'remote-store', + }, + { + header: gettext('Local Store'), + width: 200, + sortable: true, + dataIndex: 'store', + }, + { + header: gettext('Schedule'), + sortable: true, + dataIndex: 'schedule', + }, + { + header: gettext('Status'), + dataIndex: 'last-run-state', + flex: 1, + renderer: 'render_sync_status', + }, + { + header: gettext('Last Sync'), + sortable: true, + minWidth: 200, + renderer: 'render_optional_timestamp', + dataIndex: 'last-run-endtime', + }, + { + text: gettext('Duration'), + dataIndex: 'duration', + width: 60, + renderer: Proxmox.Utils.render_duration, + }, + { + header: gettext('Next Run'), + sortable: true, + minWidth: 200, + renderer: 'render_optional_timestamp', + dataIndex: 'next-run', + }, + { + header: gettext('Comment'), + hidden: true, + sortable: true, + renderer: Ext.String.htmlEncode, + dataIndex: 'comment', + }, + ], +});