Ext.define('PBS.Dashboard', { extend: 'Ext.panel.Panel', xtype: 'pbsDashboard', controller: { xclass: 'Ext.app.ViewController', openDashboardOptions: function() { var me = this; var viewModel = me.getViewModel(); Ext.create('Ext.window.Window', { modal: true, width: 300, title: gettext('Dashboard Options'), layout: { type: 'auto', }, items: [{ xtype: 'form', bodyPadding: '10 10 10 10', defaultButton: 'savebutton', items: [{ xtype: 'proxmoxintegerfield', itemId: 'days', labelWidth: 100, anchor: '100%', allowBlank: false, minValue: 1, maxValue: 60, value: viewModel.get('days'), fieldLabel: gettext('Days to show'), }], buttons: [{ text: gettext('Save'), reference: 'savebutton', formBind: true, handler: function() { var win = this.up('window'); var days = win.down('#days').getValue(); me.setDays(days, true); win.close(); }, }], }], }).show(); }, setDays: function(days, setState) { var me = this; var viewModel = me.getViewModel(); viewModel.set('days', days); viewModel.notify(); viewModel.getStore('tasks').reload(); if (setState) { var sp = Ext.state.Manager.getProvider(); sp.set('dashboard-days', days); } }, updateRepositoryStatus: function(store, records, success) { if (!success) { return; } let me = this; me.lookup('nodeInfo').setRepositoryInfo(records[0].data['standard-repos']); }, updateSubscription: function(store, records, success) { if (!success) { return; } let me = this; let status = records[0].data.status || 'unknown'; // 2 = all good, 1 = different leves, 0 = none let subStatus = status.toLowerCase() === 'active' ? 2 : 0; me.lookup('subscription').setSubStatus(subStatus); me.lookup('nodeInfo').setSubscriptionStatus(subStatus); }, updateTasks: function(store, records, success) { if (!success) return; let me = this; let viewModel = me.getViewModel(); records.sort((a, b) => a.data.duration - b.data.duration); let top10 = records.slice(-10); me.lookup('longesttasks').updateTasks(top10); let data = { backup: { error: 0, warning: 0, ok: 0 }, prune: { error: 0, warning: 0, ok: 0 }, garbage_collection: { error: 0, warning: 0, ok: 0 }, sync: { error: 0, warning: 0, ok: 0 }, verify: { error: 0, warning: 0, ok: 0 }, }; records.forEach(record => { let task = record.data; let type = task.worker_type; if (type === 'syncjob') { type = 'sync'; } if (type.startsWith('verif')) { type = 'verify'; } if (data[type] && task.status) { let parsed = Proxmox.Utils.parse_task_status(task.status); data[type][parsed]++; } }); me.lookup('tasksummary').updateTasks(data, viewModel.get('sinceEpoch')); }, init: function(view) { var me = this; var sp = Ext.state.Manager.getProvider(); var days = sp.get('dashboard-days') || 30; me.setDays(days, false); view.mon(sp, 'statechange', function(provider, key, value) { if (key !== 'summarycolumns') { return; } Proxmox.Utils.updateColumns(view); }); }, }, viewModel: { data: { days: 30, }, formulas: { sinceEpoch: (get) => (Date.now()/1000 - get('days') * 24*3600).toFixed(0), }, stores: { repositories: { storeid: 'dash-repositories', type: 'update', interval: 15000, autoStart: true, autoLoad: true, autoDestroy: true, proxy: { type: 'proxmox', url: '/api2/json/nodes/localhost/apt/repositories', }, listeners: { load: 'updateRepositoryStatus', }, }, subscription: { storeid: 'dash-subscription', type: 'update', interval: 10000, autoStart: true, autoLoad: true, autoDestroy: true, proxy: { type: 'proxmox', url: '/api2/json/nodes/localhost/subscription', }, listeners: { load: 'updateSubscription', }, }, tasks: { storeid: 'dash-tasks', type: 'update', interval: 15000, autoStart: true, autoLoad: true, autoDestroy: true, model: 'proxmox-tasks', proxy: { type: 'proxmox', url: '/api2/json/nodes/localhost/tasks', extraParams: { limit: 0, since: '{sinceEpoch}', }, }, listeners: { load: 'updateTasks', }, }, }, }, listeners: { resize: function(panel) { Proxmox.Utils.updateColumns(panel); }, }, title: gettext('Dashboard'), layout: { type: 'column', }, bodyPadding: '20 0 0 20', minWidth: 700, defaults: { columnWidth: 0.49, xtype: 'panel', margin: '0 20 20 0', }, tools: [ { type: 'gear', tooltip: gettext('Edit dashboard settings'), handler: 'openDashboardOptions', }, ], scrollable: true, items: [ { xtype: 'pbsNodeInfoPanel', reference: 'nodeInfo', height: 280, }, { xtype: 'pbsDatastoresStatistics', height: 280, }, { xtype: 'pbsLongestTasks', bind: { title: gettext('Longest Tasks') + ' (' + Ext.String.format(gettext('{0} days'), '{days}') + ')', }, reference: 'longesttasks', height: 250, }, { xtype: 'pbsRunningTasks', height: 250, }, { bind: { title: gettext('Task Summary') + ' (' + Ext.String.format(gettext('{0} days'), '{days}') + ')', }, xtype: 'pbsTaskSummary', height: 200, reference: 'tasksummary', }, { iconCls: 'fa fa-ticket', title: 'Subscription', height: 200, reference: 'subscription', xtype: 'pbsSubscriptionInfo', }, ], }); Ext.define('PBS.dashboard.SubscriptionInfo', { extend: 'Ext.panel.Panel', xtype: 'pbsSubscriptionInfo', style: { cursor: 'pointer', }, layout: { type: 'hbox', align: 'middle', }, items: [ { xtype: 'box', itemId: 'icon', data: { icon: 'question-circle', }, width: 100, tpl: '