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