]>
Commit | Line | Data |
---|---|---|
a83cedc2 DC |
1 | Ext.define('pbs-slot-model', { |
2 | extend: 'Ext.data.Model', | |
b5af9333 | 3 | fields: ['entry-id', 'label-text', 'is-labeled', ' model', 'name', 'vendor', 'serial', 'state', 'status', 'pool', 'activity', |
a83cedc2 DC |
4 | { |
5 | name: 'is-blocked', | |
6 | calculate: function(data) { | |
7 | return data.state !== undefined; | |
8 | }, | |
9 | }, | |
d1bee434 DC |
10 | { |
11 | name: 'is-empty', | |
12 | calculate: function(data) { | |
13 | return data['label-text'] === undefined; | |
14 | }, | |
15 | }, | |
a83cedc2 DC |
16 | ], |
17 | idProperty: 'entry-id', | |
18 | }); | |
19 | ||
70fab5b4 DC |
20 | Ext.define('PBS.TapeManagement.FreeSlotSelector', { |
21 | extend: 'Proxmox.form.ComboGrid', | |
22 | alias: 'widget.pbsFreeSlotSelector', | |
23 | ||
24 | valueField: 'id', | |
25 | displayField: 'id', | |
26 | ||
27 | listConfig: { | |
28 | columns: [ | |
29 | { | |
30 | dataIndex: 'id', | |
31 | text: gettext('ID'), | |
32 | flex: 1, | |
33 | }, | |
34 | { | |
35 | dataIndex: 'type', | |
36 | text: gettext('Type'), | |
37 | flex: 1, | |
38 | }, | |
39 | ], | |
40 | }, | |
41 | }); | |
42 | ||
fd9aa8df DC |
43 | Ext.define('PBS.TapeManagement.ChangerStatus', { |
44 | extend: 'Ext.panel.Panel', | |
45 | alias: 'widget.pbsChangerStatus', | |
46 | ||
fd641b99 DM |
47 | tools: [PBS.Utils.get_help_tool("tape_backup")], |
48 | ||
fd9aa8df DC |
49 | controller: { |
50 | xclass: 'Ext.app.ViewController', | |
51 | ||
7eefd0c3 | 52 | importTape: function(v, rI, cI, button, el, record) { |
fd9aa8df DC |
53 | let me = this; |
54 | let view = me.getView(); | |
58791864 | 55 | let from = record.data['entry-id']; |
7eefd0c3 | 56 | let changer = encodeURIComponent(view.changer); |
58791864 DC |
57 | Ext.create('Proxmox.window.Edit', { |
58 | title: gettext('Import'), | |
59 | isCreate: true, | |
60 | submitText: gettext('OK'), | |
61 | method: 'POST', | |
62 | url: `/api2/extjs/tape/changer/${changer}/transfer`, | |
44192580 DC |
63 | submitOptions: { |
64 | timeout: 3*60*1000, | |
65 | }, | |
58791864 DC |
66 | items: [ |
67 | { | |
68 | xtype: 'displayfield', | |
69 | name: 'from', | |
70 | value: from, | |
71 | submitValue: true, | |
72 | fieldLabel: gettext('From Slot'), | |
73 | }, | |
74 | { | |
70fab5b4 | 75 | xtype: 'pbsFreeSlotSelector', |
58791864 DC |
76 | name: 'to', |
77 | fieldLabel: gettext('To Slot'), | |
70fab5b4 DC |
78 | store: { |
79 | data: me.free_slots, | |
80 | }, | |
58791864 DC |
81 | }, |
82 | ], | |
83 | listeners: { | |
84 | destroy: function() { | |
85 | me.reload(); | |
86 | }, | |
87 | }, | |
88 | }).show(); | |
89 | }, | |
90 | ||
7eefd0c3 | 91 | slotTransfer: function(v, rI, cI, button, el, record) { |
fd9aa8df | 92 | let me = this; |
7eefd0c3 | 93 | let view = me.getView(); |
fd9aa8df | 94 | let from = record.data['entry-id']; |
7eefd0c3 | 95 | let changer = encodeURIComponent(view.changer); |
fd9aa8df DC |
96 | Ext.create('Proxmox.window.Edit', { |
97 | title: gettext('Transfer'), | |
98 | isCreate: true, | |
99 | submitText: gettext('OK'), | |
100 | method: 'POST', | |
101 | url: `/api2/extjs/tape/changer/${changer}/transfer`, | |
44192580 DC |
102 | submitOptions: { |
103 | timeout: 3*60*1000, | |
104 | }, | |
fd9aa8df DC |
105 | items: [ |
106 | { | |
107 | xtype: 'displayfield', | |
108 | name: 'from', | |
109 | value: from, | |
110 | submitValue: true, | |
111 | fieldLabel: gettext('From Slot'), | |
112 | }, | |
113 | { | |
70fab5b4 | 114 | xtype: 'pbsFreeSlotSelector', |
fd9aa8df DC |
115 | name: 'to', |
116 | fieldLabel: gettext('To Slot'), | |
70fab5b4 DC |
117 | store: { |
118 | data: me.free_slots.concat(me.free_ie_slots), | |
119 | }, | |
fd9aa8df DC |
120 | }, |
121 | ], | |
122 | listeners: { | |
123 | destroy: function() { | |
124 | me.reload(); | |
125 | }, | |
126 | }, | |
127 | }).show(); | |
128 | }, | |
129 | ||
d4bfdfe7 DM |
130 | labelMedia: function(button, event, record) { |
131 | let me = this; | |
d4bfdfe7 DM |
132 | Ext.create('PBS.TapeManagement.LabelMediaWindow', { |
133 | driveid: record.data.name, | |
3c715edd | 134 | label: record.data["label-text"], |
d4bfdfe7 DM |
135 | }).show(); |
136 | }, | |
137 | ||
2af8b8ef DM |
138 | catalog: function(button, event, record) { |
139 | let me = this; | |
140 | ||
141 | let view = me.getView(); | |
142 | PBS.Utils.driveCommand(record.data.name, 'catalog', { | |
143 | waitMsgTarget: view, | |
144 | method: 'POST', | |
145 | success: function(response) { | |
146 | Ext.create('Proxmox.window.TaskViewer', { | |
147 | upid: response.result.data, | |
148 | }).show(); | |
149 | }, | |
150 | }); | |
151 | }, | |
152 | ||
983edbc5 DC |
153 | 'format-inserted': function(button, event, record) { |
154 | let me = this; | |
155 | ||
156 | let view = me.getView(); | |
157 | PBS.Utils.driveCommand(record.data.name, 'format-media', { | |
158 | waitMsgTarget: view, | |
159 | method: 'POST', | |
160 | success: function(response) { | |
161 | Ext.create('Proxmox.window.TaskProgress', { | |
162 | upid: response.result.data, | |
163 | taskDone: function() { | |
164 | me.reload(); | |
165 | }, | |
166 | }).show(); | |
167 | }, | |
168 | }); | |
169 | }, | |
170 | ||
a2e30cd5 | 171 | format: function(v, rI, cI, button, el, record) { |
85205bc2 | 172 | let me = this; |
7eefd0c3 | 173 | let view = me.getView(); |
85205bc2 DC |
174 | let label = record.data['label-text']; |
175 | ||
7eefd0c3 | 176 | let changer = encodeURIComponent(view.changer); |
88e1f799 | 177 | let singleDrive = me.drives.length === 1 ? me.drives[0] : undefined; |
85205bc2 DC |
178 | Ext.create('PBS.TapeManagement.EraseWindow', { |
179 | label, | |
180 | changer, | |
88e1f799 | 181 | singleDrive, |
85205bc2 DC |
182 | listeners: { |
183 | destroy: function() { | |
184 | me.reload(); | |
185 | }, | |
186 | }, | |
187 | }).show(); | |
188 | }, | |
189 | ||
7eefd0c3 | 190 | load: function(v, rI, cI, button, el, record) { |
fd9aa8df | 191 | let me = this; |
7eefd0c3 | 192 | let view = me.getView(); |
fd9aa8df | 193 | let label = record.data['label-text']; |
d1bee434 | 194 | let slot = record.data['entry-id']; |
fd9aa8df | 195 | |
7eefd0c3 | 196 | let changer = encodeURIComponent(view.changer); |
dff8ea92 | 197 | let singleDrive = me.drives.length === 1 ? me.drives[0] : undefined; |
fd9aa8df | 198 | |
d1bee434 DC |
199 | let apiCall = label !== "" ? 'load-media' : 'load-slot'; |
200 | let params = label !== "" ? { 'label-text': label } : { 'source-slot': slot }; | |
201 | ||
dff8ea92 DC |
202 | if (singleDrive !== undefined) { |
203 | Proxmox.Utils.API2Request({ | |
204 | method: 'POST', | |
d1bee434 DC |
205 | params, |
206 | url: `/api2/extjs/tape/drive/${singleDrive}/${apiCall}`, | |
dff8ea92 DC |
207 | success: function(response, opt) { |
208 | Ext.create('Proxmox.window.TaskProgress', { | |
209 | upid: response.result.data, | |
210 | taskDone: function(success) { | |
211 | me.reload(); | |
212 | }, | |
213 | }).show(); | |
fd9aa8df | 214 | }, |
dff8ea92 DC |
215 | failure: function(response, opt) { |
216 | Ext.Msg.alert(gettext('Error'), response.htmlStatus); | |
fd9aa8df | 217 | }, |
dff8ea92 DC |
218 | }); |
219 | } else { | |
220 | Ext.create('Proxmox.window.Edit', { | |
221 | isCreate: true, | |
222 | autoShow: true, | |
223 | submitText: gettext('OK'), | |
224 | title: gettext('Load Media into Drive'), | |
225 | url: `/api2/extjs/tape/drive`, | |
226 | method: 'POST', | |
227 | submitUrl: function(url, values) { | |
228 | let drive = values.drive; | |
229 | delete values.drive; | |
d1bee434 | 230 | return `${url}/${encodeURIComponent(drive)}/${apiCall}`; |
dff8ea92 DC |
231 | }, |
232 | items: [ | |
10f788b7 | 233 | label !== "" ? { |
dff8ea92 DC |
234 | xtype: 'displayfield', |
235 | name: 'label-text', | |
236 | value: label, | |
237 | submitValue: true, | |
238 | fieldLabel: gettext('Media'), | |
d1bee434 DC |
239 | } : { |
240 | xtype: 'displayfield', | |
241 | name: 'source-slot', | |
242 | value: slot, | |
243 | submitValue: true, | |
244 | fieldLabel: gettext('Source Slot'), | |
dff8ea92 DC |
245 | }, |
246 | { | |
247 | xtype: 'pbsDriveSelector', | |
248 | fieldLabel: gettext('Drive'), | |
249 | changer: changer, | |
250 | name: 'drive', | |
251 | }, | |
252 | ], | |
253 | listeners: { | |
254 | destroy: function() { | |
255 | me.reload(); | |
256 | }, | |
257 | }, | |
258 | }); | |
259 | } | |
fd9aa8df DC |
260 | }, |
261 | ||
7eefd0c3 | 262 | unload: async function(v, rI, cI, button, el, record) { |
fd9aa8df DC |
263 | let me = this; |
264 | let drive = record.data.name; | |
fd9aa8df | 265 | try { |
3006d70e | 266 | await Proxmox.Async.api2({ |
918a3672 | 267 | method: 'POST', |
b0338178 | 268 | timeout: 5*60*1000, |
fd9aa8df DC |
269 | url: `/api2/extjs/tape/drive/${encodeURIComponent(drive)}/unload`, |
270 | }); | |
3006d70e TL |
271 | } catch (response) { |
272 | Ext.Msg.alert(gettext('Error'), response.result.message); | |
fd9aa8df | 273 | } |
4f688e09 | 274 | me.reload(); |
fd9aa8df DC |
275 | }, |
276 | ||
fd9aa8df DC |
277 | cartridgeMemory: function(view, rI, cI, button, el, record) { |
278 | let me = this; | |
279 | let drive = record.data.name; | |
3d3e31b7 DM |
280 | PBS.Utils.driveCommand(drive, 'cartridge-memory', { |
281 | waitMsgTarget: me.getView(), | |
282 | success: PBS.Utils.showCartridgeMemoryWindow, | |
fd9aa8df DC |
283 | }); |
284 | }, | |
285 | ||
bbe05d7f | 286 | cleanDrive: function(button, event, record) { |
fd9aa8df | 287 | let me = this; |
3d3e31b7 DM |
288 | PBS.Utils.driveCommand(record.data.name, 'clean', { |
289 | waitMsgTarget: me.getView(), | |
3d3e31b7 | 290 | method: 'PUT', |
2970cd3d DM |
291 | success: function(response) { |
292 | Ext.create('Proxmox.window.TaskProgress', { | |
293 | upid: response.result.data, | |
294 | taskDone: function() { | |
295 | me.reload(); | |
296 | }, | |
297 | }).show(); | |
298 | }, | |
3d3e31b7 | 299 | }); |
fd9aa8df DC |
300 | }, |
301 | ||
302 | volumeStatistics: function(view, rI, cI, button, el, record) { | |
303 | let me = this; | |
304 | let drive = record.data.name; | |
3d3e31b7 DM |
305 | PBS.Utils.driveCommand(drive, 'volume-statistics', { |
306 | waitMsgTarget: me.getView(), | |
307 | success: PBS.Utils.showVolumeStatisticsWindow, | |
fd9aa8df DC |
308 | }); |
309 | }, | |
310 | ||
311 | readLabel: function(view, rI, cI, button, el, record) { | |
312 | let me = this; | |
313 | let drive = record.data.name; | |
fd9aa8df | 314 | |
3d3e31b7 DM |
315 | PBS.Utils.driveCommand(drive, 'read-label', { |
316 | waitMsgTarget: me.getView(), | |
317 | success: PBS.Utils.showMediaLabelWindow, | |
fd9aa8df DC |
318 | }); |
319 | }, | |
320 | ||
321 | status: function(view, rI, cI, button, el, record) { | |
322 | let me = this; | |
323 | let drive = record.data.name; | |
3d3e31b7 DM |
324 | PBS.Utils.driveCommand(drive, 'status', { |
325 | waitMsgTarget: me.getView(), | |
326 | success: PBS.Utils.showDriveStatusWindow, | |
fd9aa8df DC |
327 | }); |
328 | }, | |
329 | ||
330 | reloadList: function() { | |
331 | let me = this; | |
332 | me.lookup('changerselector').getStore().load(); | |
333 | }, | |
334 | ||
335 | barcodeLabel: function() { | |
336 | let me = this; | |
7eefd0c3 DC |
337 | let view = me.getView(); |
338 | let changer = view.changer; | |
fd9aa8df DC |
339 | if (changer === '') { |
340 | return; | |
341 | } | |
342 | ||
3f0e344b DC |
343 | let singleDrive = me.drives.length === 1 ? me.drives[0] : undefined; |
344 | ||
fd9aa8df DC |
345 | Ext.create('Proxmox.window.Edit', { |
346 | title: gettext('Barcode Label'), | |
347 | showTaskViewer: true, | |
b8d526f1 | 348 | method: 'POST', |
fd9aa8df DC |
349 | url: '/api2/extjs/tape/drive', |
350 | submitUrl: function(url, values) { | |
351 | let drive = values.drive; | |
352 | delete values.drive; | |
353 | return `${url}/${encodeURIComponent(drive)}/barcode-label-media`; | |
354 | }, | |
355 | ||
356 | items: [ | |
357 | { | |
3f0e344b | 358 | xtype: singleDrive === undefined ? 'pbsDriveSelector' : 'displayfield', |
fd9aa8df | 359 | fieldLabel: gettext('Drive'), |
3f0e344b | 360 | submitValue: true, |
fd9aa8df | 361 | name: 'drive', |
3f0e344b | 362 | value: singleDrive, |
fd9aa8df DC |
363 | changer: changer, |
364 | }, | |
365 | { | |
366 | xtype: 'pbsMediaPoolSelector', | |
367 | fieldLabel: gettext('Pool'), | |
368 | name: 'pool', | |
369 | skipEmptyText: true, | |
370 | allowBlank: true, | |
371 | }, | |
372 | ], | |
373 | }).show(); | |
374 | }, | |
375 | ||
e2225aa8 DC |
376 | inventory: function() { |
377 | let me = this; | |
7eefd0c3 DC |
378 | let view = me.getView(); |
379 | let changer = view.changer; | |
e2225aa8 DC |
380 | if (changer === '') { |
381 | return; | |
382 | } | |
383 | ||
57ee4e9e DC |
384 | Ext.create('Proxmox.window.Edit', { |
385 | title: gettext('Inventory'), | |
386 | showTaskViewer: true, | |
387 | method: 'PUT', | |
388 | url: '/api2/extjs/tape/drive', | |
389 | submitUrl: function(url, values) { | |
390 | let drive = values.drive; | |
391 | delete values.drive; | |
392 | return `${url}/${encodeURIComponent(drive)}/inventory`; | |
393 | }, | |
e2225aa8 | 394 | |
57ee4e9e DC |
395 | items: [ |
396 | { | |
397 | xtype: 'pbsDriveSelector', | |
398 | labelWidth: 120, | |
399 | fieldLabel: gettext('Drive'), | |
400 | name: 'drive', | |
401 | changer: changer, | |
402 | autoSelect: true, | |
e2225aa8 | 403 | }, |
57ee4e9e DC |
404 | { |
405 | xtype: 'proxmoxcheckbox', | |
406 | labelWidth: 120, | |
407 | fieldLabel: gettext('Restore Catalogs'), | |
408 | name: 'catalog', | |
a3161787 | 409 | }, |
57ee4e9e DC |
410 | { |
411 | xtype: 'proxmoxcheckbox', | |
412 | labelWidth: 120, | |
413 | fieldLabel: gettext('Force all Tapes'), | |
414 | name: 'read-all-labels', | |
a3161787 | 415 | }, |
57ee4e9e DC |
416 | ], |
417 | }).show(); | |
e2225aa8 DC |
418 | }, |
419 | ||
076afa61 DC |
420 | scheduleReload: function(time) { |
421 | let me = this; | |
422 | if (me.reloadTimeout === undefined) { | |
423 | me.reloadTimeout = setTimeout(function() { | |
424 | me.reload(); | |
425 | }, time); | |
426 | } | |
427 | }, | |
428 | ||
9896a75c | 429 | cancelReload: function() { |
076afa61 DC |
430 | let me = this; |
431 | if (me.reloadTimeout !== undefined) { | |
432 | clearTimeout(me.reloadTimeout); | |
433 | me.reloadTimeout = undefined; | |
434 | } | |
9896a75c DC |
435 | }, |
436 | ||
437 | reload: function() { | |
438 | let me = this; | |
439 | me.cancelReload(); | |
076afa61 | 440 | me.reload_full(true); |
cbd98993 DM |
441 | }, |
442 | ||
443 | reload_no_cache: function() { | |
076afa61 DC |
444 | let me = this; |
445 | if (me.reloadTimeout !== undefined) { | |
446 | clearTimeout(me.reloadTimeout); | |
447 | me.reloadTimeout = undefined; | |
448 | } | |
449 | me.reload_full(false); | |
cbd98993 DM |
450 | }, |
451 | ||
4c3eabea DC |
452 | drives: [], |
453 | ||
454 | updateDrives: function(drives) { | |
455 | let me = this; | |
456 | me.drives = drives; | |
457 | }, | |
458 | ||
70fab5b4 | 459 | free_slots: [], |
4c7be5f5 | 460 | free_ie_slots: [], |
70fab5b4 DC |
461 | |
462 | updateFreeSlots: function(free_slots, free_ie_slots) { | |
463 | let me = this; | |
464 | me.free_slots = free_slots; | |
465 | me.free_ie_slots = free_ie_slots; | |
466 | }, | |
467 | ||
cbd98993 | 468 | reload_full: async function(use_cache) { |
fd9aa8df DC |
469 | let me = this; |
470 | let view = me.getView(); | |
7eefd0c3 | 471 | let changer = view.changer; |
fd9aa8df DC |
472 | if (changer === '') { |
473 | return; | |
474 | } | |
475 | ||
476 | try { | |
423e3cbd DC |
477 | if (!use_cache) { |
478 | Proxmox.Utils.setErrorMask(view, true); | |
479 | Proxmox.Utils.setErrorMask(me.lookup('content')); | |
480 | } | |
3006d70e | 481 | let status_fut = Proxmox.Async.api2({ |
b0338178 | 482 | timeout: 5*60*1000, |
cbd98993 | 483 | method: 'GET', |
fd9aa8df | 484 | url: `/api2/extjs/tape/changer/${encodeURIComponent(changer)}/status`, |
cbd98993 DM |
485 | params: { |
486 | cache: use_cache, | |
487 | }, | |
fd9aa8df | 488 | }); |
3006d70e | 489 | let drives_fut = Proxmox.Async.api2({ |
b0338178 | 490 | timeout: 5*60*1000, |
b5af9333 | 491 | url: `/api2/extjs/tape/drive?query-activity=true&changer=${encodeURIComponent(changer)}`, |
fd9aa8df DC |
492 | }); |
493 | ||
3006d70e | 494 | let tapes_fut = Proxmox.Async.api2({ |
b0338178 | 495 | timeout: 5*60*1000, |
42eef145 | 496 | url: '/api2/extjs/tape/media/list', |
aa16b7b2 DM |
497 | method: 'GET', |
498 | params: { | |
6ef8e290 | 499 | "update-status": false, |
6d62e69f | 500 | }, |
42eef145 DC |
501 | }); |
502 | ||
503 | let [status, drives, tapes_list] = await Promise.all([status_fut, drives_fut, tapes_fut]); | |
504 | ||
fd9aa8df DC |
505 | let data = { |
506 | slot: [], | |
507 | 'import-export': [], | |
508 | drive: [], | |
509 | }; | |
510 | ||
42eef145 DC |
511 | let tapes = {}; |
512 | ||
513 | for (const tape of tapes_list.result.data) { | |
bc02c278 DC |
514 | tapes[tape['label-text']] = { |
515 | labeled: true, | |
516 | pool: tape.pool, | |
517 | status: tape.expired ? 'expired' : tape.status, | |
518 | }; | |
42eef145 DC |
519 | } |
520 | ||
fd9aa8df DC |
521 | let drive_entries = {}; |
522 | ||
523 | for (const entry of drives.result.data) { | |
524 | drive_entries[entry['changer-drivenum'] || 0] = entry; | |
525 | } | |
526 | ||
70fab5b4 DC |
527 | let free_slots = []; |
528 | let free_ie_slots = []; | |
529 | ||
4c3eabea DC |
530 | let valid_drives = []; |
531 | ||
fd9aa8df DC |
532 | for (let entry of status.result.data) { |
533 | let type = entry['entry-kind']; | |
4c3eabea | 534 | let id = entry['entry-id']; |
fd9aa8df | 535 | |
23eed675 DC |
536 | if (type === 'drive') { |
537 | if (drive_entries[id] === undefined) { | |
538 | continue; | |
539 | } | |
540 | ||
4c3eabea DC |
541 | entry = Ext.applyIf(entry, drive_entries[id]); |
542 | valid_drives.push(drive_entries[id].name); | |
fd9aa8df DC |
543 | } |
544 | ||
bc02c278 DC |
545 | if (tapes[entry['label-text']] !== undefined) { |
546 | entry['is-labeled'] = true; | |
547 | entry.pool = tapes[entry['label-text']].pool; | |
548 | entry.status = tapes[entry['label-text']].status; | |
549 | } else { | |
550 | entry['is-labeled'] = false; | |
551 | } | |
42eef145 | 552 | |
70fab5b4 DC |
553 | if (!entry['label-text'] && type !== 'drive') { |
554 | if (type === 'slot') { | |
555 | free_slots.push({ | |
4c3eabea | 556 | id, |
70fab5b4 DC |
557 | type, |
558 | }); | |
559 | } else { | |
560 | free_ie_slots.push({ | |
4c3eabea | 561 | id, |
70fab5b4 DC |
562 | type, |
563 | }); | |
564 | } | |
565 | } | |
fd9aa8df DC |
566 | data[type].push(entry); |
567 | } | |
568 | ||
a83cedc2 DC |
569 | // the stores are diffstores and are only refreshed |
570 | // on a 'load' event, which does not trigger on 'setData' | |
571 | // so we have to fire them ourselves | |
fd9aa8df | 572 | |
a83cedc2 DC |
573 | me.lookup('slots').getStore().rstore.setData(data.slot); |
574 | me.lookup('slots').getStore().rstore.fireEvent('load', me, [], true); | |
575 | ||
576 | me.lookup('import_export').getStore().rstore.setData(data['import-export']); | |
577 | me.lookup('import_export').getStore().rstore.fireEvent('load', me, [], true); | |
578 | ||
579 | me.lookup('drives').getStore().rstore.setData(data.drive); | |
580 | me.lookup('drives').getStore().rstore.fireEvent('load', me, [], true); | |
fd9aa8df | 581 | |
3c715edd DM |
582 | // manually fire selectionchange to update button status |
583 | me.lookup('drives').getSelectionModel().fireEvent('selectionchange', me); | |
584 | ||
70fab5b4 | 585 | me.updateFreeSlots(free_slots, free_ie_slots); |
4c3eabea | 586 | me.updateDrives(valid_drives); |
70fab5b4 | 587 | |
423e3cbd DC |
588 | if (!use_cache) { |
589 | Proxmox.Utils.setErrorMask(view); | |
590 | } | |
591 | Proxmox.Utils.setErrorMask(me.lookup('content')); | |
3006d70e | 592 | } catch (response) { |
9896a75c DC |
593 | if (!view || view.isDestroyed) { |
594 | return; | |
595 | } | |
596 | ||
423e3cbd DC |
597 | if (!use_cache) { |
598 | Proxmox.Utils.setErrorMask(view); | |
599 | } | |
3006d70e | 600 | Proxmox.Utils.setErrorMask(me.lookup('content'), response.result.message.toString()); |
fd9aa8df | 601 | } |
076afa61 DC |
602 | |
603 | me.scheduleReload(5000); | |
fd9aa8df | 604 | }, |
4094fe5a | 605 | |
d1bee434 DC |
606 | renderLabel: function(value) { |
607 | if (value === undefined) { | |
608 | return ''; | |
609 | } | |
610 | ||
611 | if (value === "") { | |
612 | return Ext.htmlEncode("<no-barcode>"); | |
613 | } | |
614 | ||
615 | return value; | |
616 | }, | |
617 | ||
4094fe5a DC |
618 | renderIsLabeled: function(value, mD, record) { |
619 | if (!record.data['label-text']) { | |
620 | return ""; | |
621 | } | |
622 | ||
623 | if (record.data['label-text'].startsWith("CLN")) { | |
624 | return ""; | |
625 | } | |
626 | ||
627 | if (!value) { | |
628 | return gettext('Not Labeled'); | |
629 | } | |
630 | ||
631 | let status = record.data.status; | |
632 | if (record.data.pool) { | |
633 | return `${status} (${record.data.pool})`; | |
634 | } | |
635 | return status; | |
636 | }, | |
0d890ec4 | 637 | |
0d890ec4 DC |
638 | control: { |
639 | 'grid[reference=drives]': { | |
640 | cellclick: function(table, td, ci, rec, tr, ri, e) { | |
f26276bc | 641 | if (e.position.column.dataIndex !== 'state') { |
0d890ec4 DC |
642 | return; |
643 | } | |
644 | ||
645 | let upid = rec.data.state; | |
646 | if (!upid || !upid.startsWith("UPID")) { | |
647 | return; | |
648 | } | |
649 | ||
650 | Ext.create('Proxmox.window.TaskViewer', { | |
651 | autoShow: true, | |
652 | upid, | |
653 | }); | |
654 | }, | |
655 | }, | |
656 | }, | |
7eefd0c3 DC |
657 | |
658 | init: function(view) { | |
659 | let me = this; | |
660 | if (!view.changer) { | |
661 | throw "no changer given"; | |
662 | } | |
663 | ||
664 | view.title = `${gettext("Changer")}: ${view.changer}`; | |
9896a75c | 665 | me.reload(); |
7eefd0c3 | 666 | }, |
fd9aa8df DC |
667 | }, |
668 | ||
669 | listeners: { | |
9896a75c | 670 | deactivate: 'cancelReload', |
f8735e59 | 671 | beforedestroy: 'cancelReload', |
fd9aa8df DC |
672 | }, |
673 | ||
674 | tbar: [ | |
fd9aa8df DC |
675 | { |
676 | text: gettext('Reload'), | |
677 | xtype: 'proxmoxButton', | |
cbd98993 | 678 | handler: 'reload_no_cache', |
fd9aa8df DC |
679 | selModel: false, |
680 | }, | |
681 | '-', | |
fd9aa8df DC |
682 | { |
683 | text: gettext('Barcode Label'), | |
684 | xtype: 'proxmoxButton', | |
685 | handler: 'barcodeLabel', | |
686 | iconCls: 'fa fa-barcode', | |
fd9aa8df | 687 | }, |
e2225aa8 DC |
688 | { |
689 | text: gettext('Inventory'), | |
690 | xtype: 'proxmoxButton', | |
691 | handler: 'inventory', | |
692 | iconCls: 'fa fa-book', | |
e2225aa8 | 693 | }, |
fd9aa8df DC |
694 | ], |
695 | ||
9a1ecae0 | 696 | layout: 'fit', |
fd9aa8df | 697 | bodyPadding: 5, |
fd9aa8df DC |
698 | |
699 | items: [ | |
700 | { | |
701 | xtype: 'container', | |
702 | reference: 'content', | |
703 | layout: { | |
704 | type: 'hbox', | |
9a1ecae0 | 705 | align: 'stretch', |
fd9aa8df DC |
706 | }, |
707 | items: [ | |
708 | { | |
709 | xtype: 'grid', | |
710 | reference: 'slots', | |
711 | title: gettext('Slots'), | |
712 | padding: 5, | |
9a1ecae0 | 713 | srollable: true, |
fd9aa8df DC |
714 | flex: 1, |
715 | store: { | |
a83cedc2 DC |
716 | type: 'diff', |
717 | rstore: { | |
718 | type: 'store', | |
719 | model: 'pbs-slot-model', | |
720 | }, | |
fd9aa8df DC |
721 | data: [], |
722 | }, | |
723 | columns: [ | |
724 | { | |
970a70b4 | 725 | text: gettext('ID'), |
fd9aa8df DC |
726 | dataIndex: 'entry-id', |
727 | width: 50, | |
728 | }, | |
729 | { | |
730 | text: gettext("Content"), | |
731 | dataIndex: 'label-text', | |
732 | flex: 1, | |
d1bee434 | 733 | renderer: 'renderLabel', |
fd9aa8df | 734 | }, |
42eef145 | 735 | { |
bc02c278 | 736 | text: gettext('Inventory'), |
42eef145 | 737 | dataIndex: 'is-labeled', |
4094fe5a | 738 | renderer: 'renderIsLabeled', |
bc02c278 | 739 | flex: 1, |
42eef145 | 740 | }, |
fd9aa8df DC |
741 | { |
742 | text: gettext('Actions'), | |
743 | xtype: 'actioncolumn', | |
744 | width: 100, | |
745 | items: [ | |
746 | { | |
747 | iconCls: 'fa fa-rotate-90 fa-exchange', | |
748 | handler: 'slotTransfer', | |
d2edc68e | 749 | tooltip: gettext('Transfer'), |
4e0faf5e | 750 | isActionDisabled: (v, r, c, i, rec) => rec.data['is-empty'], |
fd9aa8df | 751 | }, |
85205bc2 DC |
752 | { |
753 | iconCls: 'fa fa-trash-o', | |
a2e30cd5 DC |
754 | handler: 'format', |
755 | tooltip: gettext('Format'), | |
4e0faf5e | 756 | isActionDisabled: (v, r, c, i, rec) => rec.data['is-empty'], |
85205bc2 | 757 | }, |
fd9aa8df DC |
758 | { |
759 | iconCls: 'fa fa-rotate-90 fa-upload', | |
760 | handler: 'load', | |
d2edc68e | 761 | tooltip: gettext('Load'), |
4e0faf5e | 762 | isActionDisabled: (v, r, c, i, rec) => rec.data['is-empty'], |
fd9aa8df DC |
763 | }, |
764 | ], | |
765 | }, | |
766 | ], | |
767 | }, | |
768 | { | |
769 | xtype: 'container', | |
770 | flex: 2, | |
771 | defaults: { | |
772 | padding: 5, | |
773 | }, | |
9a1ecae0 DC |
774 | layout: { |
775 | type: 'vbox', | |
776 | align: 'stretch', | |
777 | }, | |
fd9aa8df DC |
778 | items: [ |
779 | { | |
780 | xtype: 'grid', | |
781 | reference: 'drives', | |
9a1ecae0 DC |
782 | scrollable: true, |
783 | maxHeight: 350, // ~10 drives | |
fd9aa8df DC |
784 | title: gettext('Drives'), |
785 | store: { | |
a83cedc2 DC |
786 | type: 'diff', |
787 | rstore: { | |
788 | type: 'store', | |
789 | model: 'pbs-slot-model', | |
790 | }, | |
fd9aa8df DC |
791 | data: [], |
792 | }, | |
d4bfdfe7 DM |
793 | tbar: [ |
794 | { | |
795 | text: gettext('Label Media'), | |
796 | xtype: 'proxmoxButton', | |
797 | handler: 'labelMedia', | |
798 | iconCls: 'fa fa-barcode', | |
799 | disabled: true, | |
d1bee434 | 800 | enableFn: (rec) => !rec.data["is-empty"], |
d4bfdfe7 | 801 | }, |
2af8b8ef DM |
802 | { |
803 | text: gettext('Catalog'), | |
804 | xtype: 'proxmoxButton', | |
805 | handler: 'catalog', | |
806 | iconCls: 'fa fa-book', | |
807 | disabled: true, | |
d1bee434 | 808 | enableFn: (rec) => !rec.data["is-empty"], |
2af8b8ef | 809 | }, |
983edbc5 DC |
810 | { |
811 | text: gettext('Format'), | |
812 | xtype: 'proxmoxButton', | |
813 | handler: 'format-inserted', | |
814 | iconCls: 'fa fa-trash-o', | |
815 | disabled: true, | |
d1bee434 | 816 | enableFn: (rec) => !rec.data["is-empty"], |
983edbc5 DC |
817 | dangerous: true, |
818 | confirmMsg: gettext('Are you sure you want to format the inserted tape?'), | |
819 | }, | |
820 | '-', | |
bbe05d7f DM |
821 | { |
822 | text: gettext('Clean Drive'), | |
823 | xtype: 'proxmoxButton', | |
824 | handler: 'cleanDrive', | |
825 | iconCls: 'fa fa-shower', | |
826 | disabled: true, | |
827 | }, | |
d4bfdfe7 | 828 | ], |
fd9aa8df DC |
829 | columns: [ |
830 | { | |
970a70b4 | 831 | text: gettext('ID'), |
fd9aa8df | 832 | dataIndex: 'entry-id', |
970a70b4 | 833 | hidden: true, |
fd9aa8df DC |
834 | width: 50, |
835 | }, | |
836 | { | |
837 | text: gettext("Content"), | |
838 | dataIndex: 'label-text', | |
839 | flex: 1, | |
d1bee434 | 840 | renderer: 'renderLabel', |
fd9aa8df | 841 | }, |
4094fe5a DC |
842 | { |
843 | text: gettext('Inventory'), | |
844 | dataIndex: 'is-labeled', | |
845 | renderer: 'renderIsLabeled', | |
0d890ec4 | 846 | flex: 1.5, |
4094fe5a | 847 | }, |
fd9aa8df DC |
848 | { |
849 | text: gettext("Name"), | |
850 | sortable: true, | |
851 | dataIndex: 'name', | |
852 | flex: 1, | |
853 | renderer: Ext.htmlEncode, | |
854 | }, | |
b5af9333 DC |
855 | { |
856 | text: gettext('Activity'), | |
857 | dataIndex: 'activity', | |
858 | renderer: PBS.Utils.renderDriveActivity, | |
859 | hidden: true, | |
860 | flex: 1, | |
861 | }, | |
0d890ec4 DC |
862 | { |
863 | text: gettext('State'), | |
864 | dataIndex: 'state', | |
865 | flex: 3, | |
9d5b426a | 866 | renderer: PBS.Utils.renderDriveState, |
0d890ec4 | 867 | }, |
fd9aa8df DC |
868 | { |
869 | text: gettext("Vendor"), | |
870 | sortable: true, | |
871 | dataIndex: 'vendor', | |
0d890ec4 | 872 | hidden: true, |
fd9aa8df DC |
873 | flex: 1, |
874 | renderer: Ext.htmlEncode, | |
875 | }, | |
876 | { | |
877 | text: gettext("Model"), | |
878 | sortable: true, | |
879 | dataIndex: 'model', | |
0d890ec4 | 880 | hidden: true, |
fd9aa8df DC |
881 | flex: 1, |
882 | renderer: Ext.htmlEncode, | |
883 | }, | |
884 | { | |
885 | text: gettext("Serial"), | |
886 | sortable: true, | |
887 | dataIndex: 'serial', | |
0d890ec4 | 888 | hidden: true, |
fd9aa8df DC |
889 | flex: 1, |
890 | renderer: Ext.htmlEncode, | |
891 | }, | |
892 | { | |
893 | xtype: 'actioncolumn', | |
894 | text: gettext('Actions'), | |
895 | width: 140, | |
896 | items: [ | |
897 | { | |
898 | iconCls: 'fa fa-rotate-270 fa-upload', | |
899 | handler: 'unload', | |
d2edc68e | 900 | tooltip: gettext('Unload'), |
4e0faf5e | 901 | isActionDisabled: (v, r, c, i, rec) => rec.data['is-empty'] || rec.data['is-blocked'], |
fd9aa8df DC |
902 | }, |
903 | { | |
904 | iconCls: 'fa fa-hdd-o', | |
905 | handler: 'cartridgeMemory', | |
d2edc68e | 906 | tooltip: gettext('Cartridge Memory'), |
4e0faf5e | 907 | isActionDisabled: (v, r, c, i, rec) => rec.data['is-empty'] || rec.data['is-blocked'], |
fd9aa8df DC |
908 | }, |
909 | { | |
910 | iconCls: 'fa fa-line-chart', | |
911 | handler: 'volumeStatistics', | |
d2edc68e | 912 | tooltip: gettext('Volume Statistics'), |
4e0faf5e | 913 | isActionDisabled: (v, r, c, i, rec) => rec.data['is-empty'] || rec.data['is-blocked'], |
fd9aa8df DC |
914 | }, |
915 | { | |
916 | iconCls: 'fa fa-tag', | |
917 | handler: 'readLabel', | |
d2edc68e | 918 | tooltip: gettext('Read Label'), |
4e0faf5e | 919 | isActionDisabled: (v, r, c, i, rec) => rec.data['is-empty'] || rec.data['is-blocked'], |
fd9aa8df DC |
920 | }, |
921 | { | |
922 | iconCls: 'fa fa-info-circle', | |
d2edc68e | 923 | tooltip: gettext('Status'), |
fd9aa8df | 924 | handler: 'status', |
4e0faf5e | 925 | isActionDisabled: (v, r, c, i, rec) => rec.data['is-blocked'], |
fd9aa8df | 926 | }, |
fd9aa8df DC |
927 | ], |
928 | }, | |
929 | ], | |
930 | }, | |
931 | { | |
932 | xtype: 'grid', | |
933 | reference: 'import_export', | |
9a1ecae0 DC |
934 | flex: 1, |
935 | srollable: true, | |
fd9aa8df | 936 | store: { |
a83cedc2 DC |
937 | type: 'diff', |
938 | rstore: { | |
939 | type: 'store', | |
940 | model: 'pbs-slot-model', | |
941 | }, | |
fd9aa8df DC |
942 | data: [], |
943 | }, | |
970a70b4 | 944 | title: gettext('Import-Export Slots'), |
fd9aa8df DC |
945 | columns: [ |
946 | { | |
970a70b4 | 947 | text: gettext('ID'), |
fd9aa8df DC |
948 | dataIndex: 'entry-id', |
949 | width: 50, | |
950 | }, | |
951 | { | |
952 | text: gettext("Content"), | |
953 | dataIndex: 'label-text', | |
d1bee434 | 954 | renderer: 'renderLabel', |
fd9aa8df DC |
955 | flex: 1, |
956 | }, | |
4094fe5a DC |
957 | { |
958 | text: gettext('Inventory'), | |
959 | dataIndex: 'is-labeled', | |
960 | renderer: 'renderIsLabeled', | |
961 | flex: 1, | |
962 | }, | |
fd9aa8df DC |
963 | { |
964 | text: gettext('Actions'), | |
58791864 DC |
965 | xtype: 'actioncolumn', |
966 | items: [ | |
967 | { | |
968 | iconCls: 'fa fa-rotate-270 fa-upload', | |
969 | handler: 'importTape', | |
970 | tooltip: gettext('Import'), | |
4e0faf5e | 971 | isActionDisabled: (v, r, c, i, rec) => rec.data['is-empty'], |
58791864 DC |
972 | }, |
973 | ], | |
fd9aa8df DC |
974 | width: 80, |
975 | }, | |
976 | ], | |
977 | }, | |
978 | ], | |
979 | }, | |
980 | ], | |
981 | }, | |
982 | ], | |
983 | }); |