]> git.proxmox.com Git - pmg-gui.git/blame - js/Dashboard.js
ui: trim whitespaces when adding a subscription key
[pmg-gui.git] / js / Dashboard.js
CommitLineData
5936e3ef
DC
1Ext.define('PMG.Dashboard', {
2 extend: 'Ext.panel.Panel',
3 xtype: 'pmgDashboard',
4
b047eec0
DC
5 controller: {
6 xclass: 'Ext.app.ViewController',
5936e3ef 7
b047eec0
DC
8 openDashboardOptions: function() {
9 var me = this;
10 var viewModel = me.getViewModel();
11 Ext.create('Ext.window.Window', {
12 modal: true,
13 width: 300,
14 title: gettext('Dashboard Options'),
15 layout: {
c87d46fb 16 type: 'auto',
b047eec0
DC
17 },
18 items: [{
19 xtype: 'form',
de0ebd99 20 bodyPadding: '10 10 10 10',
b047eec0
DC
21 defaultButton: 'savebutton',
22 items: [{
23 xtype: 'proxmoxintegerfield',
24 itemId: 'hours',
25 labelWidth: 100,
26 anchor: '100%',
27 allowBlank: false,
28 minValue: 1,
29 maxValue: 24,
30 value: viewModel.get('hours'),
c87d46fb 31 fieldLabel: gettext('Hours to show'),
b047eec0
DC
32 }],
33 buttons: [{
34 text: gettext('Save'),
35 reference: 'loginButton',
36 formBind: true,
37 handler: function() {
38 var win = this.up('window');
39 var hours = win.down('#hours').getValue();
40 me.setHours(hours, true);
41 win.close();
c87d46fb
TL
42 },
43 }],
44 }],
b047eec0
DC
45 }).show();
46 },
5936e3ef 47
b047eec0
DC
48 setHours: function(hours, setState) {
49 var me = this;
50 var viewModel = me.getViewModel();
51 viewModel.set('hours', hours);
52 viewModel.notify();
53
54 Ext.Array.forEach(['recentmails', 'receivers'], function(item) {
86109d3a 55 viewModel.getStore(item).reload();
b047eec0
DC
56 });
57
58 if (setState) {
59 var sp = Ext.state.Manager.getProvider();
60 sp.set('dashboard-hours', hours);
61 }
62 },
63
64 updateMailStats: function(store, records, success) {
65 if (!success) {
66 return;
67 }
68 var me = this;
69 var viewModel = me.getViewModel();
70
71 var count = 0;
72 var bytes_in = 0;
73 var bytes_out = 0;
74 var ptime = 0;
b6248f6e 75 var avg_ptime = 'N/A';
b047eec0
DC
76
77 records.forEach(function(item) {
78 bytes_in += item.data.bytes_in;
79 bytes_out += item.data.bytes_out;
b79fbba8
DC
80 // unnormalize
81 count += (item.data.count*item.data.timespan)/60;
b047eec0
DC
82 ptime += item.data.ptimesum;
83 });
84
85 if (count) {
b6248f6e 86 avg_ptime = (ptime/count).toFixed(2) + " s";
b047eec0
DC
87 }
88
89 viewModel.set('bytes_in', Proxmox.Utils.format_size(bytes_in));
90 viewModel.set('bytes_out', Proxmox.Utils.format_size(bytes_out));
b6248f6e 91 viewModel.set('avg_ptime', avg_ptime);
b047eec0
DC
92 },
93
94 updateClusterStats: function(store, records, success) {
95 if (!success) {
96 return;
97 }
98 var me = this;
99 var viewmodel = me.getViewModel();
100
101 var subStatus = 2; // 2 = all good, 1 = different leves, 0 = none
102 var subLevel = "";
103
104 var cpu = 0;
105 var mem = 0;
106 var hd = 0;
107 var count = records.length;
bb7ab2ba 108 var errors = [];
b047eec0
DC
109
110 records.forEach(function(item) {
111 // subscription level check
112 if (subStatus && item.data.level) {
113 if (subLevel !== "" && subLevel !== item.data.level) {
114 subStatus = 1;
115 } else if (subLevel === "") {
116 subLevel = item.data.level;
117 }
118 } else {
119 subStatus = 0;
120 }
121
a0a5f5cf 122 if (item.data.name === Proxmox.NodeName) {
48e23079
FE
123 let repoStatus = me.lookup('nodeInfo').down('#repositoryStatus');
124 repoStatus.setSubscriptionStatus(!!item.data.level);
a0a5f5cf
FE
125 }
126
b047eec0 127 // resources count
91c74e81
DC
128 cpu += item.data.cpu || 0;
129
130 var memory = item.data.memory || { used: 0, total: 1 };
c87d46fb 131 mem += memory.used/memory.total;
91c74e81
DC
132
133 var rootfs = item.data.rootfs || { used: 0, total: 1 };
c87d46fb 134 hd += rootfs.used/rootfs.total;
91c74e81 135
bb7ab2ba
DC
136 if (item.data.conn_error && count > 1) {
137 count--;
138 errors.push({
139 name: item.data.name,
c87d46fb 140 msg: item.data.conn_error,
bb7ab2ba
DC
141 });
142 }
b047eec0
DC
143 });
144
145 var subscriptionPanel = me.lookup('subscription');
146 subscriptionPanel.setSubStatus(subStatus);
147
91a4c642
FE
148 // the node info already displays this information in case there is no cluster
149 me.lookup('clusterResources').setHidden(records.length === 1);
150
b047eec0
DC
151 cpu = cpu/count;
152 mem = mem/count;
153 hd = hd/count;
154
155 var cpuPanel = me.lookup('cpu');
156 cpuPanel.updateValue(cpu);
157
131ba4f6 158 var memPanel = me.lookup('mem');
b047eec0
DC
159 memPanel.updateValue(mem);
160
131ba4f6 161 var hdPanel = me.lookup('hd');
b047eec0 162 hdPanel.updateValue(hd);
bb7ab2ba
DC
163
164 if (errors.length && !viewmodel.get('error_shown')) {
165 var text = "";
166 errors.forEach(function(error) {
167 text += error.name + ':<br>' + error.msg + '<br>';
168 });
169 Ext.Msg.alert(gettext('Error'), text);
170 viewmodel.set('error_shown', true);
171 }
b047eec0
DC
172 },
173
11eae1a0
FE
174 updateRepositoryStatus: function(store, records, success) {
175 if (!success) {
176 return;
177 }
178
179 let me = this;
48e23079
FE
180 let repoStatus = me.lookup('nodeInfo').down('#repositoryStatus');
181 repoStatus.setRepositoryInfo(records[0].data['standard-repos']);
11eae1a0
FE
182 },
183
b047eec0
DC
184 init: function(view) {
185 var me = this;
186 var sp = Ext.state.Manager.getProvider();
187 var hours = sp.get('dashboard-hours') || 12;
188 me.setHours(hours, false);
3f8d6457
DC
189
190 view.mon(sp, 'statechange', function(provider, key, value) {
191 if (key !== 'summarycolumns') {
192 return;
193 }
194 Proxmox.Utils.updateColumnWidth(view);
195 });
c87d46fb 196 },
b047eec0
DC
197 },
198
3f8d6457
DC
199 listeners: {
200 resize: panel => Proxmox.Utils.updateColumnWidth(panel),
201 },
202
b047eec0
DC
203 viewModel: {
204 data: {
205 timespan: 300, // in seconds
206 hours: 12, // in hours
bb7ab2ba 207 error_shown: false,
b047eec0
DC
208 'bytes_in': 0,
209 'bytes_out': 0,
c87d46fb 210 'avg_ptime': 0.0,
b047eec0
DC
211 },
212
213 stores: {
214 cluster: {
215 storeid: 'dash-cluster',
216 type: 'update',
217 interval: 5000,
218 autoStart: true,
b047eec0
DC
219 autoDestroy: true,
220 proxy: {
929f40ff 221 extraParams: { list_single_node: 1 },
b047eec0 222 type: 'proxmox',
c87d46fb 223 url: '/api2/json/config/cluster/status',
b047eec0
DC
224 },
225 listeners: {
c87d46fb
TL
226 load: 'updateClusterStats',
227 },
b047eec0
DC
228 },
229 recentmails: {
230 storeid: 'dash-recent',
231 interval: 5000,
232 type: 'update',
233 autoStart: true,
b047eec0
DC
234 autoDestroy: true,
235 proxy: {
236 type: 'proxmox',
237 url: '/api2/json/statistics/recent',
238 extraParams: {
239 hours: '{hours}',
c87d46fb
TL
240 timespan: '{timespan}',
241 },
b047eec0
DC
242 },
243 fields: [
b79fbba8
DC
244 {
245 type: 'number', name: 'count',
c87d46fb 246 convert: PMG.Utils.convert_field_to_per_min,
b79fbba8
DC
247 },
248 {
249 type: 'number', name: 'count_in',
c87d46fb 250 convert: PMG.Utils.convert_field_to_per_min,
b79fbba8
DC
251 },
252 {
253 type: 'number', name: 'count_out',
c87d46fb 254 convert: PMG.Utils.convert_field_to_per_min,
b79fbba8
DC
255 },
256 {
257 type: 'number', name: 'spam',
c87d46fb 258 convert: PMG.Utils.convert_field_to_per_min,
b79fbba8
DC
259 },
260 {
261 type: 'number', name: 'spam_in',
c87d46fb 262 convert: PMG.Utils.convert_field_to_per_min,
b79fbba8
DC
263 },
264 {
265 type: 'number', name: 'spam_out',
c87d46fb 266 convert: PMG.Utils.convert_field_to_per_min,
b79fbba8
DC
267 },
268 {
269 type: 'number', name: 'virus',
c87d46fb 270 convert: PMG.Utils.convert_field_to_per_min,
b79fbba8
DC
271 },
272 {
273 type: 'number', name: 'virus_in',
c87d46fb 274 convert: PMG.Utils.convert_field_to_per_min,
b79fbba8 275 },
b047eec0
DC
276 { type: 'integer', name: 'virus_out' },
277 { type: 'integer', name: 'bytes_in' },
278 { type: 'integer', name: 'bytes_out' },
279 { type: 'number', name: 'ptimesum' },
c87d46fb 280 { type: 'date', dateFormat: 'timestamp', name: 'time' },
b047eec0
DC
281 ],
282 listeners: {
c87d46fb
TL
283 load: 'updateMailStats',
284 },
b047eec0
DC
285 },
286 receivers: {
287 storeid: 'dash-receivers',
288 interval: 10000,
289 type: 'update',
290 autoStart: true,
b047eec0
DC
291 autoDestroy: true,
292 proxy: {
293 type: 'proxmox',
294 url: '/api2/json/statistics/recentreceivers',
295 extraParams: {
c87d46fb 296 hours: '{hours}',
a2afe563 297 limit: 10, // make this also configurable?
c87d46fb 298 },
b047eec0
DC
299 },
300 fields: [
301 { type: 'integer', name: 'count' },
c87d46fb
TL
302 { type: 'string', name: 'receiver' },
303 ],
304 },
11eae1a0
FE
305 repositories: {
306 storeid: 'dash-repositories',
307 type: 'update',
308 interval: 15000,
309 autoStart: true,
310 autoLoad: true,
311 autoDestroy: true,
312 proxy: {
313 type: 'proxmox',
314 url: '/api2/json/nodes/localhost/apt/repositories',
315 },
316 listeners: {
317 load: 'updateRepositoryStatus',
318 },
319 },
c87d46fb 320 },
b047eec0
DC
321 },
322
323 bind: {
324 title: gettext('Dashboard') + ' (' +
c87d46fb 325 Ext.String.format(gettext('{0} hours'), '{hours}') + ')',
b047eec0
DC
326 },
327
de0ebd99 328 layout: {
c87d46fb 329 type: 'column',
de0ebd99 330 },
b047eec0
DC
331 border: false,
332
333 bodyPadding: '20 0 0 20',
334
335 defaults: {
3f8d6457 336 columnWidth: 1,
b047eec0 337 xtype: 'panel',
c87d46fb 338 margin: '0 20 20 0',
b047eec0
DC
339 },
340
341 tools: [
342 {
343 type: 'gear',
c87d46fb
TL
344 handler: 'openDashboardOptions',
345 },
b047eec0
DC
346 ],
347
348 scrollable: true,
349
350 items: [
351 {
352 height: 300,
353 flex: 1,
354 iconCls: 'fa fa-tachometer',
355 title: gettext('E-Mail Volume'),
356 layout: {
357 type: 'vbox',
c87d46fb 358 align: 'stretch',
b047eec0
DC
359 },
360 defaults: {
361 xtype: 'pmgMiniGraph',
362 bind: {
c87d46fb
TL
363 store: '{recentmails}',
364 },
b047eec0
DC
365 },
366 items: [
367 {
368 fields: ['count'],
c87d46fb 369 fieldTitles: [gettext('Mails / min')],
b047eec0 370 seriesConfig: {
c87d46fb 371 colors: ['#00617F'],
b047eec0
DC
372 style: {
373 opacity: 0.60,
c87d46fb 374 lineWidth: 1,
b047eec0
DC
375 },
376 highlightCfg: {
377 opacity: 1,
c87d46fb
TL
378 scaling: 1,
379 },
380 },
b047eec0
DC
381 },
382 {
383 fields: ['spam'],
c87d46fb 384 fieldTitles: [gettext('Spam / min')],
b047eec0 385 seriesConfig: {
c87d46fb 386 colors: ['#E67300'],
b047eec0
DC
387 style: {
388 opacity: 0.60,
c87d46fb 389 lineWidth: 1,
b047eec0
DC
390 },
391 highlightCfg: {
392 opacity: 1,
c87d46fb
TL
393 scaling: 1,
394 },
395 },
396 },
397 ],
b047eec0
DC
398 },
399 {
400 xtype: 'container',
401 height: 300,
402 layout: {
403 type: 'vbox',
c87d46fb 404 align: 'stretch',
b047eec0
DC
405 },
406 items: [
407 {
408 xtype: 'pmgMailProcessing',
409 title: gettext('E-Mail Processing'),
410 iconCls: 'fa fa-hourglass-half',
411 height: 180,
412 bind: {
413 data: {
7b18f75e
DC
414 'bytes_in': '{bytes_in}',
415 'bytes_out': '{bytes_out}',
c87d46fb
TL
416 'avg_ptime': '{avg_ptime}',
417 },
418 },
b047eec0
DC
419 },
420 {
421 iconCls: 'fa fa-ticket',
f334aeb0 422 title: gettext('Subscription'),
b047eec0
DC
423 reference: 'subscription',
424 xtype: 'pmgSubscriptionInfo',
425 margin: '10 0 0 0',
c87d46fb
TL
426 height: 110,
427 },
428 ],
b047eec0 429 },
11eae1a0
FE
430 {
431 xtype: 'pmgNodeInfoPanel',
432 reference: 'nodeInfo',
95288fa8 433 height: 300,
9b7b0553 434 bodyPadding: '15 5 15 5',
11eae1a0
FE
435 iconCls: 'fa fa-tasks',
436 },
b047eec0 437 {
95288fa8 438 height: 300,
b047eec0
DC
439 iconCls: 'fa fa-list',
440 title: gettext('Top Receivers'),
441
a2afe563 442 bodyPadding: '10 10 10 10',
b047eec0
DC
443 layout: {
444 type: 'vbox',
445 pack: 'center',
c87d46fb 446 align: 'stretch',
b047eec0
DC
447 },
448 items: [{
449 xtype: 'grid',
450 bind: {
c87d46fb 451 store: '{receivers}',
b047eec0 452 },
b047eec0 453 emptyText: gettext('No data in database'),
b047eec0
DC
454 // remove all borders/lines/headers
455 border: false,
456 bodyBorder: false,
457 hideHeaders: true,
458 header: false,
459 columnLines: false,
460 rowLines: false,
461 viewConfig: {
c87d46fb 462 stripeRows: false,
b047eec0 463 },
b047eec0
DC
464 columns: [
465 {
466 dataIndex: 'receiver',
467 flex: 1,
c87d46fb 468 text: gettext('Receiver'),
b047eec0
DC
469 },
470 {
471 dataIndex: 'count',
472 align: 'right',
c87d46fb
TL
473 text: gettext('Count'),
474 },
475 ],
476 }],
477 },
8f691c7b
TL
478 {
479 height: 250,
480 iconCls: 'fa fa-tasks',
481 title: gettext('Cluster Resources (average)'),
482 reference: 'clusterResources',
483 hidden: true,
484 bodyPadding: '0 20 0 20',
485 layout: {
486 type: 'hbox',
487 align: 'center',
488 },
489 defaults: {
490 xtype: 'proxmoxGauge',
491 spriteFontSize: '20px',
492 flex: 1,
493 },
494 items: [
495 {
496 title: gettext('CPU'),
497 reference: 'cpu',
498 },
499 {
500 title: gettext('Memory'),
501 reference: 'mem',
502 },
503 {
504 title: gettext('Storage'),
505 reference: 'hd',
506 },
507 ],
508 },
c87d46fb 509 ],
5936e3ef 510});