]>
Commit | Line | Data |
---|---|---|
84b9eced TL |
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: { | |
65b0cea6 | 16 | type: 'auto', |
84b9eced TL |
17 | }, |
18 | items: [{ | |
19 | xtype: 'form', | |
20 | bodyPadding: '10 10 10 10', | |
21 | defaultButton: 'savebutton', | |
22 | items: [{ | |
23 | xtype: 'proxmoxintegerfield', | |
ad9d1625 | 24 | itemId: 'days', |
84b9eced TL |
25 | labelWidth: 100, |
26 | anchor: '100%', | |
27 | allowBlank: false, | |
28 | minValue: 1, | |
ad9d1625 DC |
29 | maxValue: 60, |
30 | value: viewModel.get('days'), | |
6e0f58e7 | 31 | fieldLabel: gettext('Days to show'), |
84b9eced TL |
32 | }], |
33 | buttons: [{ | |
34 | text: gettext('Save'), | |
ad9d1625 | 35 | reference: 'savebutton', |
84b9eced TL |
36 | formBind: true, |
37 | handler: function() { | |
38 | var win = this.up('window'); | |
ad9d1625 DC |
39 | var days = win.down('#days').getValue(); |
40 | me.setDays(days, true); | |
84b9eced | 41 | win.close(); |
65b0cea6 TL |
42 | }, |
43 | }], | |
44 | }], | |
84b9eced TL |
45 | }).show(); |
46 | }, | |
47 | ||
ad9d1625 | 48 | setDays: function(days, setState) { |
84b9eced TL |
49 | var me = this; |
50 | var viewModel = me.getViewModel(); | |
ad9d1625 | 51 | viewModel.set('days', days); |
84b9eced TL |
52 | viewModel.notify(); |
53 | ||
ad9d1625 DC |
54 | viewModel.getStore('tasks').reload(); |
55 | ||
84b9eced TL |
56 | if (setState) { |
57 | var sp = Ext.state.Manager.getProvider(); | |
ad9d1625 | 58 | sp.set('dashboard-days', days); |
84b9eced TL |
59 | } |
60 | }, | |
61 | ||
4672273f FE |
62 | updateRepositoryStatus: function(store, records, success) { |
63 | if (!success) { return; } | |
64 | let me = this; | |
6a7b6738 TL |
65 | let view = me.getView(); |
66 | view.down('#repositoryStatus').setRepositoryInfo(records[0].data['standard-repos']); | |
4672273f | 67 | }, |
84b9eced TL |
68 | |
69 | updateSubscription: function(store, records, success) { | |
739a5145 DC |
70 | if (!success) { return; } |
71 | let me = this; | |
6a7b6738 | 72 | let view = me.getView(); |
dcd75edb TL |
73 | let status = records[0].data.status || 'unknown'; |
74 | // 2 = all good, 1 = different leves, 0 = none | |
6a7b6738 | 75 | let subscriptionActive = status.toLowerCase() === 'active'; |
dcd75edb | 76 | let subStatus = status.toLowerCase() === 'active' ? 2 : 0; |
739a5145 | 77 | me.lookup('subscription').setSubStatus(subStatus); |
6a7b6738 | 78 | view.down('#repositoryStatus').setSubscriptionStatus(subscriptionActive); |
84b9eced TL |
79 | }, |
80 | ||
195d7c90 DC |
81 | updateTasks: function(store, records, success) { |
82 | if (!success) return; | |
83 | let me = this; | |
4acd7229 | 84 | let viewModel = me.getViewModel(); |
195d7c90 DC |
85 | |
86 | records.sort((a, b) => a.data.duration - b.data.duration); | |
87 | let top10 = records.slice(-10); | |
88 | me.lookup('longesttasks').updateTasks(top10); | |
89 | ||
90 | let data = { | |
65b0cea6 TL |
91 | backup: { error: 0, warning: 0, ok: 0 }, |
92 | prune: { error: 0, warning: 0, ok: 0 }, | |
93 | garbage_collection: { error: 0, warning: 0, ok: 0 }, | |
94 | sync: { error: 0, warning: 0, ok: 0 }, | |
4acd7229 | 95 | verify: { error: 0, warning: 0, ok: 0 }, |
0763ac14 DC |
96 | 'tape-backup': { error: 0, warning: 0, ok: 0 }, |
97 | 'tape-restore': { error: 0, warning: 0, ok: 0 }, | |
195d7c90 DC |
98 | }; |
99 | ||
100 | records.forEach(record => { | |
21486225 TL |
101 | let task = record.data; |
102 | let type = task.worker_type; | |
195d7c90 DC |
103 | if (type === 'syncjob') { |
104 | type = 'sync'; | |
105 | } | |
106 | ||
baf9c370 | 107 | if (type.startsWith('verif')) { |
4acd7229 DC |
108 | type = 'verify'; |
109 | } | |
110 | ||
21ff6e59 DC |
111 | if (type.startsWith('prune')) { |
112 | type = 'prune'; | |
113 | } | |
114 | ||
0763ac14 DC |
115 | if (type.startsWith('tape-backup')) { |
116 | type = 'tape-backup'; | |
117 | } | |
118 | ||
21486225 TL |
119 | if (data[type] && task.status) { |
120 | let parsed = Proxmox.Utils.parse_task_status(task.status); | |
195d7c90 DC |
121 | data[type][parsed]++; |
122 | } | |
123 | }); | |
124 | ||
dee74aa4 | 125 | me.lookup('tasksummary').updateTasks(data, viewModel.get('sinceEpoch')); |
195d7c90 DC |
126 | }, |
127 | ||
84b9eced TL |
128 | init: function(view) { |
129 | var me = this; | |
130 | var sp = Ext.state.Manager.getProvider(); | |
ad9d1625 DC |
131 | var days = sp.get('dashboard-days') || 30; |
132 | me.setDays(days, false); | |
01284de0 DC |
133 | |
134 | view.mon(sp, 'statechange', function(provider, key, value) { | |
135 | if (key !== 'summarycolumns') { | |
136 | return; | |
137 | } | |
138 | Proxmox.Utils.updateColumns(view); | |
139 | }); | |
65b0cea6 | 140 | }, |
84b9eced TL |
141 | }, |
142 | ||
143 | viewModel: { | |
144 | data: { | |
ad9d1625 | 145 | days: 30, |
84b9eced TL |
146 | }, |
147 | ||
1f0d23f7 | 148 | formulas: { |
ad9d1625 | 149 | sinceEpoch: (get) => (Date.now()/1000 - get('days') * 24*3600).toFixed(0), |
1f0d23f7 DC |
150 | }, |
151 | ||
84b9eced | 152 | stores: { |
4672273f FE |
153 | repositories: { |
154 | storeid: 'dash-repositories', | |
155 | type: 'update', | |
156 | interval: 15000, | |
157 | autoStart: true, | |
158 | autoLoad: true, | |
159 | autoDestroy: true, | |
160 | proxy: { | |
161 | type: 'proxmox', | |
162 | url: '/api2/json/nodes/localhost/apt/repositories', | |
163 | }, | |
164 | listeners: { | |
165 | load: 'updateRepositoryStatus', | |
166 | }, | |
167 | }, | |
84b9eced TL |
168 | subscription: { |
169 | storeid: 'dash-subscription', | |
170 | type: 'update', | |
171 | interval: 10000, | |
172 | autoStart: true, | |
173 | autoLoad: true, | |
174 | autoDestroy: true, | |
175 | proxy: { | |
176 | type: 'proxmox', | |
65b0cea6 | 177 | url: '/api2/json/nodes/localhost/subscription', |
84b9eced TL |
178 | }, |
179 | listeners: { | |
65b0cea6 TL |
180 | load: 'updateSubscription', |
181 | }, | |
84b9eced | 182 | }, |
195d7c90 DC |
183 | tasks: { |
184 | storeid: 'dash-tasks', | |
185 | type: 'update', | |
186 | interval: 15000, | |
187 | autoStart: true, | |
188 | autoLoad: true, | |
189 | autoDestroy: true, | |
190 | model: 'proxmox-tasks', | |
191 | proxy: { | |
192 | type: 'proxmox', | |
a2a7dd15 | 193 | url: '/api2/json/nodes/localhost/tasks', |
ad9d1625 | 194 | extraParams: { |
a2a7dd15 | 195 | limit: 0, |
ad9d1625 DC |
196 | since: '{sinceEpoch}', |
197 | }, | |
195d7c90 DC |
198 | }, |
199 | listeners: { | |
65b0cea6 TL |
200 | load: 'updateTasks', |
201 | }, | |
195d7c90 | 202 | }, |
65b0cea6 | 203 | }, |
84b9eced TL |
204 | }, |
205 | ||
01284de0 DC |
206 | listeners: { |
207 | resize: function(panel) { | |
208 | Proxmox.Utils.updateColumns(panel); | |
209 | }, | |
210 | }, | |
211 | ||
ad9d1625 | 212 | title: gettext('Dashboard'), |
84b9eced TL |
213 | |
214 | layout: { | |
65b0cea6 | 215 | type: 'column', |
84b9eced TL |
216 | }, |
217 | ||
218 | bodyPadding: '20 0 0 20', | |
219 | ||
01284de0 DC |
220 | minWidth: 700, |
221 | ||
84b9eced TL |
222 | defaults: { |
223 | columnWidth: 0.49, | |
224 | xtype: 'panel', | |
65b0cea6 | 225 | margin: '0 20 20 0', |
84b9eced TL |
226 | }, |
227 | ||
ad9d1625 DC |
228 | tools: [ |
229 | { | |
230 | type: 'gear', | |
a2920c37 | 231 | tooltip: gettext('Edit dashboard settings'), |
ad9d1625 DC |
232 | handler: 'openDashboardOptions', |
233 | }, | |
234 | ], | |
235 | ||
84b9eced TL |
236 | scrollable: true, |
237 | ||
238 | items: [ | |
239 | { | |
e584593c | 240 | xtype: 'pbsNodeInfoPanel', |
4672273f | 241 | reference: 'nodeInfo', |
b20368ee | 242 | height: 280, |
84b9eced | 243 | }, |
ae66873c DC |
244 | { |
245 | xtype: 'pbsDatastoresStatistics', | |
b20368ee | 246 | height: 280, |
ae66873c | 247 | }, |
84b9eced | 248 | { |
195d7c90 | 249 | xtype: 'pbsLongestTasks', |
ad9d1625 DC |
250 | bind: { |
251 | title: gettext('Longest Tasks') + ' (' + | |
252 | Ext.String.format(gettext('{0} days'), '{days}') + ')', | |
253 | }, | |
195d7c90 | 254 | reference: 'longesttasks', |
e099bd07 | 255 | height: 280, |
195d7c90 DC |
256 | }, |
257 | { | |
258 | xtype: 'pbsRunningTasks', | |
e099bd07 | 259 | height: 280, |
195d7c90 DC |
260 | }, |
261 | { | |
ad9d1625 DC |
262 | bind: { |
263 | title: gettext('Task Summary') + ' (' + | |
264 | Ext.String.format(gettext('{0} days'), '{days}') + ')', | |
265 | }, | |
195d7c90 | 266 | xtype: 'pbsTaskSummary', |
0763ac14 | 267 | height: 250, |
195d7c90 DC |
268 | reference: 'tasksummary', |
269 | }, | |
270 | { | |
271 | iconCls: 'fa fa-ticket', | |
272 | title: 'Subscription', | |
0763ac14 | 273 | height: 250, |
195d7c90 | 274 | reference: 'subscription', |
739a5145 | 275 | xtype: 'pbsSubscriptionInfo', |
84b9eced | 276 | }, |
65b0cea6 | 277 | ], |
84b9eced TL |
278 | }); |
279 | ||
739a5145 | 280 | Ext.define('PBS.dashboard.SubscriptionInfo', { |
84b9eced | 281 | extend: 'Ext.panel.Panel', |
739a5145 | 282 | xtype: 'pbsSubscriptionInfo', |
84b9eced TL |
283 | |
284 | style: { | |
65b0cea6 | 285 | cursor: 'pointer', |
84b9eced TL |
286 | }, |
287 | ||
739a5145 DC |
288 | layout: { |
289 | type: 'hbox', | |
290 | align: 'middle', | |
291 | }, | |
292 | ||
293 | items: [ | |
294 | { | |
295 | xtype: 'box', | |
296 | itemId: 'icon', | |
297 | data: { | |
298 | icon: 'question-circle', | |
299 | }, | |
300 | width: 100, | |
301 | tpl: '<center><i class="fa fa-3x fa-{icon}"></i></center>', | |
302 | }, | |
303 | { | |
304 | flex: 1, | |
305 | xtype: 'box', | |
306 | data: { | |
307 | message: gettext('Unknown'), | |
308 | }, | |
309 | itemId: 'message', | |
310 | tpl: '<center>{message}</center>', | |
311 | }, | |
312 | ], | |
313 | ||
84b9eced TL |
314 | setSubStatus: function(status) { |
315 | var me = this; | |
739a5145 DC |
316 | let icon = ''; |
317 | let message = ''; | |
84b9eced TL |
318 | |
319 | switch (status) { | |
320 | case 2: | |
739a5145 DC |
321 | icon = 'check good'; |
322 | message = gettext('Your subscription status is valid.'); | |
84b9eced | 323 | break; |
2e75b6d8 | 324 | case 1: |
739a5145 DC |
325 | icon = 'exclamation-triangle warning'; |
326 | message = gettext('Warning: Your subscription levels are not the same.'); | |
84b9eced | 327 | break; |
2e75b6d8 | 328 | case 0: |
739a5145 | 329 | icon = 'times-circle critical'; |
5176346b | 330 | message = `<h1>${gettext('No valid subscription')}</h1>${PBS.Utils.noSubKeyHtml}`; |
84b9eced TL |
331 | break; |
332 | default: | |
333 | throw 'invalid subscription status'; | |
334 | } | |
739a5145 DC |
335 | me.getComponent('icon').update({ icon }); |
336 | me.getComponent('message').update({ message }); | |
84b9eced | 337 | }, |
84b9eced TL |
338 | |
339 | listeners: { | |
340 | click: { | |
341 | element: 'body', | |
342 | fn: function() { | |
343 | var mainview = this.component.up('mainview'); | |
739a5145 | 344 | mainview.getController().redirectTo('pbsSubscription'); |
65b0cea6 TL |
345 | }, |
346 | }, | |
347 | }, | |
84b9eced | 348 | }); |