]> git.proxmox.com Git - proxmox-backup.git/blobdiff - www/tape/ChangerStatus.js
ui: tape/ChangerStatus: add missing model fields
[proxmox-backup.git] / www / tape / ChangerStatus.js
index 96eeadeb4765975a5d3440333f1493c3593983b5..fcf4d6dd5f75472120206fa45f25140d9022e0d5 100644 (file)
@@ -1,3 +1,16 @@
+Ext.define('pbs-slot-model', {
+    extend: 'Ext.data.Model',
+    fields: ['entry-id', 'label-text', 'is-labeled', ' model', 'name', 'vendor', 'serial', 'state', 'status', 'pool',
+       {
+           name: 'is-blocked',
+           calculate: function(data) {
+               return data.state !== undefined;
+           },
+       },
+    ],
+    idProperty: 'entry-id',
+});
+
 Ext.define('PBS.TapeManagement.ChangerStatus', {
     extend: 'Ext.panel.Panel',
     alias: 'widget.pbsChangerStatus',
@@ -91,6 +104,23 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
            }).show();
        },
 
+       erase: function(view, rI, cI, button, el, record) {
+           let me = this;
+           let vm = me.getViewModel();
+           let label = record.data['label-text'];
+
+           let changer = vm.get('changer');
+           Ext.create('PBS.TapeManagement.EraseWindow', {
+               label,
+               changer,
+               listeners: {
+                   destroy: function() {
+                       me.reload();
+                   },
+               },
+           }).show();
+       },
+
        load: function(view, rI, cI, button, el, record) {
            let me = this;
            let vm = me.getViewModel();
@@ -100,9 +130,12 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
 
            Ext.create('Proxmox.window.Edit', {
                isCreate: true,
+               autoShow: true,
                submitText: gettext('OK'),
                title: gettext('Load Media into Drive'),
                url: `/api2/extjs/tape/drive`,
+               showProgress: true,
+               method: 'POST',
                submitUrl: function(url, values) {
                    let drive = values.drive;
                    delete values.drive;
@@ -128,23 +161,26 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                        me.reload();
                    },
                },
-           }).show();
+           });
        },
 
        unload: async function(view, rI, cI, button, el, record) {
            let me = this;
            let drive = record.data.name;
-           Proxmox.Utils.setErrorMask(view, true);
            try {
-               await PBS.Async.api2({
-                   method: 'PUT',
+               let response = await PBS.Async.api2({
+                   method: 'POST',
+                   timeout: 5*60*1000,
                    url: `/api2/extjs/tape/drive/${encodeURIComponent(drive)}/unload`,
                });
-               Proxmox.Utils.setErrorMask(view);
-               me.reload();
+
+               Ext.create('Proxmox.window.TaskProgress', {
+                   autoShow: true,
+                   upid: response.result.data,
+                   taskDone: () => me.reload(),
+               });
            } catch (error) {
                Ext.Msg.alert(gettext('Error'), error);
-               Proxmox.Utils.setErrorMask(view);
                me.reload();
            }
        },
@@ -156,6 +192,7 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
            method = method || 'GET';
            Proxmox.Utils.API2Request({
                url: `/api2/extjs/tape/drive/${driveid}/${command}`,
+               timeout: 5*60*1000,
                method,
                waitMsgTarget: view,
                params,
@@ -371,7 +408,34 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
            }).show();
        },
 
-       reload: async function() {
+       scheduleReload: function(time) {
+           let me = this;
+           if (me.reloadTimeout === undefined) {
+               me.reloadTimeout = setTimeout(function() {
+                   me.reload();
+               }, time);
+           }
+       },
+
+       reload: function() {
+           let me = this;
+           if (me.reloadTimeout !== undefined) {
+               clearTimeout(me.reloadTimeout);
+               me.reloadTimeout = undefined;
+           }
+           me.reload_full(true);
+       },
+
+       reload_no_cache: function() {
+           let me = this;
+           if (me.reloadTimeout !== undefined) {
+               clearTimeout(me.reloadTimeout);
+               me.reloadTimeout = undefined;
+           }
+           me.reload_full(false);
+       },
+
+       reload_full: async function(use_cache) {
            let me = this;
            let view = me.getView();
            let vm = me.getViewModel();
@@ -381,17 +445,30 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
            }
 
            try {
-               Proxmox.Utils.setErrorMask(view, true);
-               Proxmox.Utils.setErrorMask(me.lookup('content'));
+               if (!use_cache) {
+                   Proxmox.Utils.setErrorMask(view, true);
+                   Proxmox.Utils.setErrorMask(me.lookup('content'));
+               }
                let status_fut = PBS.Async.api2({
+                   timeout: 5*60*1000,
+                   method: 'GET',
                    url: `/api2/extjs/tape/changer/${encodeURIComponent(changer)}/status`,
+                   params: {
+                       cache: use_cache,
+                   },
                });
                let drives_fut = PBS.Async.api2({
+                   timeout: 5*60*1000,
                    url: `/api2/extjs/tape/drive?changer=${encodeURIComponent(changer)}`,
                });
 
                let tapes_fut = PBS.Async.api2({
+                   timeout: 5*60*1000,
                    url: '/api2/extjs/tape/media/list',
+                   method: 'GET',
+                   params: {
+                       "update-status": false,
+                   },
                });
 
                let [status, drives, tapes_list] = await Promise.all([status_fut, drives_fut, tapes_fut]);
@@ -405,7 +482,11 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                let tapes = {};
 
                for (const tape of tapes_list.result.data) {
-                   tapes[tape['label-text']] = true;
+                   tapes[tape['label-text']] = {
+                       labeled: true,
+                       pool: tape.pool,
+                       status: tape.expired ? 'expired' : tape.status,
+                   };
                }
 
                let drive_entries = {};
@@ -421,21 +502,98 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                        entry = Ext.applyIf(entry, drive_entries[entry['entry-id']]);
                    }
 
-                   entry['is-labeled'] = !!tapes[entry['label-text']];
+                   if (tapes[entry['label-text']] !== undefined) {
+                       entry['is-labeled'] = true;
+                       entry.pool = tapes[entry['label-text']].pool;
+                       entry.status = tapes[entry['label-text']].status;
+                   } else {
+                       entry['is-labeled'] = false;
+                   }
 
                    data[type].push(entry);
                }
 
+               // the stores are diffstores and are only refreshed
+               // on a 'load' event, which does not trigger on 'setData'
+               // so we have to fire them ourselves
+
+               me.lookup('slots').getStore().rstore.setData(data.slot);
+               me.lookup('slots').getStore().rstore.fireEvent('load', me, [], true);
+
+               me.lookup('import_export').getStore().rstore.setData(data['import-export']);
+               me.lookup('import_export').getStore().rstore.fireEvent('load', me, [], true);
 
-               me.lookup('slots').getStore().setData(data.slot);
-               me.lookup('import_export').getStore().setData(data['import-export']);
-               me.lookup('drives').getStore().setData(data.drive);
+               me.lookup('drives').getStore().rstore.setData(data.drive);
+               me.lookup('drives').getStore().rstore.fireEvent('load', me, [], true);
 
-               Proxmox.Utils.setErrorMask(view);
+               if (!use_cache) {
+                   Proxmox.Utils.setErrorMask(view);
+               }
+               Proxmox.Utils.setErrorMask(me.lookup('content'));
            } catch (err) {
-               Proxmox.Utils.setErrorMask(view);
-               Proxmox.Utils.setErrorMask(me.lookup('content'), err);
+               if (!use_cache) {
+                   Proxmox.Utils.setErrorMask(view);
+               }
+               Proxmox.Utils.setErrorMask(me.lookup('content'), err.toString());
            }
