ui: tape: add BackupOverview Panel

shows all tapes with the relevant info
* which pool it belongs to
* what backups are on it
* which media-set
* location
* etc.

This is very rough, and maybe not the best way to display this information.
It may make sense to reverse the tree, i.e. having pools at top-level,
then media-sets, then tapes, then snapshots..

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2021-01-28 12:59:47 +01:00 committed by Dietmar Maurer
parent 80a3749088
commit 07d6c0967d
2 changed files with 151 additions and 0 deletions

View File

@ -20,6 +20,7 @@ TAPE_UI_FILES= \
tape/window/LabelMedia.js \ tape/window/LabelMedia.js \
tape/window/PoolEdit.js \ tape/window/PoolEdit.js \
tape/window/TapeBackup.js \ tape/window/TapeBackup.js \
tape/BackupOverview.js \
TapeManagement.js TapeManagement.js
endif endif

150
www/tape/BackupOverview.js Normal file
View File

@ -0,0 +1,150 @@
Ext.define('PBS.TapeManagement.BackupOverview', {
extend: 'Ext.tree.Panel',
alias: 'widget.pbsBackupOverview',
controller: {
xclass: 'Ext.app.ViewController',
backup: function() {
let me = this;
Ext.create('PBS.TapeManagement.TapeBackupWindow', {
listeners: {
destroy: function() {
me.reload();
},
},
}).show();
},
reload: async function() {
let me = this;
let view = me.getView();
Proxmox.Utils.setErrorMask(view, true);
try {
let list_response = await PBS.Async.api2({
url: '/api2/extjs/tape/media/list',
});
let list = list_response.result.data.sort(
(a, b) => a['label-text'].localeCompare(b['label-text']),
);
let content = {};
let content_response = await PBS.Async.api2({
url: '/api2/extjs/tape/media/content',
});
let content_list = content_response.result.data.sort(
(a, b) => a.snapshot.localeCompare(b.snapshot),
);
for (let entry of content_list) {
let tape = entry['label-text'];
entry['label-text'] = entry.snapshot;
entry.leaf = true;
if (content[tape] === undefined) {
content[tape] = [entry];
} else {
content[tape].push(entry);
}
}
for (let child of list) {
let tape = child['label-text'];
if (content[tape]) {
child.children = content[tape];
child.leaf = false;
} else {
child.leaf = true;
}
}
view.setRootNode({
expanded: true,
children: list,
});
Proxmox.Utils.setErrorMask(view, false);
} catch (error) {
Proxmox.Utils.setErrorMask(view, error.toString());
}
},
},
listeners: {
activate: 'reload',
},
store: {
sorters: 'label-text',
data: [],
},
rootVisible: false,
tbar: [
{
text: gettext('Reload'),
handler: 'reload',
},
'-',
{
text: gettext('New Backup'),
handler: 'backup',
},
],
columns: [
{
xtype: 'treecolumn',
text: gettext('Tape/Backup'),
dataIndex: 'label-text',
flex: 3,
},
{
text: gettext('Location'),
dataIndex: 'location',
flex: 1,
renderer: function(value) {
if (!value) {
return "";
}
let result;
if ((result = /^online-(.+)$/.exec(value)) !== null) {
return Ext.htmlEncode(result[1]);
}
return value;
},
},
{
text: gettext('Status'),
dataIndex: 'status',
flex: 1,
},
{
text: gettext('Media Set'),
dataIndex: 'media-set-name',
flex: 2,
},
{
text: gettext('Pool'),
dataIndex: 'pool',
flex: 1,
},
{
text: gettext('Sequence Nr.'),
dataIndex: 'seq-nr',
flex: 0.5,
},
{
text: gettext('Backup Time'),
dataIndex: 'backup-time',
renderer: (time) => time !== undefined ? new Date(time*1000) : "",
flex: 1,
},
],
});