]> git.proxmox.com Git - proxmox-backup.git/blame - www/Dashboard.js
ui: Dashboard: show LongestTask/RunningTask/TaskSummary
[proxmox-backup.git] / www / Dashboard.js
CommitLineData
84b9eced
TL
1Ext.define('PBS.Dashboard', {
2 extend: 'Ext.panel.Panel',
3 xtype: 'pbsDashboard',
4
5 controller: {
6 xclass: 'Ext.app.ViewController',
7
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: {
16 type: 'auto'
17 },
18 items: [{
19 xtype: 'form',
20 bodyPadding: '10 10 10 10',
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'),
31 fieldLabel: gettext('Hours to show')
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();
42 }
43 }]
44 }]
45 }).show();
46 },
47
48 setHours: function(hours, setState) {
49 var me = this;
50 var viewModel = me.getViewModel();
51 viewModel.set('hours', hours);
52 viewModel.notify();
53
54 if (setState) {
55 var sp = Ext.state.Manager.getProvider();
56 sp.set('dashboard-hours', hours);
57 }
58 },
59
60
61 updateSubscription: function(store, records, success) {
62 if (!success) {
63 return;
64 }
65 var me = this;
66 var viewmodel = me.getViewModel();
67
68 var subStatus = 2; // 2 = all good, 1 = different leves, 0 = none
69 var subLevel = "";
70 },
71
72 updateUsageStats: function(store, records, success) {
73 if (!success) {
74 return;
75 }
76 if (records === undefined || records.length < 1) {
77 return;
78 }
79 let me = this;
80 let viewmodel = me.getViewModel();
81
82 let res = records[0].data;
83
84 let cpu = res.cpu,
85 mem = res.memory,
34020b92 86 root = res.root;
84b9eced
TL
87
88 var cpuPanel = me.lookup('cpu');
89 cpuPanel.updateValue(cpu);
90
91 var memPanel = me.lookup('mem');
92 memPanel.updateValue(mem.used / mem.total);
93
34020b92
DC
94 var hdPanel = me.lookup('root');
95 hdPanel.updateValue(root.used / root.total);
84b9eced
TL
96 },
97
195d7c90
DC
98 updateTasks: function(store, records, success) {
99 if (!success) return;
100 let me = this;
101
102 records.sort((a, b) => a.data.duration - b.data.duration);
103 let top10 = records.slice(-10);
104 me.lookup('longesttasks').updateTasks(top10);
105
106 let data = {
107 backup: { error: 0, warning: 0, ok: 0, },
108 prune: { error: 0, warning: 0, ok: 0, },
109 garbage_collection: { error: 0, warning: 0, ok: 0, },
110 sync: { error: 0, warning: 0, ok: 0, },
111 };
112
113 records.forEach(record => {
114 let type = record.data.worker_type;
115 if (type === 'syncjob') {
116 type = 'sync';
117 }
118
119 if (data[type] && record.data.status) {
120 let parsed = Proxmox.Utils.parse_task_status(record.data.status);
121 data[type][parsed]++;
122 }
123 });
124
125 me.lookup('tasksummary').updateTasks(data);
126 },
127
84b9eced
TL
128 init: function(view) {
129 var me = this;
130 var sp = Ext.state.Manager.getProvider();
131 var hours = sp.get('dashboard-hours') || 12;
132 me.setHours(hours, false);
133 }
134 },
135
136 viewModel: {
137 data: {
138 timespan: 300, // in seconds
139 hours: 12, // in hours
140 error_shown: false,
141 'bytes_in': 0,
142 'bytes_out': 0,
143 'avg_ptime': 0.0
144 },
145
146 stores: {
147 usage: {
148 storeid: 'dash-usage',
149 type: 'update',
150 interval: 3000,
151 autoStart: true,
152 autoLoad: true,
153 autoDestroy: true,
154 proxy: {
155 type: 'proxmox',
e325dbd4 156 url: '/api2/json/nodes/localhost/status'
84b9eced
TL
157 },
158 listeners: {
159 load: 'updateUsageStats'
160 }
161 },
162 subscription: {
163 storeid: 'dash-subscription',
164 type: 'update',
165 interval: 10000,
166 autoStart: true,
167 autoLoad: true,
168 autoDestroy: true,
169 proxy: {
170 type: 'proxmox',
171 url: '/api2/json/subscription'
172 },
173 listeners: {
174 load: 'updateSubscription'
175 }
176 },
195d7c90
DC
177 tasks: {
178 storeid: 'dash-tasks',
179 type: 'update',
180 interval: 15000,
181 autoStart: true,
182 autoLoad: true,
183 autoDestroy: true,
184 model: 'proxmox-tasks',
185 proxy: {
186 type: 'proxmox',
187 url: '/api2/json/status/tasks'
188 },
189 listeners: {
190 load: 'updateTasks'
191 }
192 },
84b9eced
TL
193 }
194 },
195
196 title: gettext('Dashboard') + ' - WIP',
197
198 layout: {
199 type: 'column'
200 },
201
202 bodyPadding: '20 0 0 20',
203
204 defaults: {
205 columnWidth: 0.49,
206 xtype: 'panel',
207 margin: '0 20 20 0'
208 },
209
210 scrollable: true,
211
212 items: [
213 {
214 height: 250,
215 iconCls: 'fa fa-tasks',
216 title: gettext('Server Resources'),
217 bodyPadding: '0 20 0 20',
218 layout: {
219 type: 'hbox',
220 align: 'center'
221 },
222 defaults: {
223 xtype: 'proxmoxGauge',
224 spriteFontSize: '20px',
225 flex: 1
226 },
227 items: [
228 {
229 title: gettext('CPU'),
230 reference: 'cpu'
231 },
232 {
233 title: gettext('Memory'),
234 reference: 'mem'
235 },
236 {
34020b92
DC
237 title: gettext('Root Disk'),
238 reference: 'root'
84b9eced
TL
239 }
240 ]
241 },
ae66873c
DC
242 {
243 xtype: 'pbsDatastoresStatistics',
244 height: 250,
245 },
84b9eced 246 {
195d7c90
DC
247 xtype: 'pbsLongestTasks',
248 reference: 'longesttasks',
84b9eced 249 height: 250,
195d7c90
DC
250 },
251 {
252 xtype: 'pbsRunningTasks',
253 height: 250,
254 },
255 {
256 xtype: 'pbsTaskSummary',
257 reference: 'tasksummary',
258 },
259 {
260 iconCls: 'fa fa-ticket',
261 title: 'Subscription',
262 height: 166,
263 reference: 'subscription',
264 xtype: 'pmgSubscriptionInfo',
84b9eced
TL
265 },
266 ]
267});
268
269Ext.define('PMG.dashboard.SubscriptionInfo', {
270 extend: 'Ext.panel.Panel',
271 xtype: 'pmgSubscriptionInfo',
272
273 data: {
274 icon: 'question-circle',
275 message: gettext('Unknown')
276 },
277
278 style: {
279 cursor: 'pointer'
280 },
281
282 setSubStatus: function(status) {
283 var me = this;
284 var data = {};
285
286 switch (status) {
287 case 2:
288 data.icon = 'check green';
289 data.message = gettext('Your subscription status is valid.');
290 break;
2e75b6d8 291 case 1:
84b9eced
TL
292 data.icon = 'exclamation-triangle yellow';
293 data.message = gettext('Warning: Your subscription levels are not the same.');
294 break;
2e75b6d8 295 case 0:
84b9eced
TL
296 data.icon = 'times-circle red';
297 data.message = gettext('You have at least one node without subscription.');
298 break;
299 default:
300 throw 'invalid subscription status';
301 }
302 me.update(data);
303 },
304 tpl: [
305 '<table style="height: 100%;" class="dash">',
306 '<tr><td class="center">',
307 '<i class="fa fa-3x fa-{icon}"></i>',
308 '</td><td class="center">{message}</td></tr>',
309 '</table>'
310 ],
311
312 listeners: {
313 click: {
314 element: 'body',
315 fn: function() {
316 var mainview = this.component.up('mainview');
317 mainview.getController().redirectTo('pmgSubscription');
318 }
319 }
320 }
321});