]>
Commit | Line | Data |
---|---|---|
7b608503 DC |
1 | Ext.define('PBS.TapeManagement.DriveStatus', { |
2 | extend: 'Ext.panel.Panel', | |
3 | alias: 'widget.pbsDriveStatus', | |
4 | mixins: ['Proxmox.Mixin.CBind'], | |
5 | ||
fd641b99 DM |
6 | tools: [PBS.Utils.get_help_tool("tape_backup")], |
7 | ||
7b608503 DC |
8 | cbindData: function(config) { |
9 | let me = this; | |
10 | me.setTitle(`${gettext('Drive')}: ${me.drive}`); | |
a4003d90 | 11 | let baseurl = `/api2/json/tape/drive/${me.drive}/`; |
7b608503 | 12 | return { |
a4003d90 DC |
13 | driveStatusUrl: `${baseurl}/status`, |
14 | cartridgeMemoryUrl: `${baseurl}/cartridge-memory`, | |
7b608503 DC |
15 | }; |
16 | }, | |
17 | ||
a4003d90 DC |
18 | layout: { |
19 | type: 'vbox', | |
20 | align: 'stretch', | |
21 | }, | |
7b608503 DC |
22 | |
23 | bodyPadding: 5, | |
24 | ||
41f1132e DC |
25 | viewModel: { |
26 | data: { | |
27 | online: false, | |
6f3714b9 DC |
28 | busy: true, |
29 | loaded: false, | |
41f1132e DC |
30 | }, |
31 | }, | |
32 | ||
7b608503 DC |
33 | controller: { |
34 | xclass: 'Ext.app.ViewController', | |
35 | ||
69e5ba29 DC |
36 | reloadTapeStore: function() { |
37 | Ext.ComponentQuery.query('navigationtree')[0].reloadTapeStore(); | |
38 | }, | |
39 | ||
7b608503 DC |
40 | reload: function() { |
41 | let me = this; | |
42 | me.lookup('statusgrid').rstore.load(); | |
43 | }, | |
41f1132e DC |
44 | |
45 | onLoad: function() { | |
46 | let me = this; | |
47 | let statusgrid = me.lookup('statusgrid'); | |
48c4193f | 48 | let online = statusgrid.getObjectValue('file-number') !== undefined; |
41f1132e DC |
49 | let vm = me.getViewModel(); |
50 | vm.set('online', online); | |
646fc7f0 DC |
51 | let title = online ? gettext('Status') : gettext('Status (No Tape loaded)'); |
52 | statusgrid.setTitle(title); | |
69e5ba29 | 53 | Ext.ComponentQuery.query('navigationtree')[0].reloadTapeStore(); |
41f1132e DC |
54 | }, |
55 | ||
6f3714b9 DC |
56 | onStateLoad: function(store) { |
57 | let me = this; | |
58 | let view = me.getView(); | |
59 | let vm = me.getViewModel(); | |
60 | let driveRecord = store.findRecord('name', view.drive, 0, false, true, true); | |
61 | let busy = !!driveRecord.data.state; | |
62 | vm.set('busy', busy); | |
63 | let statusgrid = me.lookup('statusgrid'); | |
64 | if (!vm.get('loaded')) { | |
65 | if (busy) { | |
66 | // have to use a timeout so that the component can be rendered first | |
67 | // otherwise the 'mask' call errors out | |
68 | setTimeout(function() { | |
69 | statusgrid.mask(gettext('Drive is busy')); | |
70 | }, 10); | |
71 | } else { | |
72 | // have to use a timeout so that the component can be rendered first | |
73 | // otherwise the 'mask' call errors out | |
74 | setTimeout(function() { | |
75 | statusgrid.unmask(); | |
76 | }, 10); | |
77 | me.reload(); | |
78 | vm.set('loaded', true); | |
79 | } | |
80 | } | |
81 | }, | |
82 | ||
41f1132e DC |
83 | labelMedia: function() { |
84 | let me = this; | |
85 | Ext.create('PBS.TapeManagement.LabelMediaWindow', { | |
86 | driveid: me.getView().drive, | |
69e5ba29 DC |
87 | apiCallDone: function(success) { |
88 | if (success) { | |
89 | me.reloadTapeStore(); | |
90 | } | |
91 | }, | |
41f1132e DC |
92 | }).show(); |
93 | }, | |
94 | ||
e29f456e | 95 | format: function() { |
30a08095 DC |
96 | let me = this; |
97 | let view = me.getView(); | |
98 | let driveid = view.drive; | |
e29f456e | 99 | PBS.Utils.driveCommand(driveid, 'format-media', { |
30a08095 DC |
100 | waitMsgTarget: view, |
101 | method: 'POST', | |
102 | success: function(response) { | |
69e5ba29 | 103 | me.reloadTapeStore(); |
30a08095 DC |
104 | Ext.create('Proxmox.window.TaskProgress', { |
105 | upid: response.result.data, | |
106 | taskDone: function() { | |
107 | me.reload(); | |
108 | }, | |
109 | }).show(); | |
110 | }, | |
111 | }); | |
112 | }, | |
113 | ||
b83e136f | 114 | ejectMedia: function() { |
41f1132e DC |
115 | let me = this; |
116 | let view = me.getView(); | |
117 | let driveid = view.drive; | |
118 | PBS.Utils.driveCommand(driveid, 'eject-media', { | |
119 | waitMsgTarget: view, | |
120 | method: 'POST', | |
121 | success: function(response) { | |
69e5ba29 | 122 | me.reloadTapeStore(); |
41f1132e DC |
123 | Ext.create('Proxmox.window.TaskProgress', { |
124 | upid: response.result.data, | |
125 | taskDone: function() { | |
126 | me.reload(); | |
127 | }, | |
128 | }).show(); | |
129 | }, | |
130 | }); | |
131 | }, | |
132 | ||
133 | catalog: function() { | |
134 | let me = this; | |
135 | let view = me.getView(); | |
136 | let drive = view.drive; | |
137 | PBS.Utils.driveCommand(drive, 'catalog', { | |
138 | waitMsgTarget: view, | |
139 | method: 'POST', | |
140 | success: function(response) { | |
69e5ba29 | 141 | me.reloadTapeStore(); |
41f1132e DC |
142 | Ext.create('Proxmox.window.TaskViewer', { |
143 | upid: response.result.data, | |
144 | taskDone: function() { | |
145 | me.reload(); | |
146 | }, | |
147 | }).show(); | |
148 | }, | |
149 | }); | |
150 | }, | |
151 | ||
d0a0bad9 DC |
152 | readLabel: function() { |
153 | let me = this; | |
154 | let view = me.getView(); | |
155 | let drive = view.drive; | |
156 | ||
157 | PBS.Utils.driveCommand(drive, 'read-label', { | |
158 | waitMsgTarget: view, | |
69e5ba29 DC |
159 | success: function(response) { |
160 | me.reloadTapeStore(); | |
161 | PBS.Utils.showMediaLabelWindow(response); | |
162 | }, | |
d0a0bad9 DC |
163 | }); |
164 | }, | |
165 | ||
166 | volumeStatistics: function() { | |
167 | let me = this; | |
168 | let view = me.getView(); | |
169 | let drive = view.drive; | |
170 | PBS.Utils.driveCommand(drive, 'volume-statistics', { | |
171 | waitMsgTarget: view, | |
69e5ba29 DC |
172 | success: function(response) { |
173 | me.reloadTapeStore(); | |
174 | PBS.Utils.showVolumeStatisticsWindow(response); | |
175 | }, | |
d0a0bad9 DC |
176 | }); |
177 | }, | |
178 | ||
9bcdade8 DM |
179 | cartridgeMemory: function() { |
180 | let me = this; | |
181 | let view = me.getView(); | |
182 | let drive = view.drive; | |
183 | PBS.Utils.driveCommand(drive, 'cartridge-memory', { | |
184 | waitMsgTarget: me.getView(), | |
69e5ba29 DC |
185 | success: function(response) { |
186 | me.reloadTapeStore(); | |
187 | PBS.Utils.showCartridgeMemoryWindow(response); | |
188 | }, | |
9bcdade8 DM |
189 | }); |
190 | }, | |
191 | ||
41f1132e DC |
192 | init: function(view) { |
193 | let me = this; | |
194 | me.mon(me.lookup('statusgrid').getStore().rstore, 'load', 'onLoad'); | |
fa29d7eb | 195 | let tapeStore = Ext.ComponentQuery.query('navigationtree')[0].tapeStore; |
6f3714b9 DC |
196 | me.mon(tapeStore, 'load', 'onStateLoad'); |
197 | if (tapeStore.isLoaded()) { | |
198 | me.onStateLoad(tapeStore); | |
199 | } | |
41f1132e | 200 | }, |
7b608503 DC |
201 | }, |
202 | ||
7b608503 DC |
203 | tbar: [ |
204 | { | |
205 | xtype: 'proxmoxButton', | |
206 | handler: 'reload', | |
207 | text: gettext('Reload'), | |
6f3714b9 DC |
208 | disabled: true, |
209 | bind: { | |
210 | disabled: '{busy}', | |
211 | }, | |
7b608503 | 212 | }, |
41f1132e DC |
213 | '-', |
214 | { | |
215 | text: gettext('Label Media'), | |
216 | xtype: 'proxmoxButton', | |
217 | handler: 'labelMedia', | |
218 | iconCls: 'fa fa-barcode', | |
219 | disabled: true, | |
220 | bind: { | |
221 | disabled: '{!online}', | |
222 | }, | |
223 | }, | |
224 | { | |
225 | text: gettext('Eject'), | |
226 | xtype: 'proxmoxButton', | |
227 | handler: 'ejectMedia', | |
228 | iconCls: 'fa fa-eject', | |
229 | disabled: true, | |
230 | bind: { | |
231 | disabled: '{!online}', | |
232 | }, | |
233 | }, | |
30a08095 | 234 | { |
e29f456e | 235 | text: gettext('Format'), |
30a08095 | 236 | xtype: 'proxmoxButton', |
e29f456e | 237 | handler: 'format', |
30a08095 DC |
238 | iconCls: 'fa fa-trash-o', |
239 | dangerous: true, | |
a2e30cd5 | 240 | confirmMsg: gettext('Are you sure you want to format the inserted tape?'), |
30a08095 DC |
241 | disabled: true, |
242 | bind: { | |
243 | disabled: '{!online}', | |
244 | }, | |
245 | }, | |
41f1132e DC |
246 | { |
247 | text: gettext('Catalog'), | |
248 | xtype: 'proxmoxButton', | |
249 | handler: 'catalog', | |
250 | iconCls: 'fa fa-book', | |
251 | disabled: true, | |
252 | bind: { | |
253 | disabled: '{!online}', | |
254 | }, | |
255 | }, | |
d0a0bad9 DC |
256 | { |
257 | text: gettext('Read Label'), | |
258 | xtype: 'proxmoxButton', | |
259 | handler: 'readLabel', | |
260 | iconCls: 'fa fa-tag', | |
261 | disabled: true, | |
262 | bind: { | |
263 | disabled: '{!online}', | |
264 | }, | |
265 | }, | |
266 | { | |
9bcdade8 | 267 | text: gettext('Volume Statistics'), |
d0a0bad9 DC |
268 | xtype: 'proxmoxButton', |
269 | handler: 'volumeStatistics', | |
270 | iconCls: 'fa fa-line-chart', | |
271 | disabled: true, | |
272 | bind: { | |
273 | disabled: '{!online}', | |
274 | }, | |
275 | }, | |
9bcdade8 DM |
276 | { |
277 | text: gettext('Cartridge Memory'), | |
278 | xtype: 'proxmoxButton', | |
279 | iconCls: 'fa fa-hdd-o', | |
280 | handler: 'cartridgeMemory', | |
281 | disabled: true, | |
282 | bind: { | |
283 | disabled: '{!online}', | |
284 | }, | |
285 | }, | |
d0a0bad9 | 286 | |
7b608503 DC |
287 | ], |
288 | ||
289 | items: [ | |
290 | { | |
291 | xtype: 'container', | |
292 | layout: { | |
293 | type: 'hbox', | |
294 | align: 'stretch', | |
295 | }, | |
296 | defaults: { | |
297 | padding: 5, | |
298 | flex: 1, | |
299 | }, | |
300 | items: [ | |
301 | { | |
302 | xtype: 'pbsDriveInfoPanel', | |
303 | cbind: { | |
304 | drive: '{drive}', | |
305 | }, | |
306 | }, | |
307 | { | |
308 | xtype: 'pbsDriveStatusGrid', | |
309 | reference: 'statusgrid', | |
310 | cbind: { | |
311 | url: '{driveStatusUrl}', | |
312 | }, | |
313 | }, | |
314 | ], | |
315 | }, | |
316 | ], | |
317 | }); | |
318 | ||
319 | Ext.define('PBS.TapeManagement.DriveStatusGrid', { | |
320 | extend: 'Proxmox.grid.ObjectGrid', | |
321 | alias: 'widget.pbsDriveStatusGrid', | |
322 | ||
323 | title: gettext('Status'), | |
324 | ||
325 | rows: { | |
48c4193f DM |
326 | 'density': { |
327 | required: true, | |
328 | header: gettext('Tape Density'), | |
329 | }, | |
7b608503 DC |
330 | 'blocksize': { |
331 | required: true, | |
84314647 | 332 | header: gettext('Block Size'), |
7b608503 DC |
333 | renderer: function(value) { |
334 | if (!value) { | |
335 | return gettext('Dynamic'); | |
336 | } | |
337 | return `${gettext('Fixed')} - ${Proxmox.Utils.format_size(value)}`; | |
338 | }, | |
339 | }, | |
48c4193f | 340 | 'write-protect': { |
7b608503 | 341 | required: true, |
48c4193f DM |
342 | header: gettext('Write Protect'), |
343 | defaultValue: false, | |
511e4f69 | 344 | renderer: Proxmox.Utils.format_boolean, |
7b608503 | 345 | }, |
48c4193f DM |
346 | 'compression': { |
347 | required: true, | |
348 | header: gettext('Compression'), | |
511e4f69 | 349 | renderer: Proxmox.Utils.format_boolean, |
48c4193f | 350 | }, |
1d6b1e02 DC |
351 | 'drive-activity': { |
352 | header: gettext('Drive Activity'), | |
353 | renderer: PBS.Utils.renderDriveActivity, | |
354 | }, | |
48c4193f | 355 | 'file-number': { |
511e4f69 DC |
356 | header: gettext('Tape Position'), |
357 | renderer: function(value, mD, r, rI, cI, store) { | |
358 | let me = this; | |
359 | let filenr = value; | |
360 | let rec = store.getById('block-number'); | |
361 | if (rec) { | |
362 | let blocknr = rec.data.value; | |
363 | return `File ${filenr}, Block ${blocknr}`; | |
364 | } | |
365 | return `File ${filenr}`; | |
366 | }, | |
48c4193f DM |
367 | }, |
368 | 'block-number': { | |
511e4f69 | 369 | visible: false, |
7b608503 DC |
370 | }, |
371 | 'manufactured': { | |
372 | header: gettext('Tape Manufacture Date'), | |
373 | renderer: function(value) { | |
374 | if (value) { | |
b0156179 | 375 | return Ext.Date.format(new Date(value*1000), "Y-m-d"); |
7b608503 DC |
376 | } |
377 | return ""; | |
378 | }, | |
379 | }, | |
380 | 'bytes-read': { | |
381 | header: gettext('Tape Read'), | |
382 | renderer: Proxmox.Utils.format_size, | |
383 | }, | |
384 | 'bytes-written': { | |
385 | header: gettext('Tape Written'), | |
386 | renderer: Proxmox.Utils.format_size, | |
387 | }, | |
e0f68926 DC |
388 | 'medium-passes': { |
389 | header: gettext('Tape Passes'), | |
390 | }, | |
391 | 'medium-wearout': { | |
392 | header: gettext('Tape Wearout'), | |
ac4a1fb3 DM |
393 | renderer: function(value) { |
394 | if (value !== undefined) { | |
395 | return (value*100).toFixed(2) + "%"; | |
396 | } | |
397 | return value; | |
398 | }, | |
e0f68926 | 399 | }, |
511e4f69 DC |
400 | 'alert-flags': { |
401 | header: gettext('Alert Flags'), | |
402 | }, | |
7b608503 DC |
403 | }, |
404 | }); | |
405 | ||
406 | Ext.define('PBS.TapeManagement.DriveInfoPanel', { | |
407 | extend: 'Ext.panel.Panel', | |
408 | alias: 'widget.pbsDriveInfoPanel', | |
409 | ||
410 | title: gettext('Information'), | |
411 | ||
412 | defaults: { | |
413 | printBar: false, | |
414 | padding: 5, | |
415 | }, | |
416 | bodyPadding: 15, | |
417 | ||
418 | viewModel: { | |
d810014e DC |
419 | data: { |
420 | drive: {}, | |
421 | }, | |
422 | ||
423 | formulas: { | |
424 | driveState: function(get) { | |
425 | let drive = get('drive'); | |
426 | return PBS.Utils.renderDriveState(drive.state, {}); | |
427 | }, | |
428 | }, | |
7b608503 DC |
429 | }, |
430 | ||
431 | items: [ | |
432 | { | |
433 | xtype: 'pmxInfoWidget', | |
434 | title: gettext('Name'), | |
435 | bind: { | |
436 | data: { | |
d810014e | 437 | text: '{drive.name}', |
7b608503 DC |
438 | }, |
439 | }, | |
440 | }, | |
441 | { | |
442 | xtype: 'pmxInfoWidget', | |
443 | title: gettext('Vendor'), | |
444 | bind: { | |
445 | data: { | |
d810014e | 446 | text: '{drive.vendor}', |
7b608503 DC |
447 | }, |
448 | }, | |
449 | }, | |
450 | { | |
451 | xtype: 'pmxInfoWidget', | |
452 | title: gettext('Model'), | |
453 | bind: { | |
454 | data: { | |
d810014e | 455 | text: '{drive.model}', |
7b608503 DC |
456 | }, |
457 | }, | |
458 | }, | |
459 | { | |
460 | xtype: 'pmxInfoWidget', | |
461 | title: gettext('Serial'), | |
462 | bind: { | |
463 | data: { | |
d810014e | 464 | text: '{drive.serial}', |
7b608503 DC |
465 | }, |
466 | }, | |
467 | }, | |
468 | { | |
469 | xtype: 'pmxInfoWidget', | |
470 | title: gettext('Path'), | |
471 | bind: { | |
472 | data: { | |
d810014e DC |
473 | text: '{drive.path}', |
474 | }, | |
475 | }, | |
476 | }, | |
477 | { | |
478 | xtype: 'pmxInfoWidget', | |
84d32846 | 479 | reference: 'statewidget', |
d810014e DC |
480 | title: gettext('State'), |
481 | bind: { | |
482 | data: { | |
483 | text: '{driveState}', | |
7b608503 DC |
484 | }, |
485 | }, | |
486 | }, | |
487 | ], | |
488 | ||
84d32846 DC |
489 | clickState: function(e, t, eOpts) { |
490 | let me = this; | |
491 | let vm = me.getViewModel(); | |
492 | let drive = vm.get('drive'); | |
493 | if (t.classList.contains('right-aligned')) { | |
494 | let upid = drive.state; | |
495 | if (!upid || !upid.startsWith("UPID")) { | |
496 | return; | |
497 | } | |
498 | ||
499 | Ext.create('Proxmox.window.TaskViewer', { | |
500 | autoShow: true, | |
501 | upid, | |
502 | }); | |
503 | } | |
504 | }, | |
505 | ||
d810014e | 506 | updateData: function(store) { |
7b608503 | 507 | let me = this; |
d810014e DC |
508 | if (!store) { |
509 | return; | |
510 | } | |
511 | let record = store.findRecord('name', me.drive, 0, false, true, true); | |
7b608503 DC |
512 | if (!record) { |
513 | return; | |
514 | } | |
515 | ||
516 | let vm = me.getViewModel(); | |
d810014e | 517 | vm.set('drive', record.data); |
825dfe7e DC |
518 | vm.notify(); |
519 | me.updatePointer(); | |
520 | }, | |
521 | ||
522 | updatePointer: function() { | |
523 | let me = this; | |
84d32846 DC |
524 | let stateWidget = me.down('pmxInfoWidget[reference=statewidget]'); |
525 | let stateEl = stateWidget.getEl(); | |
825dfe7e DC |
526 | if (!stateEl) { |
527 | setTimeout(function() { | |
528 | me.updatePointer(); | |
529 | }, 100); | |
530 | return; | |
531 | } | |
532 | ||
533 | let vm = me.getViewModel(); | |
534 | let drive = vm.get('drive'); | |
535 | ||
536 | if (drive.state) { | |
84d32846 DC |
537 | stateEl.addCls('info-pointer'); |
538 | } else { | |
539 | stateEl.removeCls('info-pointer'); | |
540 | } | |
825dfe7e | 541 | }, |
84d32846 | 542 | |
825dfe7e DC |
543 | listeners: { |
544 | afterrender: function() { | |
545 | let me = this; | |
546 | let stateWidget = me.down('pmxInfoWidget[reference=statewidget]'); | |
547 | let stateEl = stateWidget.getEl(); | |
548 | stateEl.on('click', me.clickState, me); | |
549 | }, | |
7b608503 DC |
550 | }, |
551 | ||
552 | initComponent: function() { | |
553 | let me = this; | |
554 | if (!me.drive) { | |
555 | throw "no drive given"; | |
556 | } | |
557 | ||
825dfe7e DC |
558 | me.callParent(); |
559 | ||
fa29d7eb | 560 | let tapeStore = Ext.ComponentQuery.query('navigationtree')[0].tapeStore; |
d810014e DC |
561 | me.mon(tapeStore, 'load', me.updateData, me); |
562 | if (tapeStore.isLoaded()) { | |
563 | me.updateData(tapeStore); | |
7b608503 | 564 | } |
7b608503 DC |
565 | }, |
566 | }); |