From 631e55092066305e6e2f830cd2c4eb87b7590812 Mon Sep 17 00:00:00 2001 From: Dominik Csapak Date: Tue, 2 Feb 2021 14:00:36 +0100 Subject: [PATCH] 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 --- www/Utils.js | 9 ++ www/tape/BackupOverview.js | 169 +++++++++++++++++++++---------------- 2 files changed, 103 insertions(+), 75 deletions(-) diff --git a/www/Utils.js b/www/Utils.js index acfc4556..3bb709e4 100644 --- a/www/Utils.js +++ b/www/Utils.js @@ -260,6 +260,15 @@ Ext.define('PBS.Utils', { 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) { var cls = ''; if (btype.startsWith('vm')) { diff --git a/www/tape/BackupOverview.js b/www/tape/BackupOverview.js index 4743dcc0..f850c29a 100644 --- a/www/tape/BackupOverview.js +++ b/www/tape/BackupOverview.js @@ -16,50 +16,98 @@ Ext.define('PBS.TapeManagement.BackupOverview', { }).show(); }, - reload: async function() { + restore: function(button, record) { let me = this; let view = me.getView(); + let selection = view.getSelection(); + if (!selection || selection.length < 1) { + return; + } - Proxmox.Utils.setErrorMask(view, true); + 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(); + }, - 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']), - ); + 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] = {}; + } - let content = {}; + if (data[pool][group] === undefined) { + data[pool][group] = {}; + } - let content_response = await PBS.Async.api2({ - url: '/api2/extjs/tape/media/content', + if (data[pool][group][id] === undefined) { + data[pool][group][id] = []; + } + data[pool][group][id].push({ + text: media_set, + uuid, + ctime, + leaf: true, }); + } - 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); + 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); + } - for (let child of list) { - let tape = child['label-text']; - if (content[tape]) { - child.children = content[tape]; - child.leaf = false; - } else { - child.leaf = true; - } - } + return list; + }, + + reload: async function() { + let me = this; + let view = me.getView(); + + Proxmox.Utils.setErrorMask(view, true); + + try { + let list = await me.loadContent(); view.setRootNode({ expanded: true, @@ -78,8 +126,14 @@ Ext.define('PBS.TapeManagement.BackupOverview', { }, store: { - sorters: 'label-text', 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, @@ -99,50 +153,15 @@ Ext.define('PBS.TapeManagement.BackupOverview', { columns: [ { xtype: 'treecolumn', - text: gettext('Tape/Backup'), - dataIndex: 'label-text', + text: gettext('Pool/Group/Snapshot/Media Set'), + dataIndex: 'text', + sortable: false, 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) : "", + text: gettext('Media Set UUID'), + dataIndex: 'uuid', + sortable: false, flex: 1, }, ], -- 2.39.5