From: Dominik Csapak <d.csapak@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup 3/6] ui: tape: rework BackupOverview
Date: Tue, 2 Feb 2021 14:00:36 +0100 [thread overview]
Message-ID: <20210202130039.6564-3-d.csapak@proxmox.com> (raw)
In-Reply-To: <20210202130039.6564-1-d.csapak@proxmox.com>
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>
---
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.20.1
next prev parent reply other threads:[~2021-02-02 13:00 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-02 13:00 [pbs-devel] [PATCH proxmox-backup 1/6] api2/types/tape/media: add media_set_ctime to MediaContentEntry Dominik Csapak
2021-02-02 13:00 ` [pbs-devel] [PATCH proxmox-backup 2/6] ui: refactor get_type_icon_cls Dominik Csapak
2021-02-02 13:00 ` Dominik Csapak [this message]
2021-02-02 13:00 ` [pbs-devel] [PATCH proxmox-backup 4/6] ui: tape: TapeBackupWindow: add missing DriveSelector Dominik Csapak
2021-02-02 13:00 ` [pbs-devel] [PATCH proxmox-backup 5/6] ui: tape: add Restore Window Dominik Csapak
2021-02-02 13:00 ` [pbs-devel] [PATCH proxmox-backup 6/6] ui: tape: add TapeInventory panel Dominik Csapak
2021-02-02 13:49 ` [pbs-devel] applied: [PATCH proxmox-backup 1/6] api2/types/tape/media: add media_set_ctime to MediaContentEntry Dietmar Maurer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210202130039.6564-3-d.csapak@proxmox.com \
--to=d.csapak@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox