proxmox-backup/www/tape/DriveStatus.js
Dominik Csapak 69e5ba29c4 ui: tape: reload drive status on user actions
when the user start an action where we know that it locks the drive,
reload the tape store, so that the state is refreshed

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
2021-04-23 16:25:17 +02:00

563 lines
12 KiB
JavaScript

Ext.define('PBS.TapeManagement.DriveStatus', {
extend: 'Ext.panel.Panel',
alias: 'widget.pbsDriveStatus',
mixins: ['Proxmox.Mixin.CBind'],
tools: [PBS.Utils.get_help_tool("tape_backup")],
cbindData: function(config) {
let me = this;
me.setTitle(`${gettext('Drive')}: ${me.drive}`);
let baseurl = `/api2/json/tape/drive/${me.drive}/`;
return {
driveStatusUrl: `${baseurl}/status`,
cartridgeMemoryUrl: `${baseurl}/cartridge-memory`,
};
},
layout: {
type: 'vbox',
align: 'stretch',
},
bodyPadding: 5,
viewModel: {
data: {
online: false,
busy: true,
loaded: false,
},
},
controller: {
xclass: 'Ext.app.ViewController',
reloadTapeStore: function() {
Ext.ComponentQuery.query('navigationtree')[0].reloadTapeStore();
},
reload: function() {
let me = this;
me.lookup('statusgrid').rstore.load();
},
onLoad: function() {
let me = this;
let statusgrid = me.lookup('statusgrid');
let online = statusgrid.getObjectValue('file-number') !== undefined;
let vm = me.getViewModel();
vm.set('online', online);
let title = online ? gettext('Status') : gettext('Status (No Tape loaded)');
statusgrid.setTitle(title);
Ext.ComponentQuery.query('navigationtree')[0].reloadTapeStore();
},
onStateLoad: function(store) {
let me = this;
let view = me.getView();
let vm = me.getViewModel();
let driveRecord = store.findRecord('name', view.drive, 0, false, true, true);
let busy = !!driveRecord.data.state;
vm.set('busy', busy);
let statusgrid = me.lookup('statusgrid');
if (!vm.get('loaded')) {
if (busy) {
// have to use a timeout so that the component can be rendered first
// otherwise the 'mask' call errors out
setTimeout(function() {
statusgrid.mask(gettext('Drive is busy'));
}, 10);
} else {
// have to use a timeout so that the component can be rendered first
// otherwise the 'mask' call errors out
setTimeout(function() {
statusgrid.unmask();
}, 10);
me.reload();
vm.set('loaded', true);
}
}
},
labelMedia: function() {
let me = this;
Ext.create('PBS.TapeManagement.LabelMediaWindow', {
driveid: me.getView().drive,
apiCallDone: function(success) {
if (success) {
me.reloadTapeStore();
}
},
}).show();
},
format: function() {
let me = this;
let view = me.getView();
let driveid = view.drive;
PBS.Utils.driveCommand(driveid, 'format-media', {
waitMsgTarget: view,
method: 'POST',
success: function(response) {
me.reloadTapeStore();
Ext.create('Proxmox.window.TaskProgress', {
upid: response.result.data,
taskDone: function() {
me.reload();
},
}).show();
},
});
},
ejectMedia: function() {
let me = this;
let view = me.getView();
let driveid = view.drive;
PBS.Utils.driveCommand(driveid, 'eject-media', {
waitMsgTarget: view,
method: 'POST',
success: function(response) {
me.reloadTapeStore();
Ext.create('Proxmox.window.TaskProgress', {
upid: response.result.data,
taskDone: function() {
me.reload();
},
}).show();
},
});
},
catalog: function() {
let me = this;
let view = me.getView();
let drive = view.drive;
PBS.Utils.driveCommand(drive, 'catalog', {
waitMsgTarget: view,
method: 'POST',
success: function(response) {
me.reloadTapeStore();
Ext.create('Proxmox.window.TaskViewer', {
upid: response.result.data,
taskDone: function() {
me.reload();
},
}).show();
},
});
},
readLabel: function() {
let me = this;
let view = me.getView();
let drive = view.drive;
PBS.Utils.driveCommand(drive, 'read-label', {
waitMsgTarget: view,
success: function(response) {
me.reloadTapeStore();
PBS.Utils.showMediaLabelWindow(response);
},
});
},
volumeStatistics: function() {
let me = this;
let view = me.getView();
let drive = view.drive;
PBS.Utils.driveCommand(drive, 'volume-statistics', {
waitMsgTarget: view,
success: function(response) {
me.reloadTapeStore();
PBS.Utils.showVolumeStatisticsWindow(response);
},
});
},
cartridgeMemory: function() {
let me = this;
let view = me.getView();
let drive = view.drive;
PBS.Utils.driveCommand(drive, 'cartridge-memory', {
waitMsgTarget: me.getView(),
success: function(response) {
me.reloadTapeStore();
PBS.Utils.showCartridgeMemoryWindow(response);
},
});
},
init: function(view) {
let me = this;
me.mon(me.lookup('statusgrid').getStore().rstore, 'load', 'onLoad');
let tapeStore = Ext.ComponentQuery.query('navigationtree')[0].tapeStore;
me.mon(tapeStore, 'load', 'onStateLoad');
if (tapeStore.isLoaded()) {
me.onStateLoad(tapeStore);
}
},
},
tbar: [
{
xtype: 'proxmoxButton',
handler: 'reload',
text: gettext('Reload'),
disabled: true,
bind: {
disabled: '{busy}',
},
},
'-',
{
text: gettext('Label Media'),
xtype: 'proxmoxButton',
handler: 'labelMedia',
iconCls: 'fa fa-barcode',
disabled: true,
bind: {
disabled: '{!online}',
},
},
{
text: gettext('Eject'),
xtype: 'proxmoxButton',
handler: 'ejectMedia',
iconCls: 'fa fa-eject',
disabled: true,
bind: {
disabled: '{!online}',
},
},
{
text: gettext('Format'),
xtype: 'proxmoxButton',
handler: 'format',
iconCls: 'fa fa-trash-o',
dangerous: true,
confirmMsg: gettext('Are you sure you want to format the inserted tape?'),
disabled: true,
bind: {
disabled: '{!online}',
},
},
{
text: gettext('Catalog'),
xtype: 'proxmoxButton',
handler: 'catalog',
iconCls: 'fa fa-book',
disabled: true,
bind: {
disabled: '{!online}',
},
},
{
text: gettext('Read Label'),
xtype: 'proxmoxButton',
handler: 'readLabel',
iconCls: 'fa fa-tag',
disabled: true,
bind: {
disabled: '{!online}',
},
},
{
text: gettext('Volume Statistics'),
xtype: 'proxmoxButton',
handler: 'volumeStatistics',
iconCls: 'fa fa-line-chart',
disabled: true,
bind: {
disabled: '{!online}',
},
},
{
text: gettext('Cartridge Memory'),
xtype: 'proxmoxButton',
iconCls: 'fa fa-hdd-o',
handler: 'cartridgeMemory',
disabled: true,
bind: {
disabled: '{!online}',
},
},
],
items: [
{
xtype: 'container',
layout: {
type: 'hbox',
align: 'stretch',
},
defaults: {
padding: 5,
flex: 1,
},
items: [
{
xtype: 'pbsDriveInfoPanel',
cbind: {
drive: '{drive}',
},
},
{
xtype: 'pbsDriveStatusGrid',
reference: 'statusgrid',
cbind: {
url: '{driveStatusUrl}',
},
},
],
},
],
});
Ext.define('PBS.TapeManagement.DriveStatusGrid', {
extend: 'Proxmox.grid.ObjectGrid',
alias: 'widget.pbsDriveStatusGrid',
title: gettext('Status'),
rows: {
'density': {
required: true,
header: gettext('Tape Density'),
},
'blocksize': {
required: true,
header: gettext('Block Size'),
renderer: function(value) {
if (!value) {
return gettext('Dynamic');
}
return `${gettext('Fixed')} - ${Proxmox.Utils.format_size(value)}`;
},
},
'write-protect': {
required: true,
header: gettext('Write Protect'),
defaultValue: false,
renderer: Proxmox.Utils.format_boolean,
},
'compression': {
required: true,
header: gettext('Compression'),
renderer: Proxmox.Utils.format_boolean,
},
'file-number': {
header: gettext('Tape Position'),
renderer: function(value, mD, r, rI, cI, store) {
let me = this;
let filenr = value;
let rec = store.getById('block-number');
if (rec) {
let blocknr = rec.data.value;
return `File ${filenr}, Block ${blocknr}`;
}
return `File ${filenr}`;
},
},
'block-number': {
visible: false,
},
'manufactured': {
header: gettext('Tape Manufacture Date'),
renderer: function(value) {
if (value) {
return Ext.Date.format(new Date(value*1000), "Y-m-d");
}
return "";
},
},
'bytes-read': {
header: gettext('Tape Read'),
renderer: Proxmox.Utils.format_size,
},
'bytes-written': {
header: gettext('Tape Written'),
renderer: Proxmox.Utils.format_size,
},
'medium-passes': {
header: gettext('Tape Passes'),
},
'medium-wearout': {
header: gettext('Tape Wearout'),
renderer: function(value) {
if (value !== undefined) {
return (value*100).toFixed(2) + "%";
}
return value;
},
},
'alert-flags': {
header: gettext('Alert Flags'),
},
},
});
Ext.define('PBS.TapeManagement.DriveInfoPanel', {
extend: 'Ext.panel.Panel',
alias: 'widget.pbsDriveInfoPanel',
title: gettext('Information'),
defaults: {
printBar: false,
padding: 5,
},
bodyPadding: 15,
viewModel: {
data: {
drive: {},
},
formulas: {
driveState: function(get) {
let drive = get('drive');
return PBS.Utils.renderDriveState(drive.state, {});
},
},
},
items: [
{
xtype: 'pmxInfoWidget',
title: gettext('Name'),
bind: {
data: {
text: '{drive.name}',
},
},
},
{
xtype: 'pmxInfoWidget',
title: gettext('Vendor'),
bind: {
data: {
text: '{drive.vendor}',
},
},
},
{
xtype: 'pmxInfoWidget',
title: gettext('Model'),
bind: {
data: {
text: '{drive.model}',
},
},
},
{
xtype: 'pmxInfoWidget',
title: gettext('Serial'),
bind: {
data: {
text: '{drive.serial}',
},
},
},
{
xtype: 'pmxInfoWidget',
title: gettext('Path'),
bind: {
data: {
text: '{drive.path}',
},
},
},
{
xtype: 'pmxInfoWidget',
reference: 'statewidget',
title: gettext('State'),
bind: {
data: {
text: '{driveState}',
},
},
},
],
clickState: function(e, t, eOpts) {
let me = this;
let vm = me.getViewModel();
let drive = vm.get('drive');
if (t.classList.contains('right-aligned')) {
let upid = drive.state;
if (!upid || !upid.startsWith("UPID")) {
return;
}
Ext.create('Proxmox.window.TaskViewer', {
autoShow: true,
upid,
});
}
},
updateData: function(store) {
let me = this;
if (!store) {
return;
}
let record = store.findRecord('name', me.drive, 0, false, true, true);
if (!record) {
return;
}
let vm = me.getViewModel();
vm.set('drive', record.data);
vm.notify();
me.updatePointer();
},
updatePointer: function() {
let me = this;
let stateWidget = me.down('pmxInfoWidget[reference=statewidget]');
let stateEl = stateWidget.getEl();
if (!stateEl) {
setTimeout(function() {
me.updatePointer();
}, 100);
return;
}
let vm = me.getViewModel();
let drive = vm.get('drive');
if (drive.state) {
stateEl.addCls('info-pointer');
} else {
stateEl.removeCls('info-pointer');
}
},
listeners: {
afterrender: function() {
let me = this;
let stateWidget = me.down('pmxInfoWidget[reference=statewidget]');
let stateEl = stateWidget.getEl();
stateEl.on('click', me.clickState, me);
},
},
initComponent: function() {
let me = this;
if (!me.drive) {
throw "no drive given";
}
me.callParent();
let tapeStore = Ext.ComponentQuery.query('navigationtree')[0].tapeStore;
me.mon(tapeStore, 'load', me.updateData, me);
if (tapeStore.isLoaded()) {
me.updateData(tapeStore);
}
},
});