proxmox-backup/www/tape/DriveStatus.js
2021-04-08 12:04:14 +02:00

528 lines
10 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',
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);
},
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,
}).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) {
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) {
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) {
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: PBS.Utils.showMediaLabelWindow,
});
},
volumeStatistics: function() {
let me = this;
let view = me.getView();
let drive = view.drive;
PBS.Utils.driveCommand(drive, 'volume-statistics', {
waitMsgTarget: view,
success: PBS.Utils.showVolumeStatisticsWindow,
});
},
cartridgeMemory: function() {
let me = this;
let view = me.getView();
let drive = view.drive;
PBS.Utils.driveCommand(drive, 'cartridge-memory', {
waitMsgTarget: me.getView(),
success: PBS.Utils.showCartridgeMemoryWindow,
});
},
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 erase 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,
},
'buffer-mode': {
required: true,
header: gettext('Buffer Mode'),
},
'compression': {
required: true,
header: gettext('Compression'),
},
'file-number': {
header: gettext('File Number'),
},
'block-number': {
header: gettext('Block Number'),
},
'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;
},
},
},
});
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);
}
},
});