ui: tape: rework BackupOverview

instead of grouping by tape (which is rarely interesting),
group by pool -> group -> id -> mediaset

this way a user looking for a backup of specific vm can do just that

we may want to have an additional view here were we list all snapshots
included in the selected media-set ?

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2021-02-02 14:00:36 +01:00 committed by Dietmar Maurer
parent f806c0effa
commit 631e550920
2 changed files with 107 additions and 79 deletions

View File

@ -260,6 +260,15 @@ Ext.define('PBS.Utils', {
return dedup; return dedup;
}, },
parse_snapshot_id: function(snapshot) {
if (!snapshot) {
return [undefined, undefined, undefined];
}
let [_match, type, group, id] = /^([^/]+)\/([^/]+)\/(.+)$/.exec(snapshot);
return [type, group, id];
},
get_type_icon_cls: function(btype) { get_type_icon_cls: function(btype) {
var cls = ''; var cls = '';
if (btype.startsWith('vm')) { if (btype.startsWith('vm')) {

View File

@ -16,6 +16,90 @@ Ext.define('PBS.TapeManagement.BackupOverview', {
}).show(); }).show();
}, },
restore: function(button, record) {
let me = this;
let view = me.getView();
let selection = view.getSelection();
if (!selection || selection.length < 1) {
return;
}
let mediaset = selection[0].data.text;
let uuid = selection[0].data.uuid;
Ext.create('PBS.TapeManagement.TapeRestoreWindow', {
mediaset,
uuid,
listeners: {
destroy: function() {
me.reload();
},
},
}).show();
},
loadContent: async function() {
let content_response = await PBS.Async.api2({
url: '/api2/extjs/tape/media/content',
});
let data = {};
for (const entry of content_response.result.data) {
let pool = entry.pool;
let [type, group_id, id] = PBS.Utils.parse_snapshot_id(entry.snapshot);
let group = `${type}/${group_id}`;
let media_set = entry['media-set-name'];
let uuid = entry['media-set-uuid'];
let ctime = entry['media-set-ctime'];
if (data[pool] === undefined) {
data[pool] = {};
}
if (data[pool][group] === undefined) {
data[pool][group] = {};
}
if (data[pool][group][id] === undefined) {
data[pool][group][id] = [];
}
data[pool][group][id].push({
text: media_set,
uuid,
ctime,
leaf: true,
});
}
let list = [];
for (const [pool, groups] of Object.entries(data)) {
let pool_entry = {
text: pool,
leaf: false,
children: [],
};
for (const [group, ids] of Object.entries(groups)) {
let group_entry = {
text: group,
iconCls: "fa " + PBS.Utils.get_type_icon_cls(group),
leaf: false,
children: [],
};
for (const [id, media_sets] of Object.entries(ids)) {
let id_entry = {
text: `${group}/${id}`,
leaf: false,
children: media_sets,
};
group_entry.children.push(id_entry);
}
pool_entry.children.push(group_entry);
}
list.push(pool_entry);
}
return list;
},
reload: async function() { reload: async function() {
let me = this; let me = this;
let view = me.getView(); let view = me.getView();
@ -23,43 +107,7 @@ Ext.define('PBS.TapeManagement.BackupOverview', {
Proxmox.Utils.setErrorMask(view, true); Proxmox.Utils.setErrorMask(view, true);
try { try {
let list_response = await PBS.Async.api2({ let list = await me.loadContent();
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({ view.setRootNode({
expanded: true, expanded: true,
@ -78,8 +126,14 @@ Ext.define('PBS.TapeManagement.BackupOverview', {
}, },
store: { store: {
sorters: 'label-text',
data: [], data: [],
sorters: function(a, b) {
if (a.data.leaf && b.data.leaf) {
return a.data.ctime - b.data.ctime;
} else {
return a.data.text.localeCompare(b.data.text);
}
},
}, },
rootVisible: false, rootVisible: false,
@ -99,50 +153,15 @@ Ext.define('PBS.TapeManagement.BackupOverview', {
columns: [ columns: [
{ {
xtype: 'treecolumn', xtype: 'treecolumn',
text: gettext('Tape/Backup'), text: gettext('Pool/Group/Snapshot/Media Set'),
dataIndex: 'label-text', dataIndex: 'text',
sortable: false,
flex: 3, flex: 3,
}, },
{ {
text: gettext('Location'), text: gettext('Media Set UUID'),
dataIndex: 'location', dataIndex: 'uuid',
flex: 1, sortable: false,
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, flex: 1,
}, },
], ],