+
+           me.scheduleReload(5000);
+       },
+
+       renderIsLabeled: function(value, mD, record) {
+           if (!record.data['label-text']) {
+               return "";
+           }
+
+           if (record.data['label-text'].startsWith("CLN")) {
+               return "";
+           }
+
+           if (!value) {
+               return gettext('Not Labeled');
+           }
+
+           let status = record.data.status;
+           if (record.data.pool) {
+               return `${status} (${record.data.pool})`;
+           }
+           return status;
+       },
+
+       renderState: function(value, md, record) {
+           if (!value) {
+               return gettext('Idle');
+           }
+
+           let icon = '<i class="fa fa-spinner fa-pulse fa-fw"></i>';
+
+           if (value.startsWith("UPID")) {
+               let upid = Proxmox.Utils.parse_task_upid(value);
+               md.tdCls = "pointer";
+               return `${icon} ${upid.desc}`;
+           }
+
+           return `${icon} ${value}`;
+       },
+
+       control: {
+           'grid[reference=drives]': {
+               cellclick: function(table, td, ci, rec, tr, ri, e) {
+                   if (e.position.column.dataIndex !== 'state') {
+                       return;
+                   }
+
+                   let upid = rec.data.state;
+                   if (!upid || !upid.startsWith("UPID")) {
+                       return;
+                   }
+
+                   Ext.create('Proxmox.window.TaskViewer', {
+                       autoShow: true,
+                       upid,
+                   });
+               },
+           },
        },
     },
 
