* [pbs-devel] [PATCH proxmox-backup 2/6] ui: refactor get_type_icon_cls
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 ` Dominik Csapak
2021-02-02 13:00 ` [pbs-devel] [PATCH proxmox-backup 3/6] ui: tape: rework BackupOverview Dominik Csapak
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Dominik Csapak @ 2021-02-02 13:00 UTC (permalink / raw)
To: pbs-devel
we need this later again
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
www/Utils.js | 12 ++++++++++++
www/datastore/Content.js | 10 ++--------
2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/www/Utils.js b/www/Utils.js
index e6ea64ea..acfc4556 100644
--- a/www/Utils.js
+++ b/www/Utils.js
@@ -260,6 +260,18 @@ Ext.define('PBS.Utils', {
return dedup;
},
+ get_type_icon_cls: function(btype) {
+ var cls = '';
+ if (btype.startsWith('vm')) {
+ cls = 'fa-desktop';
+ } else if (btype.startsWith('ct')) {
+ cls = 'fa-cube';
+ } else if (btype.startsWith('host')) {
+ cls = 'fa-building';
+ }
+ return cls;
+ },
+
constructor: function() {
var me = this;
diff --git a/www/datastore/Content.js b/www/datastore/Content.js
index 12dacb89..d0cf3e0b 100644
--- a/www/datastore/Content.js
+++ b/www/datastore/Content.js
@@ -105,14 +105,8 @@ Ext.define('PBS.DataStoreContent', {
continue;
}
- var cls = '';
- if (btype === 'vm') {
- cls = 'fa-desktop';
- } else if (btype === 'ct') {
- cls = 'fa-cube';
- } else if (btype === 'host') {
- cls = 'fa-building';
- } else {
+ var cls = PBS.Utils.get_type_icon_cls(btype);
+ if (cls === "") {
console.warn(`got unknown backup-type '${btype}'`);
continue; // FIXME: auto render? what do?
}
--
2.20.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [pbs-devel] [PATCH proxmox-backup 3/6] ui: tape: rework BackupOverview
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
2021-02-02 13:00 ` [pbs-devel] [PATCH proxmox-backup 4/6] ui: tape: TapeBackupWindow: add missing DriveSelector Dominik Csapak
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Dominik Csapak @ 2021-02-02 13:00 UTC (permalink / raw)
To: pbs-devel
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
^ permalink raw reply [flat|nested] 7+ messages in thread
* [pbs-devel] [PATCH proxmox-backup 4/6] ui: tape: TapeBackupWindow: add missing DriveSelector
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 ` [pbs-devel] [PATCH proxmox-backup 3/6] ui: tape: rework BackupOverview Dominik Csapak
@ 2021-02-02 13:00 ` Dominik Csapak
2021-02-02 13:00 ` [pbs-devel] [PATCH proxmox-backup 5/6] ui: tape: add Restore Window Dominik Csapak
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Dominik Csapak @ 2021-02-02 13:00 UTC (permalink / raw)
To: pbs-devel
and make it a bit wider
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
www/tape/window/TapeBackup.js | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/www/tape/window/TapeBackup.js b/www/tape/window/TapeBackup.js
index a3ceacdc..30180146 100644
--- a/www/tape/window/TapeBackup.js
+++ b/www/tape/window/TapeBackup.js
@@ -2,12 +2,17 @@ Ext.define('PBS.TapeManagement.TapeBackupWindow', {
extend: 'Proxmox.window.Edit',
alias: 'pbsTapeBackupWindow',
+ width: 400,
subject: gettext('Backup'),
url: '/api2/extjs/tape/backup',
method: 'POST',
showTaskViewer: true,
isCreate: true,
+ defaults: {
+ labelWidth: 120,
+ },
+
items: [
{
xtype: 'pbsDataStoreSelector',
@@ -19,6 +24,11 @@ Ext.define('PBS.TapeManagement.TapeBackupWindow', {
fieldLabel: gettext('Media Pool'),
name: 'pool',
},
+ {
+ xtype: 'pbsDriveSelector',
+ fieldLabel: gettext('Drive'),
+ name: 'drive',
+ },
{
xtype: 'proxmoxcheckbox',
name: 'export-media-set',
--
2.20.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [pbs-devel] [PATCH proxmox-backup 5/6] ui: tape: add Restore Window
2021-02-02 13:00 [pbs-devel] [PATCH proxmox-backup 1/6] api2/types/tape/media: add media_set_ctime to MediaContentEntry Dominik Csapak
` (2 preceding siblings ...)
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 ` 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
5 siblings, 0 replies; 7+ messages in thread
From: Dominik Csapak @ 2021-02-02 13:00 UTC (permalink / raw)
To: pbs-devel
in the BackupOverview, when a media-set is selected
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
www/Makefile | 1 +
www/tape/BackupOverview.js | 8 ++++++
www/tape/window/TapeRestore.js | 45 ++++++++++++++++++++++++++++++++++
3 files changed, 54 insertions(+)
create mode 100644 www/tape/window/TapeRestore.js
diff --git a/www/Makefile b/www/Makefile
index 7a47ad8d..1f45bc14 100644
--- a/www/Makefile
+++ b/www/Makefile
@@ -20,6 +20,7 @@ TAPE_UI_FILES= \
tape/window/LabelMedia.js \
tape/window/PoolEdit.js \
tape/window/TapeBackup.js \
+ tape/window/TapeRestore.js \
tape/BackupOverview.js \
tape/ChangerConfig.js \
tape/ChangerStatus.js \
diff --git a/www/tape/BackupOverview.js b/www/tape/BackupOverview.js
index f850c29a..439c1394 100644
--- a/www/tape/BackupOverview.js
+++ b/www/tape/BackupOverview.js
@@ -148,6 +148,14 @@ Ext.define('PBS.TapeManagement.BackupOverview', {
text: gettext('New Backup'),
handler: 'backup',
},
+ {
+ xtype: 'proxmoxButton',
+ disabled: true,
+ text: gettext('Restore Media Set'),
+ handler: 'restore',
+ parentXType: 'treepanel',
+ enableFn: (rec) => !!rec.data.uuid,
+ },
],
columns: [
diff --git a/www/tape/window/TapeRestore.js b/www/tape/window/TapeRestore.js
new file mode 100644
index 00000000..9e0a5edb
--- /dev/null
+++ b/www/tape/window/TapeRestore.js
@@ -0,0 +1,45 @@
+Ext.define('PBS.TapeManagement.TapeRestoreWindow', {
+ extend: 'Proxmox.window.Edit',
+ alias: 'pbsTapeRestoreWindow',
+ mixins: ['Proxmox.Mixin.CBind'],
+
+ width: 400,
+ title: gettext('Restore Media Set'),
+ url: '/api2/extjs/tape/restore',
+ method: 'POST',
+ showTaskViewer: true,
+ isCreate: true,
+
+ defaults: {
+ labelWidth: 120,
+ },
+
+ items: [
+ {
+ xtype: 'displayfield',
+ fieldLabel: gettext('Media Set'),
+ cbind: {
+ value: '{mediaset}',
+ },
+ },
+ {
+ xtype: 'displayfield',
+ fieldLabel: gettext('Media Set UUID'),
+ name: 'media-set',
+ submitValue: true,
+ cbind: {
+ value: '{uuid}',
+ },
+ },
+ {
+ xtype: 'pbsDataStoreSelector',
+ fieldLabel: gettext('Datastore'),
+ name: 'store',
+ },
+ {
+ xtype: 'pbsDriveSelector',
+ fieldLabel: gettext('Drive'),
+ name: 'drive',
+ },
+ ],
+});
--
2.20.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [pbs-devel] [PATCH proxmox-backup 6/6] ui: tape: add TapeInventory panel
2021-02-02 13:00 [pbs-devel] [PATCH proxmox-backup 1/6] api2/types/tape/media: add media_set_ctime to MediaContentEntry Dominik Csapak
` (3 preceding siblings ...)
2021-02-02 13:00 ` [pbs-devel] [PATCH proxmox-backup 5/6] ui: tape: add Restore Window Dominik Csapak
@ 2021-02-02 13:00 ` 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
5 siblings, 0 replies; 7+ messages in thread
From: Dominik Csapak @ 2021-02-02 13:00 UTC (permalink / raw)
To: pbs-devel
since we do not show the tapes anymore in the BackupOverview, add
another panel where we can list the available tapes in the inventory
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
www/Makefile | 1 +
www/tape/TapeInventory.js | 104 +++++++++++++++++++++++++++++++++++++
www/tape/TapeManagement.js | 5 ++
3 files changed, 110 insertions(+)
create mode 100644 www/tape/TapeInventory.js
diff --git a/www/Makefile b/www/Makefile
index 1f45bc14..b24783ca 100644
--- a/www/Makefile
+++ b/www/Makefile
@@ -26,6 +26,7 @@ TAPE_UI_FILES= \
tape/ChangerStatus.js \
tape/DriveConfig.js \
tape/PoolConfig.js \
+ tape/TapeInventory.js \
tape/TapeManagement.js \
endif
diff --git a/www/tape/TapeInventory.js b/www/tape/TapeInventory.js
new file mode 100644
index 00000000..ba968752
--- /dev/null
+++ b/www/tape/TapeInventory.js
@@ -0,0 +1,104 @@
+Ext.define('pbs-model-tapes', {
+ extend: 'Ext.data.Model',
+ fields: [
+ 'catalog',
+ 'ctime',
+ 'expired',
+ 'label-text',
+ 'location',
+ 'media-set-ctime',
+ 'media-set-name',
+ 'media-set-uuid',
+ 'pool',
+ 'seq-nr',
+ 'status',
+ 'uuid',
+ ],
+ idProperty: 'label-text',
+ proxy: {
+ type: 'proxmox',
+ url: '/api2/json/tape/media/list',
+ },
+});
+
+Ext.define('PBS.TapeManagement.TapeInventory', {
+ extend: 'Ext.grid.Panel',
+ alias: 'widget.pbsTapeInventory',
+
+ controller: {
+ xclass: 'Ext.app.ViewController',
+
+ reload: function() {
+ this.getView().getStore().rstore.load();
+ },
+
+ stopStore: function() {
+ this.getView().getStore().rstore.stopUpdate();
+ },
+
+ startStore: function() {
+ this.getView().getStore().rstore.startUpdate();
+ },
+ },
+
+ listeners: {
+ beforedestroy: 'stopStore',
+ deactivate: 'stopStore',
+ activate: 'startStore',
+ },
+
+ store: {
+ type: 'diff',
+ rstore: {
+ type: 'update',
+ storeid: 'proxmox-tape-tapes',
+ model: 'pbs-model-tapes',
+ },
+ sorters: 'label-text',
+ },
+
+ columns: [
+ {
+ text: gettext('Label'),
+ dataIndex: 'label-text',
+ flex: 1,
+ },
+ {
+ text: gettext('Pool'),
+ dataIndex: 'pool',
+ sorter: (a, b) => (a.data.pool || "").localeCompare(b.data.pool || ""),
+ flex: 1,
+ },
+ {
+ text: gettext('Media Set'),
+ dataIndex: 'media-set-name',
+ flex: 2,
+ sorter: function(a, b) {
+ return (a.data['media-set-ctime'] || 0) - (b.data['media-set-ctime'] || 0);
+ },
+ },
+ {
+ text: gettext('Location'),
+ dataIndex: 'location',
+ flex: 1,
+ renderer: function(value) {
+ if (value === 'offline') {
+ return `<i class="fa fa-circle-o"></i> ${gettext("Offline")}`;
+ } else if (value.startsWith('online-')) {
+ let location = value.substring(value.indexOf('-') + 1);
+ return `<i class="fa fa-dot-circle-o"></i> ${gettext("Online")} - ${location}`;
+ } else if (value.startsWith('vault-')) {
+ let location = value.substring(value.indexOf('-') + 1);
+ return `<i class="fa fa-archive"></i> ${gettext("Vault")} - ${location}`;
+ } else {
+ return value;
+ }
+ },
+ },
+ {
+ text: gettext('Status'),
+ dataIndex: 'status',
+ flex: 1,
+ },
+ ],
+});
diff --git a/www/tape/TapeManagement.js b/www/tape/TapeManagement.js
index 8461b0b3..e558620a 100644
--- a/www/tape/TapeManagement.js
+++ b/www/tape/TapeManagement.js
@@ -16,6 +16,11 @@ Ext.define('PBS.TapeManagement', {
itemId: 'backup',
xtype: 'pbsBackupOverview',
},
+ {
+ title: gettext('Tape Inventory'),
+ itemId: 'inventory',
+ xtype: 'pbsTapeInventory',
+ },
{
title: gettext('Library'),
itemId: 'library',
--
2.20.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [pbs-devel] applied: [PATCH proxmox-backup 1/6] api2/types/tape/media: add media_set_ctime to MediaContentEntry
2021-02-02 13:00 [pbs-devel] [PATCH proxmox-backup 1/6] api2/types/tape/media: add media_set_ctime to MediaContentEntry Dominik Csapak
` (4 preceding siblings ...)
2021-02-02 13:00 ` [pbs-devel] [PATCH proxmox-backup 6/6] ui: tape: add TapeInventory panel Dominik Csapak
@ 2021-02-02 13:49 ` Dietmar Maurer
5 siblings, 0 replies; 7+ messages in thread
From: Dietmar Maurer @ 2021-02-02 13:49 UTC (permalink / raw)
To: Proxmox Backup Server development discussion, Dominik Csapak
applied all patches
^ permalink raw reply [flat|nested] 7+ messages in thread