ui: add Task Panels for dashboard

LongestTasks:
grid that shows tasks sorted by duration in descending order

RunningTasks:
grid that shows all running tasks

TaskSummary:
an overview of backup,prune,gc and sync tasks (error/warning/ok)

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Dominik Csapak 2020-06-12 13:34:05 +02:00 committed by Wolfgang Bumiller
parent 4b12879289
commit 6f3146c08c
4 changed files with 296 additions and 0 deletions

View File

@ -19,6 +19,9 @@ JSSRC= \
window/ACLEdit.js \ window/ACLEdit.js \
window/DataStoreEdit.js \ window/DataStoreEdit.js \
dashboard/DataStoreStatistics.js \ dashboard/DataStoreStatistics.js \
dashboard/LongestTasks.js \
dashboard/RunningTasks.js \
dashboard/TaskSummary.js \
Utils.js \ Utils.js \
LoginView.js \ LoginView.js \
VersionInfo.js \ VersionInfo.js \

View File

@ -0,0 +1,104 @@
Ext.define('PBS.LongestTasks', {
extend: 'Ext.grid.Panel',
alias: 'widget.pbsLongestTasks',
title: gettext('Longest Tasks (last Month)'),
hideHeaders: true,
rowLines: false,
emptyText: gettext('No Tasks'),
controller: {
xclass: 'Ext.app.ViewController',
openTask: function(record) {
let me = this;
let view = me.getView();
Ext.create('Proxmox.window.TaskViewer', {
upid: record.data.upid,
endtime: record.data.endtime,
}).show();
},
openTaskItemDblClick: function(grid, record) {
this.openTask(record);
},
openTaskActionColumn: function(grid, rowIndex) {
this.openTask(grid.getStore().getAt(rowIndex));
},
render_status: function(value) {
let cls = 'times-circle critical';
if (value === 'OK') {
cls = 'check-circle good';
} else if (value.startsWith('WARNINGS:')) {
cls = 'exclamation-circle warning';
} else if (value === 'unknown') {
cls = 'question-circle faded';
}
return `<i class="fa fa-${cls}"></i>`;
},
},
updateTasks: function(data) {
let me = this;
me.getStore().setData(data);
},
listeners: {
itemdblclick: 'openTaskItemDblClick',
},
store: {
type: 'diff',
autoDestroy: true,
autoDestroyRstore: true,
sorters: {
property: 'duration',
direction: 'DESC',
},
rstore: {
storeid: 'proxmox-tasks-dash',
type: 'store',
model: 'proxmox-tasks',
proxy: {
type: 'memory',
}
},
},
columns: [
{
text: gettext('Task'),
dataIndex: 'upid',
renderer: Proxmox.Utils.render_upid,
flex: 1,
},
{
text: gettext('Duration'),
dataIndex: 'duration',
renderer: Proxmox.Utils.format_duration_human,
},
{
text: gettext('Status'),
align: 'center',
width: 40,
dataIndex: 'status',
renderer: 'render_status',
},
{
xtype: 'actioncolumn',
width: 40,
items: [
{
iconCls: 'fa fa-chevron-right',
tooltip: gettext('Open Task'),
handler: 'openTaskActionColumn',
},
],
},
],
});

View File

@ -0,0 +1,108 @@
Ext.define('PBS.RunningTasks', {
extend: 'Ext.grid.Panel',
alias: 'widget.pbsRunningTasks',
title: gettext('Running Tasks'),
emptyText: gettext('No running tasks'),
hideHeaders: true,
rowLines: false,
controller: {
xclass: 'Ext.app.ViewController',
openTask: function(record) {
let me = this;
let view = me.getView();
Ext.create('Proxmox.window.TaskViewer', {
upid: record.data.upid,
endtime: record.data.endtime,
}).show();
},
openTaskItemDblClick: function(grid, record) {
this.openTask(record);
},
openTaskActionColumn: function(grid, rowIndex) {
this.openTask(grid.getStore().getAt(rowIndex));
},
render_status: function(value) {
let cls = 'times-circle critical';
if (value === 'OK') {
cls = 'check-circle good';
} else if (value.startsWith('WARNINGS:')) {
cls = 'exclamation-circle warning';
} else if (value === 'unknown') {
cls = 'question-circle faded';
}
return `<i class="fa fa-${cls}"></i>`;
},
},
updateTasks: function(data) {
let me = this;
me.getStore().setData(data);
},
listeners: {
itemdblclick: 'openTaskItemDblClick',
},
store: {
type: 'diff',
autoDestroy: true,
autoDestroyRstore: true,
sorters: 'starttime',
rstore: {
type: 'update',
autoStart: true,
interval: 3000,
storeid: 'pbs-running-tasks-dash',
model: 'proxmox-tasks',
proxy: {
type: 'proxmox',
// maybe separate api call?
url: '/api2/json/nodes/localhost/tasks?running=1'
},
},
},
columns: [
{
text: 'Task',
dataIndex: 'upid',
renderer: Proxmox.Utils.render_upid,
flex: 2,
},
{
text: 'Starttime',
dataIndex: 'starttime',
renderer: function(value) {
return Ext.Date.format(value, "Y-m-d H:i:s");
},
flex: 1,
},
{
text: 'Duration',
dataIndex: 'duration',
renderer: function(value, md, record) {
return Proxmox.Utils.format_duration_human((Date.now() - record.data.starttime)/1000);
}
},
{
xtype: 'actioncolumn',
width: 40,
items: [
{
iconCls: 'fa fa-chevron-right',
tooltip: gettext('Open Task'),
handler: 'openTaskActionColumn',
},
],
},
],
});

View File

@ -0,0 +1,81 @@
Ext.define('PBS.TaskSummary', {
extend: 'Ext.panel.Panel',
alias: 'widget.pbsTaskSummary',
title: gettext('Task Summary (last Month)'),
controller: {
xclass: 'Ext.app.ViewController',
render_count: function(value, md, record, rowindex, colindex) {
let cls = 'question';
switch (colindex) {
case 1: cls = "times-circle critical"; break;
case 2: cls = "exclamation-circle warning"; break;
case 3: cls = "check-circle good"; break;
default: break;
}
return `<i class="fa fa-${cls}"></i> ${value}`;
},
},
updateTasks: function(data) {
let me = this;
data.backup.type = gettext('Backups');
data.prune.type = gettext('Prunes');
data.garbage_collection.type = gettext('Garbage collections');
data.sync.type = gettext('Syncs');
me.lookup('grid').getStore().setData([
data.backup,
data.prune,
data.garbage_collection,
data.sync,
]);
},
layout: 'fit',
bodyPadding: 15,
minHeight: 166,
// we have to wrap the grid in a panel to get the padding right
items: [
{
xtype: 'grid',
reference: 'grid',
hideHeaders: true,
border: false,
bodyBorder: false,
rowLines: false,
viewConfig: {
stripeRows: false,
trackOver: false,
},
scrollable: false,
disableSelection: true,
store: {
data: []
},
columns: [
{
dataIndex: 'type',
flex: 1,
},
{
dataIndex: 'error',
renderer: 'render_count',
},
{
dataIndex: 'warning',
renderer: 'render_count',
},
{
dataIndex: 'ok',
renderer: 'render_count',
},
],
}
],
});