@@ -457,7 +615,7 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
        {
            text: gettext('Reload'),
            xtype: 'proxmoxButton',
-           handler: 'reload',
+           handler: 'reload_no_cache',
            selModel: false,
        },
        '-',
@@ -501,11 +659,16 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                    padding: 5,
                    flex: 1,
                    store: {
+                       type: 'diff',
+                       rstore: {
+                           type: 'store',
+                           model: 'pbs-slot-model',
+                       },
                        data: [],
                    },
                    columns: [
                        {
-                           text: gettext('Slot'),
+                           text: gettext('ID'),
                            dataIndex: 'entry-id',
                            width: 50,
                        },
@@ -516,20 +679,10 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                            renderer: (value) => value || '',
                        },
                        {
-                           text: gettext('Labeled'),
+                           text: gettext('Inventory'),
                            dataIndex: 'is-labeled',
-                           width: 80,
-                           renderer: function(value, mD, record) {
-                               if (!record.data['label-text']) {
-                                   return "";
-                               }
-
-                               if (record.data['label-text'].startsWith("CLN")) {
-                                   return "";
-                               }
-
-                               return Proxmox.Utils.format_boolean(value);
-                           },
+                           renderer: 'renderIsLabeled',
+                           flex: 1,
                        },
                        {
                            text: gettext('Actions'),
@@ -542,6 +695,12 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                                    tooltip: gettext('Transfer'),
                                    isDisabled: (v, r, c, i, rec) => !rec.data['label-text'],
                                },
+                               {
+                                   iconCls: 'fa fa-trash-o',
+                                   handler: 'erase',
+                                   tooltip: gettext('Erase'),
+                                   isDisabled: (v, r, c, i, rec) => !rec.data['label-text'],
+                               },
                                {
                                    iconCls: 'fa fa-rotate-90 fa-upload',
                                    handler: 'load',
@@ -564,13 +723,18 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                            reference: 'drives',
                            title: gettext('Drives'),
                            store: {
-                               fields: ['entry-id', 'label-text', 'model', 'name', 'vendor', 'serial'],
+                               type: 'diff',
+                               rstore: {
+                                   type: 'store',
+                                   model: 'pbs-slot-model',
+                               },
                                data: [],
                            },
                            columns: [
                                {
-                                   text: gettext('Slot'),
+                                   text: gettext('ID'),
                                    dataIndex: 'entry-id',
+                                   hidden: true,
                                    width: 50,
                                },
                                {
@@ -579,6 +743,12 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                                    flex: 1,
                                    renderer: (value) => value || '',
                                },
+                               {
+                                   text: gettext('Inventory'),
+                                   dataIndex: 'is-labeled',
+                                   renderer: 'renderIsLabeled',
+                                   flex: 1.5,
+                               },
                                {
                                    text: gettext("Name"),
                                    sortable: true,
@@ -586,10 +756,17 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                                    flex: 1,
                                    renderer: Ext.htmlEncode,
                                },
+                               {
+                                   text: gettext('State'),
+                                   dataIndex: 'state',
+                                   flex: 3,
+                                   renderer: 'renderState',
+                               },
                                {
                                    text: gettext("Vendor"),
                                    sortable: true,
                                    dataIndex: 'vendor',
+                                   hidden: true,
                                    flex: 1,
                                    renderer: Ext.htmlEncode,
                                },
@@ -597,6 +774,7 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                                    text: gettext("Model"),
                                    sortable: true,
                                    dataIndex: 'model',
+                                   hidden: true,
                                    flex: 1,
                                    renderer: Ext.htmlEncode,
                                },
@@ -604,6 +782,7 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                                    text: gettext("Serial"),
                                    sortable: true,
                                    dataIndex: 'serial',
+                                   hidden: true,
                                    flex: 1,
                                    renderer: Ext.htmlEncode,
                                },
