mirror of
https://git.proxmox.com/git/pmg-gui
synced 2025-05-29 10:43:41 +00:00
495 lines
10 KiB
JavaScript
495 lines
10 KiB
JavaScript
Ext.define('PMG.Dashboard', {
|
|
extend: 'Ext.panel.Panel',
|
|
xtype: 'pmgDashboard',
|
|
|
|
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: 'hours',
|
|
labelWidth: 100,
|
|
anchor: '100%',
|
|
allowBlank: false,
|
|
minValue: 1,
|
|
maxValue: 24,
|
|
value: viewModel.get('hours'),
|
|
fieldLabel: gettext('Hours to show'),
|
|
}],
|
|
buttons: [{
|
|
text: gettext('Save'),
|
|
reference: 'loginButton',
|
|
formBind: true,
|
|
handler: function() {
|
|
var win = this.up('window');
|
|
var hours = win.down('#hours').getValue();
|
|
me.setHours(hours, true);
|
|
win.close();
|
|
},
|
|
}],
|
|
}],
|
|
}).show();
|
|
},
|
|
|
|
setHours: function(hours, setState) {
|
|
var me = this;
|
|
var viewModel = me.getViewModel();
|
|
viewModel.set('hours', hours);
|
|
viewModel.notify();
|
|
|
|
Ext.Array.forEach(['recentmails', 'receivers'], function(item) {
|
|
viewModel.getStore(item).reload();
|
|
});
|
|
|
|
if (setState) {
|
|
var sp = Ext.state.Manager.getProvider();
|
|
sp.set('dashboard-hours', hours);
|
|
}
|
|
},
|
|
|
|
updateMailStats: function(store, records, success) {
|
|
if (!success) {
|
|
return;
|
|
}
|
|
var me = this;
|
|
var viewModel = me.getViewModel();
|
|
|
|
var count = 0;
|
|
var bytes_in = 0;
|
|
var bytes_out = 0;
|
|
var ptime = 0;
|
|
var avg_ptime = 'N/A';
|
|
|
|
records.forEach(function(item) {
|
|
bytes_in += item.data.bytes_in;
|
|
bytes_out += item.data.bytes_out;
|
|
// unnormalize
|
|
count += (item.data.count*item.data.timespan)/60;
|
|
ptime += item.data.ptimesum;
|
|
});
|
|
|
|
if (count) {
|
|
avg_ptime = (ptime/count).toFixed(2) + " s";
|
|
}
|
|
|
|
viewModel.set('bytes_in', Proxmox.Utils.format_size(bytes_in));
|
|
viewModel.set('bytes_out', Proxmox.Utils.format_size(bytes_out));
|
|
viewModel.set('avg_ptime', avg_ptime);
|
|
},
|
|
|
|
updateClusterStats: function(store, records, success) {
|
|
if (!success) {
|
|
return;
|
|
}
|
|
var me = this;
|
|
var viewmodel = me.getViewModel();
|
|
|
|
var subStatus = 2; // 2 = all good, 1 = different leves, 0 = none
|
|
var subLevel = "";
|
|
|
|
var cpu = 0;
|
|
var mem = 0;
|
|
var hd = 0;
|
|
var count = records.length;
|
|
var errors = [];
|
|
|
|
records.forEach(function(item) {
|
|
// subscription level check
|
|
if (subStatus && item.data.level) {
|
|
if (subLevel !== "" && subLevel !== item.data.level) {
|
|
subStatus = 1;
|
|
} else if (subLevel === "") {
|
|
subLevel = item.data.level;
|
|
}
|
|
} else {
|
|
subStatus = 0;
|
|
}
|
|
|
|
// resources count
|
|
cpu += item.data.cpu || 0;
|
|
|
|
var memory = item.data.memory || { used: 0, total: 1 };
|
|
mem += memory.used/memory.total;
|
|
|
|
var rootfs = item.data.rootfs || { used: 0, total: 1 };
|
|
hd += rootfs.used/rootfs.total;
|
|
|
|
if (item.data.conn_error && count > 1) {
|
|
count--;
|
|
errors.push({
|
|
name: item.data.name,
|
|
msg: item.data.conn_error,
|
|
});
|
|
}
|
|
});
|
|
|
|
var subscriptionPanel = me.lookup('subscription');
|
|
subscriptionPanel.setSubStatus(subStatus);
|
|
|
|
me.lookup('nodeInfo').setSubscriptionStatus(subStatus);
|
|
|
|
// the node info already displays this information in case there is no cluster
|
|
me.lookup('clusterResources').setHidden(records.length === 1);
|
|
|
|
cpu = cpu/count;
|
|
mem = mem/count;
|
|
hd = hd/count;
|
|
|
|
var cpuPanel = me.lookup('cpu');
|
|
cpuPanel.updateValue(cpu);
|
|
|
|
var memPanel = me.lookup('mem');
|
|
memPanel.updateValue(mem);
|
|
|
|
var hdPanel = me.lookup('hd');
|
|
hdPanel.updateValue(hd);
|
|
|
|
if (errors.length && !viewmodel.get('error_shown')) {
|
|
var text = "";
|
|
errors.forEach(function(error) {
|
|
text += error.name + ':<br>' + error.msg + '<br>';
|
|
});
|
|
Ext.Msg.alert(gettext('Error'), text);
|
|
viewmodel.set('error_shown', true);
|
|
}
|
|
},
|
|
|
|
updateRepositoryStatus: function(store, records, success) {
|
|
if (!success) {
|
|
return;
|
|
}
|
|
|
|
let me = this;
|
|
me.lookup('nodeInfo').setRepositoryInfo(records[0].data['standard-repos']);
|
|
},
|
|
|
|
init: function(view) {
|
|
var me = this;
|
|
var sp = Ext.state.Manager.getProvider();
|
|
var hours = sp.get('dashboard-hours') || 12;
|
|
me.setHours(hours, false);
|
|
},
|
|
},
|
|
|
|
viewModel: {
|
|
data: {
|
|
timespan: 300, // in seconds
|
|
hours: 12, // in hours
|
|
error_shown: false,
|
|
'bytes_in': 0,
|
|
'bytes_out': 0,
|
|
'avg_ptime': 0.0,
|
|
},
|
|
|
|
stores: {
|
|
cluster: {
|
|
storeid: 'dash-cluster',
|
|
type: 'update',
|
|
interval: 5000,
|
|
autoStart: true,
|
|
autoDestroy: true,
|
|
proxy: {
|
|
extraParams: { list_single_node: 1 },
|
|
type: 'proxmox',
|
|
url: '/api2/json/config/cluster/status',
|
|
},
|
|
listeners: {
|
|
load: 'updateClusterStats',
|
|
},
|
|
},
|
|
recentmails: {
|
|
storeid: 'dash-recent',
|
|
interval: 5000,
|
|
type: 'update',
|
|
autoStart: true,
|
|
autoDestroy: true,
|
|
proxy: {
|
|
type: 'proxmox',
|
|
url: '/api2/json/statistics/recent',
|
|
extraParams: {
|
|
hours: '{hours}',
|
|
timespan: '{timespan}',
|
|
},
|
|
},
|
|
fields: [
|
|
{
|
|
type: 'number', name: 'count',
|
|
convert: PMG.Utils.convert_field_to_per_min,
|
|
},
|
|
{
|
|
type: 'number', name: 'count_in',
|
|
convert: PMG.Utils.convert_field_to_per_min,
|
|
},
|
|
{
|
|
type: 'number', name: 'count_out',
|
|
convert: PMG.Utils.convert_field_to_per_min,
|
|
},
|
|
{
|
|
type: 'number', name: 'spam',
|
|
convert: PMG.Utils.convert_field_to_per_min,
|
|
},
|
|
{
|
|
type: 'number', name: 'spam_in',
|
|
convert: PMG.Utils.convert_field_to_per_min,
|
|
},
|
|
{
|
|
type: 'number', name: 'spam_out',
|
|
convert: PMG.Utils.convert_field_to_per_min,
|
|
},
|
|
{
|
|
type: 'number', name: 'virus',
|
|
convert: PMG.Utils.convert_field_to_per_min,
|
|
},
|
|
{
|
|
type: 'number', name: 'virus_in',
|
|
convert: PMG.Utils.convert_field_to_per_min,
|
|
},
|
|
{ type: 'integer', name: 'virus_out' },
|
|
{ type: 'integer', name: 'bytes_in' },
|
|
{ type: 'integer', name: 'bytes_out' },
|
|
{ type: 'number', name: 'ptimesum' },
|
|
{ type: 'date', dateFormat: 'timestamp', name: 'time' },
|
|
],
|
|
listeners: {
|
|
load: 'updateMailStats',
|
|
},
|
|
},
|
|
receivers: {
|
|
storeid: 'dash-receivers',
|
|
interval: 10000,
|
|
type: 'update',
|
|
autoStart: true,
|
|
autoDestroy: true,
|
|
proxy: {
|
|
type: 'proxmox',
|
|
url: '/api2/json/statistics/recentreceivers',
|
|
extraParams: {
|
|
hours: '{hours}',
|
|
},
|
|
},
|
|
fields: [
|
|
{ type: 'integer', name: 'count' },
|
|
{ type: 'string', name: 'receiver' },
|
|
],
|
|
},
|
|
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',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
bind: {
|
|
title: gettext('Dashboard') + ' (' +
|
|
Ext.String.format(gettext('{0} hours'), '{hours}') + ')',
|
|
},
|
|
|
|
layout: {
|
|
type: 'column',
|
|
},
|
|
border: false,
|
|
|
|
bodyPadding: '20 0 0 20',
|
|
|
|
defaults: {
|
|
columnWidth: 0.5,
|
|
xtype: 'panel',
|
|
margin: '0 20 20 0',
|
|
},
|
|
|
|
tools: [
|
|
{
|
|
type: 'gear',
|
|
handler: 'openDashboardOptions',
|
|
},
|
|
],
|
|
|
|
scrollable: true,
|
|
|
|
items: [
|
|
{
|
|
height: 300,
|
|
flex: 1,
|
|
iconCls: 'fa fa-tachometer',
|
|
title: gettext('E-Mail Volume'),
|
|
layout: {
|
|
type: 'vbox',
|
|
align: 'stretch',
|
|
},
|
|
defaults: {
|
|
xtype: 'pmgMiniGraph',
|
|
bind: {
|
|
store: '{recentmails}',
|
|
},
|
|
},
|
|
items: [
|
|
{
|
|
fields: ['count'],
|
|
fieldTitles: [gettext('Mails / min')],
|
|
seriesConfig: {
|
|
colors: ['#00617F'],
|
|
style: {
|
|
opacity: 0.60,
|
|
lineWidth: 1,
|
|
},
|
|
highlightCfg: {
|
|
opacity: 1,
|
|
scaling: 1,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
fields: ['spam'],
|
|
fieldTitles: [gettext('Spam / min')],
|
|
seriesConfig: {
|
|
colors: ['#E67300'],
|
|
style: {
|
|
opacity: 0.60,
|
|
lineWidth: 1,
|
|
},
|
|
highlightCfg: {
|
|
opacity: 1,
|
|
scaling: 1,
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
xtype: 'container',
|
|
height: 300,
|
|
layout: {
|
|
type: 'vbox',
|
|
align: 'stretch',
|
|
},
|
|
items: [
|
|
{
|
|
xtype: 'pmgMailProcessing',
|
|
title: gettext('E-Mail Processing'),
|
|
iconCls: 'fa fa-hourglass-half',
|
|
height: 180,
|
|
bind: {
|
|
data: {
|
|
'bytes_in': '{bytes_in}',
|
|
'bytes_out': '{bytes_out}',
|
|
'avg_ptime': '{avg_ptime}',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
iconCls: 'fa fa-ticket',
|
|
title: 'Subscription',
|
|
reference: 'subscription',
|
|
xtype: 'pmgSubscriptionInfo',
|
|
margin: '10 0 0 0',
|
|
height: 110,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
xtype: 'pmgNodeInfoPanel',
|
|
reference: 'nodeInfo',
|
|
height: 275,
|
|
bodyPadding: '15 5 15 5',
|
|
iconCls: 'fa fa-tasks',
|
|
},
|
|
{
|
|
height: 275,
|
|
iconCls: 'fa fa-list',
|
|
title: gettext('Top Receivers'),
|
|
|
|
bodyPadding: '20 20 20 20',
|
|
layout: {
|
|
type: 'vbox',
|
|
pack: 'center',
|
|
align: 'stretch',
|
|
},
|
|
items: [{
|
|
xtype: 'grid',
|
|
bind: {
|
|
store: '{receivers}',
|
|
},
|
|
emptyText: gettext('No data in database'),
|
|
// remove all borders/lines/headers
|
|
border: false,
|
|
bodyBorder: false,
|
|
hideHeaders: true,
|
|
header: false,
|
|
columnLines: false,
|
|
rowLines: false,
|
|
viewConfig: {
|
|
stripeRows: false,
|
|
},
|
|
columns: [
|
|
{
|
|
dataIndex: 'receiver',
|
|
flex: 1,
|
|
text: gettext('Receiver'),
|
|
},
|
|
{
|
|
dataIndex: 'count',
|
|
align: 'right',
|
|
text: gettext('Count'),
|
|
},
|
|
],
|
|
}],
|
|
},
|
|
{
|
|
height: 250,
|
|
iconCls: 'fa fa-tasks',
|
|
title: gettext('Cluster Resources (average)'),
|
|
reference: 'clusterResources',
|
|
hidden: true,
|
|
bodyPadding: '0 20 0 20',
|
|
layout: {
|
|
type: 'hbox',
|
|
align: 'center',
|
|
},
|
|
defaults: {
|
|
xtype: 'proxmoxGauge',
|
|
spriteFontSize: '20px',
|
|
flex: 1,
|
|
},
|
|
items: [
|
|
{
|
|
title: gettext('CPU'),
|
|
reference: 'cpu',
|
|
},
|
|
{
|
|
title: gettext('Memory'),
|
|
reference: 'mem',
|
|
},
|
|
{
|
|
title: gettext('Storage'),
|
|
reference: 'hd',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
});
|