From 1e37156a6baa048cac7a5f30f73e5aef2aaf5c0b Mon Sep 17 00:00:00 2001 From: Dominik Csapak Date: Thu, 12 May 2022 16:23:26 +0200 Subject: [PATCH] ui: tape/BackupOverview: show namespaces as their own level above groups since the namespaces are in the snapshot path we get here, we must parse them out, else we confuse the first namespace with the group. for now, show all namespaces on the same level (so not nested), and do not allow for preselecting a namespace for restoring Signed-off-by: Dominik Csapak --- www/Utils.js | 8 ++++++-- www/tape/BackupOverview.js | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/www/Utils.js b/www/Utils.js index cff59a7a..eec0cbb4 100644 --- a/www/Utils.js +++ b/www/Utils.js @@ -338,9 +338,13 @@ Ext.define('PBS.Utils', { if (!snapshot) { return [undefined, undefined, undefined]; } - let [_match, type, group, id] = /^([^/]+)\/([^/]+)\/(.+)$/.exec(snapshot); + let nsRegex = /(?:^|\/)(ns\/([^/]+))/g; + let namespaces = []; + let nsPaths = []; + snapshot = snapshot.replace(nsRegex, (_, nsPath, ns) => { nsPaths.push(nsPath); namespaces.push(ns); return ""; }); + let [_match, type, group, id] = /^\/?([^/]+)\/([^/]+)\/(.+)$/.exec(snapshot); - return [type, group, id]; + return [type, group, id, namespaces.join('/'), nsPaths.join('/')]; }, get_type_icon_cls: function(btype) { diff --git a/www/tape/BackupOverview.js b/www/tape/BackupOverview.js index c368640c..229d8d9d 100644 --- a/www/tape/BackupOverview.js +++ b/www/tape/BackupOverview.js @@ -154,7 +154,8 @@ Ext.define('PBS.TapeManagement.BackupOverview', { store: entry.store, snapshot: entry.snapshot, }; - let iconCls = PBS.Utils.get_type_icon_cls(entry.snapshot); + let [type, group, _id, namespace, nsPath] = PBS.Utils.parse_snapshot_id(entry.snapshot); + let iconCls = PBS.Utils.get_type_icon_cls(type); if (iconCls !== '') { entry.iconCls = `fa ${iconCls}`; } @@ -182,13 +183,21 @@ Ext.define('PBS.TapeManagement.BackupOverview', { 'media-set-uuid': entry['media-set-uuid'], 'seq-nr': entry['seq-nr'], iconCls: 'pbs-icon-tape', - expanded: true, + namespaces: {}, children: [], }; } - let [type, group, _id] = PBS.Utils.parse_snapshot_id(entry.snapshot); - let children = stores[store].tapes[tape].children; + if (stores[store].tapes[tape].namespaces[namespace] === undefined) { + stores[store].tapes[tape].namespaces[namespace] = { + text: namespace, + 'media-set-uuid': entry['media-set-uuid'], + 'is-namespace': true, + children: [], + }; + } + + let children = stores[store].tapes[tape].namespaces[namespace].children; let text = `${type}/${group}`; if (children.length < 1 || children[children.length - 1].text !== text) { children.push({ @@ -198,7 +207,7 @@ Ext.define('PBS.TapeManagement.BackupOverview', { restore: true, prefilter: { store, - snapshot: `${type}/${group}/`, + snapshot: namespace ? `${nsPath}/${type}/${group}/` : `${type}/${group}`, }, 'media-set': media_set, iconCls: `fa ${iconCls}`, @@ -213,6 +222,20 @@ Ext.define('PBS.TapeManagement.BackupOverview', { let storeNameList = Object.keys(stores); let expand = storeList.length === 1; for (const store of storeList) { + let tapeList = Object.values(store.tapes); + for (const tape of tapeList) { + let rootNs = tape.namespaces['']; + if (rootNs) { + tape.children.push(...rootNs.children); + delete tape.namespaces['']; + } + tape.children.push(...Object.values(tape.namespaces)); + if (tape.children.length === 1) { + tape.children[0].expanded = true; + } + tape.expanded = tapeList.length === 1; + delete tape.namespaces; + } store.children = Object.values(store.tapes); store.expanded = expand; delete store.tapes; @@ -254,6 +277,10 @@ Ext.define('PBS.TapeManagement.BackupOverview', { sorters: function(a, b) { if (a.data.is_media_set && b.data.is_media_set) { return a.data['media-set-ctime'] - b.data['media-set-ctime']; + } else if (a.data['is-namespace'] && !b.data['is-namespace']) { + return 1; + } else if (!a.data['is-namespace'] && b.data['is-namespace']) { + return -1; } else { return a.data.text.localeCompare(b.data.text); }