@@ -616,35 +795,37 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                                            iconCls: 'fa fa-rotate-270 fa-upload',
                                            handler: 'unload',
                                            tooltip: gettext('Unload'),
-                                           isDisabled: (v, r, c, i, rec) => !rec.data['label-text'],
+                                           isDisabled: (v, r, c, i, rec) => !rec.data['label-text'] || rec.data['is-blocked'],
                                        },
                                        {
                                            iconCls: 'fa fa-hdd-o',
                                            handler: 'cartridgeMemory',
                                            tooltip: gettext('Cartridge Memory'),
-                                           isDisabled: (v, r, c, i, rec) => !rec.data['label-text'],
+                                           isDisabled: (v, r, c, i, rec) => !rec.data['label-text'] || rec.data['is-blocked'],
                                        },
                                        {
                                            iconCls: 'fa fa-line-chart',
                                            handler: 'volumeStatistics',
                                            tooltip: gettext('Volume Statistics'),
-                                           isDisabled: (v, r, c, i, rec) => !rec.data['label-text'],
+                                           isDisabled: (v, r, c, i, rec) => !rec.data['label-text'] || rec.data['is-blocked'],
                                        },
                                        {
                                            iconCls: 'fa fa-tag',
                                            handler: 'readLabel',
                                            tooltip: gettext('Read Label'),
-                                           isDisabled: (v, r, c, i, rec) => !rec.data['label-text'],
+                                           isDisabled: (v, r, c, i, rec) => !rec.data['label-text'] || rec.data['is-blocked'],
                                        },
                                        {
                                            iconCls: 'fa fa-info-circle',
                                            tooltip: gettext('Status'),
                                            handler: 'status',
+                                           isDisabled: (v, r, c, i, rec) => rec.data['is-blocked'],
                                        },
                                        {
                                            iconCls: 'fa fa-shower',
                                            tooltip: gettext('Clean Drive'),
                                            handler: 'cleanDrive',
+                                           isDisabled: (v, r, c, i, rec) => rec.data['is-blocked'],
                                        },
                                    ],
                                },
@@ -654,12 +835,17 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                            xtype: 'grid',
                            reference: 'import_export',
                            store: {
+                               type: 'diff',
+                               rstore: {
+                                   type: 'store',
+                                   model: 'pbs-slot-model',
+                               },
                                data: [],
                            },
-                           title: gettext('Import-Export'),
+                           title: gettext('Import-Export Slots'),
                            columns: [
                                {
-                                   text: gettext('Slot'),
+                                   text: gettext('ID'),
                                    dataIndex: 'entry-id',
                                    width: 50,
                                },
@@ -669,6 +855,12 @@ Ext.define('PBS.TapeManagement.ChangerStatus', {
                                    renderer: (value) => value || '',
                                    flex: 1,
                                },
+                               {
+                                   text: gettext('Inventory'),
+                                   dataIndex: 'is-labeled',
+                                   renderer: 'renderIsLabeled',
+                                   flex: 1,
+                               },
                                {
                                    text: gettext('Actions'),
                                    xtype: 'actioncolumn',