]>
Commit | Line | Data |
---|---|---|
09d64465 DM |
1 | Ext.define('Proxmox.node.Tasks', { |
2 | extend: 'Ext.grid.GridPanel', | |
3 | ||
9e059d56 DC |
4 | alias: 'widget.proxmoxNodeTasks', |
5 | ||
09d64465 | 6 | stateful: true, |
9e059d56 DC |
7 | stateId: 'pve-grid-node-tasks', |
8 | ||
09d64465 DM |
9 | loadMask: true, |
10 | sortableColumns: false, | |
09d64465 | 11 | |
6fc91fc6 TL |
12 | // set extra filter components, must have a 'name' property for the parameter, and must |
13 | // trigger a 'change' event if the value is 'undefined', it will not be sent to the api | |
9e059d56 | 14 | extraFilter: [], |
09d64465 | 15 | |
09d64465 | 16 | |
6fc91fc6 TL |
17 | // fixed filters which cannot be changed after instantiation, for example: |
18 | // { vmid: 100 } | |
9e059d56 DC |
19 | preFilter: {}, |
20 | ||
21 | controller: { | |
22 | xclass: 'Ext.app.ViewController', | |
23 | ||
24 | showTaskLog: function() { | |
25 | let me = this; | |
26 | let selection = me.getView().getSelection(); | |
27 | if (selection.length < 1) { | |
28 | return; | |
29 | } | |
09d64465 | 30 | |
9e059d56 DC |
31 | let rec = selection[0]; |
32 | ||
33 | Ext.create('Proxmox.window.TaskViewer', { | |
34 | upid: rec.data.upid, | |
35 | endtime: rec.data.endtime, | |
36 | }).show(); | |
37 | }, | |
38 | ||
39 | updateLayout: function() { | |
40 | let me = this; | |
6fc91fc6 TL |
41 | // update the scrollbar on every store load since the total count might be different. |
42 | // the buffered grid plugin does this only on (user) scrolling itself and even reduces | |
43 | // the scrollheight again when scrolling up | |
9e059d56 DC |
44 | me.getView().updateLayout(); |
45 | }, | |
09d64465 | 46 | |
9e059d56 DC |
47 | sinceChange: function(field, newval) { |
48 | let me = this; | |
49 | let vm = me.getViewModel(); | |
09d64465 | 50 | |
9e059d56 DC |
51 | vm.set('since', newval); |
52 | }, | |
09d64465 | 53 | |
9e059d56 DC |
54 | untilChange: function(field, newval, oldval) { |
55 | let me = this; | |
56 | let vm = me.getViewModel(); | |
57 | ||
58 | vm.set('until', newval); | |
59 | }, | |
60 | ||
61 | reload: function() { | |
62 | let me = this; | |
63 | let view = me.getView(); | |
64 | view.getStore().load(); | |
65 | }, | |
66 | ||
67 | showFilter: function(btn, pressed) { | |
68 | let me = this; | |
69 | let vm = me.getViewModel(); | |
70 | vm.set('showFilter', pressed); | |
71 | }, | |
72 | ||
73 | init: function(view) { | |
74 | let me = this; | |
75 | Proxmox.Utils.monStoreErrors(view, view.getStore(), true); | |
76 | }, | |
77 | }, | |
09d64465 | 78 | |
09d64465 | 79 | |
9e059d56 DC |
80 | listeners: { |
81 | itemdblclick: 'showTaskLog', | |
82 | }, | |
83 | ||
84 | viewModel: { | |
85 | data: { | |
86 | typefilter: '', | |
87 | statusfilter: '', | |
9e059d56 DC |
88 | showFilter: false, |
89 | extraFilter: {}, | |
90 | since: null, | |
91 | until: null, | |
92 | }, | |
93 | ||
94 | formulas: { | |
95 | filterIcon: (get) => 'fa fa-filter' + (get('showFilter') ? ' info-blue' : ''), | |
96 | extraParams: function(get) { | |
97 | let me = this; | |
98 | let params = {}; | |
99 | if (get('typefilter')) { | |
100 | params.typefilter = get('typefilter'); | |
101 | } | |
102 | if (get('statusfilter')) { | |
103 | params.statusfilter = get('statusfilter'); | |
104 | } | |
9e059d56 DC |
105 | |
106 | if (get('extraFilter')) { | |
107 | let extraFilter = get('extraFilter'); | |
108 | for (const [name, value] of Object.entries(extraFilter)) { | |
109 | if (value !== undefined && value !== null && value !== "") { | |
110 | params[name] = value; | |
b1d446d0 | 111 | } |
09d64465 | 112 | } |
9e059d56 DC |
113 | } |
114 | ||
115 | if (get('since')) { | |
116 | params.since = get('since').valueOf()/1000; | |
117 | } | |
118 | ||
119 | if (get('until')) { | |
120 | let until = new Date(get('until').getTime()); // copy object | |
121 | until.setDate(until.getDate() + 1); // end of the day | |
122 | params.until = until.valueOf()/1000; | |
123 | } | |
124 | ||
125 | me.getView().getStore().load(); | |
126 | ||
127 | return params; | |
128 | }, | |
129 | }, | |
130 | ||
131 | stores: { | |
132 | bufferedstore: { | |
133 | type: 'buffered', | |
134 | pageSize: 500, | |
135 | autoLoad: true, | |
136 | remoteFilter: true, | |
137 | model: 'proxmox-tasks', | |
138 | proxy: { | |
139 | type: 'proxmox', | |
140 | startParam: 'start', | |
141 | limitParam: 'limit', | |
142 | extraParams: '{extraParams}', | |
143 | url: "/api2/json/nodes/localhost/tasks", | |
144 | }, | |
145 | listeners: { | |
146 | prefetch: 'updateLayout', | |
122a2079 | 147 | }, |
09d64465 | 148 | }, |
9e059d56 DC |
149 | }, |
150 | }, | |
151 | ||
152 | bind: { | |
153 | store: '{bufferedstore}', | |
154 | }, | |
155 | ||
156 | dockedItems: [ | |
157 | { | |
158 | xtype: 'toolbar', | |
159 | items: [ | |
f138d11f | 160 | { |
9e059d56 DC |
161 | xtype: 'proxmoxButton', |
162 | text: gettext('View'), | |
163 | iconCls: 'fa fa-window-restore', | |
164 | disabled: true, | |
165 | handler: 'showTaskLog', | |
166 | }, | |
167 | { | |
168 | xtype: 'button', | |
169 | text: gettext('Reload'), | |
170 | iconCls: 'fa fa-refresh', | |
171 | handler: 'reload', | |
f138d11f TL |
172 | }, |
173 | '->', | |
09d64465 | 174 | { |
9e059d56 DC |
175 | xtype: 'button', |
176 | enableToggle: true, | |
177 | bind: { | |
178 | iconCls: '{filterIcon}', | |
179 | }, | |
180 | text: gettext('Filter'), | |
181 | stateful: true, | |
182 | stateId: 'task-showfilter', | |
183 | stateEvents: ['toggle'], | |
184 | applyState: function(state) { | |
185 | if (state.pressed !== undefined) { | |
186 | this.setPressed(state.pressed); | |
187 | } | |
188 | }, | |
189 | getState: function() { | |
190 | return { | |
191 | pressed: this.pressed, | |
192 | }; | |
122a2079 | 193 | }, |
09d64465 | 194 | listeners: { |
9e059d56 | 195 | toggle: 'showFilter', |
122a2079 | 196 | }, |
9e059d56 | 197 | }, |
09d64465 | 198 | ], |
9e059d56 DC |
199 | }, |
200 | { | |
201 | xtype: 'toolbar', | |
202 | dock: 'top', | |
203 | reference: 'filtertoolbar', | |
204 | layout: { | |
205 | type: 'hbox', | |
206 | align: 'top', | |
207 | }, | |
208 | bind: { | |
209 | hidden: '{!showFilter}', | |
210 | }, | |
211 | items: [ | |
09d64465 | 212 | { |
9e059d56 DC |
213 | xtype: 'container', |
214 | padding: 10, | |
215 | layout: { | |
216 | type: 'vbox', | |
217 | align: 'stretch', | |
122a2079 | 218 | }, |
9e059d56 DC |
219 | defaults: { |
220 | labelWidth: 80, | |
122a2079 | 221 | }, |
9e059d56 DC |
222 | // cannot bind the values directly, as it then changes also |
223 | // on blur, causing wrong reloads of the store | |
224 | items: [ | |
225 | { | |
226 | xtype: 'datefield', | |
227 | fieldLabel: gettext('Since'), | |
228 | format: 'Y-m-d', | |
229 | bind: { | |
230 | maxValue: '{until}', | |
231 | }, | |
232 | listeners: { | |
233 | change: 'sinceChange', | |
234 | }, | |
235 | }, | |
236 | { | |
237 | xtype: 'datefield', | |
238 | fieldLabel: gettext('Until'), | |
239 | format: 'Y-m-d', | |
240 | bind: { | |
241 | minValue: '{since}', | |
242 | }, | |
243 | listeners: { | |
244 | change: 'untilChange', | |
245 | }, | |
246 | }, | |
247 | ], | |
09d64465 | 248 | }, |
54dc3ab4 | 249 | { |
9e059d56 DC |
250 | xtype: 'container', |
251 | padding: 10, | |
252 | layout: { | |
253 | type: 'vbox', | |
254 | align: 'stretch', | |
54dc3ab4 | 255 | }, |
9e059d56 DC |
256 | defaults: { |
257 | labelWidth: 80, | |
258 | }, | |
259 | items: [ | |
260 | { | |
261 | xtype: 'pmxTaskTypeSelector', | |
262 | fieldLabel: gettext('Task Type'), | |
263 | emptyText: gettext('All'), | |
264 | bind: { | |
265 | value: '{typefilter}', | |
266 | }, | |
267 | }, | |
268 | { | |
269 | xtype: 'combobox', | |
270 | fieldLabel: gettext('Task Result'), | |
271 | emptyText: gettext('All'), | |
272 | multiSelect: true, | |
273 | store: [ | |
274 | ['ok', gettext('OK')], | |
275 | ['unknown', Proxmox.Utils.unknownText], | |
276 | ['warning', gettext('Warnings')], | |
277 | ['error', gettext('Errors')], | |
278 | ], | |
279 | bind: { | |
280 | value: '{statusfilter}', | |
281 | }, | |
282 | }, | |
283 | ], | |
54dc3ab4 | 284 | }, |
9e059d56 DC |
285 | ], |
286 | }, | |
287 | ], | |
288 | ||
289 | viewConfig: { | |
290 | trackOver: false, | |
291 | stripeRows: false, // does not work with getRowClass() | |
292 | emptyText: gettext('No Tasks found'), | |
293 | ||
294 | getRowClass: function(record, index) { | |
295 | let status = record.get('status'); | |
296 | ||
297 | if (status) { | |
298 | let parsed = Proxmox.Utils.parse_task_status(status); | |
299 | if (parsed === 'error') { | |
300 | return "proxmox-invalid-row"; | |
301 | } else if (parsed === 'warning') { | |
302 | return "proxmox-warning-row"; | |
303 | } | |
304 | } | |
305 | return ''; | |
306 | }, | |
307 | }, | |
308 | ||
309 | columns: [ | |
310 | { | |
311 | header: gettext("Start Time"), | |
312 | dataIndex: 'starttime', | |
313 | width: 130, | |
314 | renderer: function(value) { | |
315 | return Ext.Date.format(value, "M d H:i:s"); | |
316 | }, | |
317 | }, | |
318 | { | |
319 | header: gettext("End Time"), | |
320 | dataIndex: 'endtime', | |
321 | width: 130, | |
322 | renderer: function(value, metaData, record) { | |
323 | if (!value) { | |
324 | metaData.tdCls = "x-grid-row-loading"; | |
325 | return ''; | |
326 | } | |
327 | return Ext.Date.format(value, "M d H:i:s"); | |
328 | }, | |
329 | }, | |
330 | { | |
331 | header: gettext("Duration"), | |
332 | hidden: true, | |
333 | width: 80, | |
334 | renderer: function(value, metaData, record) { | |
335 | let start = record.data.starttime; | |
336 | if (start) { | |
337 | let end = record.data.endtime || Date.now(); | |
338 | let duration = end - start; | |
339 | if (duration > 0) { | |
340 | duration /= 1000; | |
341 | } | |
342 | return Proxmox.Utils.format_duration_human(duration); | |
343 | } | |
344 | return Proxmox.Utils.unknownText; | |
345 | }, | |
346 | }, | |
347 | { | |
348 | header: gettext("User name"), | |
349 | dataIndex: 'user', | |
350 | width: 150, | |
351 | }, | |
352 | { | |
353 | header: gettext("Description"), | |
354 | dataIndex: 'upid', | |
355 | flex: 1, | |
356 | renderer: Proxmox.Utils.render_upid, | |
357 | }, | |
358 | { | |
359 | header: gettext("Status"), | |
360 | dataIndex: 'status', | |
361 | width: 200, | |
362 | renderer: function(value, metaData, record) { | |
363 | if (value === undefined && !record.data.endtime) { | |
364 | metaData.tdCls = "x-grid-row-loading"; | |
365 | return ''; | |
366 | } | |
367 | ||
368 | let parsed = Proxmox.Utils.parse_task_status(value); | |
369 | switch (parsed) { | |
370 | case 'unknown': return Proxmox.Utils.unknownText; | |
371 | case 'error': return Proxmox.Utils.errorText + ': ' + value; | |
372 | case 'ok': // fall-through | |
373 | case 'warning': // fall-through | |
374 | default: return value; | |
375 | } | |
376 | }, | |
377 | }, | |
378 | ], | |
379 | ||
380 | initComponent: function() { | |
381 | const me = this; | |
382 | ||
383 | let updateExtraFilters = function(name, value) { | |
384 | let vm = me.getViewModel(); | |
385 | let extraFilter = Ext.clone(vm.get('extraFilter')); | |
386 | extraFilter[name] = value; | |
387 | vm.set('extraFilter', extraFilter); | |
388 | }; | |
389 | ||
390 | for (const [name, value] of Object.entries(me.preFilter)) { | |
391 | updateExtraFilters(name, value); | |
392 | } | |
393 | ||
394 | me.callParent(); | |
395 | ||
396 | let addFields = function(items) { | |
397 | me.lookup('filtertoolbar').add({ | |
398 | xtype: 'container', | |
399 | padding: 10, | |
400 | layout: { | |
401 | type: 'vbox', | |
402 | align: 'stretch', | |
09d64465 | 403 | }, |
9e059d56 DC |
404 | defaults: { |
405 | labelWidth: 80, | |
09d64465 | 406 | }, |
9e059d56 DC |
407 | items, |
408 | }); | |
409 | }; | |
b1d446d0 | 410 | |
9e059d56 DC |
411 | // start with a userfilter |
412 | me.extraFilter = [ | |
413 | { | |
414 | xtype: 'textfield', | |
415 | fieldLabel: gettext('User name'), | |
416 | changeOptions: { | |
417 | buffer: 500, | |
122a2079 | 418 | }, |
9e059d56 | 419 | name: 'userfilter', |
122a2079 | 420 | }, |
9e059d56 DC |
421 | ...me.extraFilter, |
422 | ]; | |
423 | let items = []; | |
424 | for (const filterTemplate of me.extraFilter) { | |
425 | let filter = Ext.clone(filterTemplate); | |
09d64465 | 426 | |
9e059d56 DC |
427 | filter.listeners = filter.listeners || {}; |
428 | filter.listeners.change = Ext.apply(filter.changeOptions || {}, { | |
429 | fn: function(field, value) { | |
430 | updateExtraFilters(filter.name, value); | |
431 | }, | |
432 | }); | |
433 | ||
434 | items.push(filter); | |
435 | if (items.length === 2) { | |
436 | addFields(items); | |
437 | items = []; | |
438 | } | |
439 | } | |
440 | ||
441 | addFields(items); | |
122a2079 | 442 | }, |
09d64465 | 443 | }); |