2020-10-30 14:02:15 +00:00
|
|
|
Ext.define('PBS.node.Tasks', {
|
|
|
|
extend: 'Ext.grid.GridPanel',
|
|
|
|
|
|
|
|
alias: 'widget.pbsNodeTasks',
|
|
|
|
|
|
|
|
stateful: true,
|
|
|
|
stateId: 'pbs-grid-node-tasks',
|
|
|
|
|
|
|
|
loadMask: true,
|
|
|
|
sortableColumns: false,
|
|
|
|
|
|
|
|
controller: {
|
|
|
|
xclass: 'Ext.app.ViewController',
|
|
|
|
|
|
|
|
showTaskLog: function() {
|
|
|
|
let me = this;
|
|
|
|
let selection = me.getView().getSelection();
|
|
|
|
if (selection.length < 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let rec = selection[0];
|
|
|
|
|
|
|
|
Ext.create('Proxmox.window.TaskViewer', {
|
|
|
|
upid: rec.data.upid,
|
|
|
|
endtime: rec.data.endtime,
|
|
|
|
}).show();
|
|
|
|
},
|
|
|
|
|
|
|
|
updateLayout: function() {
|
|
|
|
let me = this;
|
|
|
|
// we want to update the scrollbar on every store load
|
|
|
|
// since the total count might be different
|
|
|
|
// the buffered grid plugin does this only on scrolling itself
|
|
|
|
// and even reduces the scrollheight again when scrolling up
|
|
|
|
me.getView().updateLayout();
|
|
|
|
},
|
|
|
|
|
|
|
|
sinceChange: function(field, newval) {
|
|
|
|
let me = this;
|
|
|
|
let vm = me.getViewModel();
|
|
|
|
|
|
|
|
vm.set('since', newval);
|
|
|
|
},
|
|
|
|
|
|
|
|
untilChange: function(field, newval, oldval) {
|
|
|
|
let me = this;
|
|
|
|
let vm = me.getViewModel();
|
|
|
|
|
|
|
|
vm.set('until', newval);
|
|
|
|
},
|
|
|
|
|
|
|
|
reload: function() {
|
|
|
|
let me = this;
|
|
|
|
let view = me.getView();
|
|
|
|
view.getStore().load();
|
|
|
|
},
|
|
|
|
|
|
|
|
showFilter: function(btn, pressed) {
|
|
|
|
let me = this;
|
|
|
|
let vm = me.getViewModel();
|
|
|
|
vm.set('showFilter', pressed);
|
|
|
|
},
|
|
|
|
|
|
|
|
init: function(view) {
|
|
|
|
let me = this;
|
|
|
|
Proxmox.Utils.monStoreErrors(view, view.getStore(), true);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
listeners: {
|
|
|
|
itemdblclick: 'showTaskLog',
|
|
|
|
},
|
|
|
|
|
|
|
|
viewModel: {
|
|
|
|
data: {
|
|
|
|
typefilter: '',
|
|
|
|
statusfilter: '',
|
|
|
|
datastore: '',
|
|
|
|
showFilter: false,
|
|
|
|
since: null,
|
|
|
|
until: null,
|
|
|
|
},
|
|
|
|
|
|
|
|
formulas: {
|
2020-11-03 13:49:04 +00:00
|
|
|
filterIcon: (get) => 'fa fa-filter' + (get('showFilter') ? ' info-blue' : ''),
|
2020-10-30 14:02:15 +00:00
|
|
|
extraParams: function(get) {
|
|
|
|
let me = this;
|
|
|
|
let params = {};
|
|
|
|
if (get('typefilter')) {
|
|
|
|
params.typefilter = get('typefilter');
|
|
|
|
}
|
|
|
|
if (get('statusfilter')) {
|
|
|
|
params.statusfilter = get('statusfilter');
|
|
|
|
}
|
|
|
|
if (get('datastore')) {
|
|
|
|
params.store = get('datastore');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (get('since')) {
|
|
|
|
params.since = get('since').valueOf()/1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (get('until')) {
|
|
|
|
let until = new Date(get('until').getTime()); // copy object
|
|
|
|
until.setDate(until.getDate() + 1); // end of the day
|
|
|
|
params.until = until.valueOf()/1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
me.getView().getStore().load();
|
|
|
|
|
|
|
|
return params;
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
stores: {
|
|
|
|
bufferedstore: {
|
|
|
|
type: 'buffered',
|
|
|
|
pageSize: 500,
|
|
|
|
autoLoad: true,
|
|
|
|
remoteFilter: true,
|
|
|
|
model: 'proxmox-tasks',
|
|
|
|
proxy: {
|
|
|
|
type: 'proxmox',
|
|
|
|
startParam: 'start',
|
|
|
|
limitParam: 'limit',
|
|
|
|
extraParams: '{extraParams}',
|
|
|
|
url: "/api2/json/nodes/localhost/tasks",
|
|
|
|
},
|
|
|
|
listeners: {
|
|
|
|
prefetch: 'updateLayout',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
bind: {
|
|
|
|
store: '{bufferedstore}',
|
|
|
|
},
|
|
|
|
|
|
|
|
dockedItems: [
|
|
|
|
{
|
|
|
|
xtype: 'toolbar',
|
|
|
|
items: [
|
|
|
|
{
|
|
|
|
xtype: 'proxmoxButton',
|
|
|
|
text: gettext('View'),
|
2020-11-03 13:49:04 +00:00
|
|
|
iconCls: 'fa fa-window-restore',
|
2020-10-30 14:02:15 +00:00
|
|
|
disabled: true,
|
|
|
|
handler: 'showTaskLog',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
xtype: 'button',
|
|
|
|
text: gettext('Reload'),
|
2020-11-03 13:49:04 +00:00
|
|
|
iconCls: 'fa fa-refresh',
|
2020-10-30 14:02:15 +00:00
|
|
|
handler: 'reload',
|
|
|
|
},
|
|
|
|
'->',
|
|
|
|
{
|
|
|
|
xtype: 'button',
|
|
|
|
enableToggle: true,
|
2020-11-03 13:49:04 +00:00
|
|
|
bind: {
|
|
|
|
iconCls: '{filterIcon}',
|
|
|
|
},
|
2020-10-30 14:02:15 +00:00
|
|
|
text: gettext('Filter'),
|
|
|
|
stateful: true,
|
|
|
|
stateId: 'task-showfilter',
|
|
|
|
stateEvents: ['toggle'],
|
|
|
|
applyState: function(state) {
|
|
|
|
if (state.pressed !== undefined) {
|
|
|
|
this.setPressed(state.pressed);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
getState: function() {
|
|
|
|
return {
|
|
|
|
pressed: this.pressed,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
listeners: {
|
|
|
|
toggle: 'showFilter',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
xtype: 'toolbar',
|
|
|
|
dock: 'top',
|
|
|
|
layout: {
|
|
|
|
type: 'hbox',
|
|
|
|
align: 'top',
|
|
|
|
},
|
|
|
|
bind: {
|
|
|
|
hidden: '{!showFilter}',
|
|
|
|
},
|
|
|
|
items: [
|
|
|
|
{
|
|
|
|
xtype: 'container',
|
|
|
|
padding: 10,
|
|
|
|
layout: {
|
|
|
|
type: 'vbox',
|
|
|
|
align: 'stretch',
|
|
|
|
},
|
2020-11-03 13:47:59 +00:00
|
|
|
defaults: {
|
|
|
|
labelWidth: 80,
|
|
|
|
},
|
|
|
|
// cannot bind the values directly, as it then changes also
|
|
|
|
// on blur, causing wrong reloads of the store
|
2020-10-30 14:02:15 +00:00
|
|
|
items: [
|
|
|
|
{
|
2020-11-03 13:47:59 +00:00
|
|
|
xtype: 'datefield',
|
|
|
|
fieldLabel: gettext('Since'),
|
|
|
|
format: 'Y-m-d',
|
2020-10-30 14:02:15 +00:00
|
|
|
bind: {
|
2020-11-03 13:47:59 +00:00
|
|
|
maxValue: '{until}',
|
|
|
|
},
|
|
|
|
listeners: {
|
|
|
|
change: 'sinceChange',
|
2020-10-30 14:02:15 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2020-11-03 13:47:59 +00:00
|
|
|
xtype: 'datefield',
|
|
|
|
fieldLabel: gettext('Until'),
|
|
|
|
format: 'Y-m-d',
|
|
|
|
bind: {
|
|
|
|
minValue: '{since}',
|
|
|
|
},
|
|
|
|
listeners: {
|
|
|
|
change: 'untilChange',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
xtype: 'container',
|
|
|
|
padding: 10,
|
|
|
|
layout: {
|
|
|
|
type: 'vbox',
|
|
|
|
align: 'stretch',
|
|
|
|
},
|
|
|
|
defaults: {
|
|
|
|
labelWidth: 80,
|
|
|
|
},
|
|
|
|
items: [
|
|
|
|
{
|
|
|
|
xtype: 'pmxTaskTypeSelector',
|
|
|
|
fieldLabel: gettext('Task Type'),
|
2020-10-30 14:02:15 +00:00
|
|
|
emptyText: gettext('All'),
|
|
|
|
bind: {
|
2020-11-03 13:47:59 +00:00
|
|
|
value: '{typefilter}',
|
2020-10-30 14:02:15 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
xtype: 'combobox',
|
2020-11-03 13:47:59 +00:00
|
|
|
fieldLabel: gettext('Task Result'),
|
2020-10-30 14:02:15 +00:00
|
|
|
emptyText: gettext('All'),
|
2020-11-03 13:47:59 +00:00
|
|
|
multiSelect: true,
|
2020-10-30 14:02:15 +00:00
|
|
|
store: [
|
2020-11-03 13:47:59 +00:00
|
|
|
['ok', gettext('OK')],
|
|
|
|
['unknown', Proxmox.Utils.unknownText],
|
|
|
|
['warning', gettext('Warnings')],
|
|
|
|
['error', gettext('Errors')],
|
2020-10-30 14:02:15 +00:00
|
|
|
],
|
|
|
|
bind: {
|
|
|
|
value: '{statusfilter}',
|
|
|
|
},
|
|
|
|
},
|
2020-11-03 13:47:59 +00:00
|
|
|
],
|
2020-10-30 14:02:15 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
xtype: 'container',
|
|
|
|
padding: 10,
|
|
|
|
layout: {
|
|
|
|
type: 'vbox',
|
|
|
|
align: 'stretch',
|
|
|
|
},
|
2020-11-03 13:47:59 +00:00
|
|
|
defaults: {
|
|
|
|
labelWidth: 80,
|
|
|
|
},
|
2020-10-30 14:02:15 +00:00
|
|
|
items: [
|
|
|
|
{
|
2020-11-03 13:47:59 +00:00
|
|
|
xtype: 'pbsDataStoreSelector',
|
|
|
|
fieldLabel: gettext('Datastore'),
|
|
|
|
emptyText: gettext('All'),
|
2020-10-30 14:02:15 +00:00
|
|
|
bind: {
|
2020-11-03 13:47:59 +00:00
|
|
|
value: '{datastore}',
|
2020-10-30 14:02:15 +00:00
|
|
|
},
|
2020-11-03 13:47:59 +00:00
|
|
|
allowBlank: true,
|
2020-10-30 14:02:15 +00:00
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
2020-11-03 13:47:59 +00:00
|
|
|
],
|
2020-10-30 14:02:15 +00:00
|
|
|
},
|
|
|
|
],
|
|
|
|
|
|
|
|
viewConfig: {
|
|
|
|
trackOver: false,
|
|
|
|
stripeRows: false, // does not work with getRowClass()
|
|
|
|
emptyText: gettext('No Tasks found'),
|
|
|
|
|
|
|
|
getRowClass: function(record, index) {
|
|
|
|
let status = record.get('status');
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
let parsed = Proxmox.Utils.parse_task_status(status);
|
|
|
|
if (parsed === 'error') {
|
|
|
|
return "proxmox-invalid-row";
|
|
|
|
} else if (parsed === 'warning') {
|
|
|
|
return "proxmox-warning-row";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return '';
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
columns: [
|
|
|
|
{
|
|
|
|
header: gettext("Start Time"),
|
|
|
|
dataIndex: 'starttime',
|
|
|
|
width: 130,
|
|
|
|
renderer: function(value) {
|
|
|
|
return Ext.Date.format(value, "M d H:i:s");
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
header: gettext("End Time"),
|
|
|
|
dataIndex: 'endtime',
|
|
|
|
width: 130,
|
|
|
|
renderer: function(value, metaData, record) {
|
|
|
|
if (!value) {
|
|
|
|
metaData.tdCls = "x-grid-row-loading";
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
return Ext.Date.format(value, "M d H:i:s");
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
header: gettext("Duration"),
|
|
|
|
hidden: true,
|
|
|
|
width: 80,
|
|
|
|
renderer: function(value, metaData, record) {
|
|
|
|
let start = record.data.starttime;
|
|
|
|
if (start) {
|
|
|
|
let end = record.data.endtime || Date.now();
|
|
|
|
let duration = end - start;
|
|
|
|
if (duration > 0) {
|
|
|
|
duration /= 1000;
|
|
|
|
}
|
|
|
|
return Proxmox.Utils.format_duration_human(duration);
|
|
|
|
}
|
|
|
|
return Proxmox.Utils.unknownText;
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
header: gettext("User name"),
|
|
|
|
dataIndex: 'user',
|
|
|
|
width: 150,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
header: gettext("Description"),
|
|
|
|
dataIndex: 'upid',
|
|
|
|
flex: 1,
|
|
|
|
renderer: Proxmox.Utils.render_upid,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
header: gettext("Status"),
|
|
|
|
dataIndex: 'status',
|
|
|
|
width: 200,
|
|
|
|
renderer: function(value, metaData, record) {
|
|
|
|
if (value === undefined && !record.data.endtime) {
|
|
|
|
metaData.tdCls = "x-grid-row-loading";
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
let parsed = Proxmox.Utils.parse_task_status(value);
|
|
|
|
switch (parsed) {
|
|
|
|
case 'unknown': return Proxmox.Utils.unknownText;
|
|
|
|
case 'error': return Proxmox.Utils.errorText + ': ' + value;
|
|
|
|
case 'ok': // fall-through
|
|
|
|
case 'warning': // fall-through
|
|
|
|
default: return value;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
});
|