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