[pbs-devel] [PATCH proxmox-backup] ui: tape/BackupOverview: add 'restore partial' button

Dominik Csapak d.csapak at proxmox.com
Tue May 11 14:42:56 CEST 2021


this opens the restore window, but with a snapshot selector, so that
the user can select the snapshots to restore

includes a textfield for basic filtering

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 www/tape/BackupOverview.js     |  31 ++++++++
 www/tape/window/TapeRestore.js | 125 +++++++++++++++++++++++++++++++++
 2 files changed, 156 insertions(+)

diff --git a/www/tape/BackupOverview.js b/www/tape/BackupOverview.js
index c028d58d..e039595d 100644
--- a/www/tape/BackupOverview.js
+++ b/www/tape/BackupOverview.js
@@ -48,6 +48,29 @@ Ext.define('PBS.TapeManagement.BackupOverview', {
 	    }).show();
 	},
 
+	restoreList: function(button, record) {
+	    let me = this;
+	    let view = me.getView();
+	    let selection = view.getSelection();
+	    if (!selection || selection.length < 1) {
+		return;
+	    }
+
+	    let node = selection[0];
+	    let mediaset = node.data.text;
+	    let uuid = node.data['media-set-uuid'];
+	    Ext.create('PBS.TapeManagement.TapeRestoreWindow', {
+		mediaset,
+		uuid,
+		list_snapshots: true,
+		listeners: {
+		    destroy: function() {
+			me.reload();
+		    },
+		},
+	    }).show();
+	},
+
 	restore: function(button, record) {
 	    let me = this;
 	    let view = me.getView();
@@ -295,6 +318,14 @@ Ext.define('PBS.TapeManagement.BackupOverview', {
 	    parentXType: 'treepanel',
 	    enableFn: (rec) => !!rec.data['media-set-uuid'],
 	},
+	{
+	    xtype: 'proxmoxButton',
+	    disabled: true,
+	    text: gettext('Restore partial Media Set'),
+	    handler: 'restoreList',
+	    parentXType: 'treepanel',
+	    enableFn: (rec) => !!rec.data['media-set-uuid'],
+	},
 	{
 	    xtype: 'proxmoxButton',
 	    disabled: true,
diff --git a/www/tape/window/TapeRestore.js b/www/tape/window/TapeRestore.js
index 7e4f5cae..560d4812 100644
--- a/www/tape/window/TapeRestore.js
+++ b/www/tape/window/TapeRestore.js
@@ -49,6 +49,10 @@ Ext.define('PBS.TapeManagement.TapeRestoreWindow', {
 		    values.snapshots = me.up('window').list;
 		}
 
+		if (Ext.isString(values.snapshots)) {
+		    values.snapshots = values.snapshots.split(',');
+		}
+
 		values.store = datastores.join(',');
 
 		return values;
@@ -138,6 +142,23 @@ Ext.define('PBS.TapeManagement.TapeRestoreWindow', {
 		    defaultBindProperty: 'value',
 		    hidden: true,
 		},
+		{
+		    fieldLabel: gettext('Snapshot Selection'),
+		    labelWidth: 200,
+		    cbind: {
+			hidden: '{!list_snapshots}',
+		    },
+		    reference: 'snapshotLabel',
+		    xtype: 'displayfield',
+		},
+		{
+		    xtype: 'pbsTapeSnapshotGrid',
+		    reference: 'snapshotGrid',
+		    name: 'snapshots',
+		    cbind: {
+			hidden: '{!list_snapshots}',
+		    },
+		},
 	    ],
 	},
     ],
@@ -186,6 +207,9 @@ Ext.define('PBS.TapeManagement.TapeRestoreWindow', {
 			    datastores[content.store] = true;
 			}
 			me.setDataStores(Object.keys(datastores));
+			let store = me.lookup('snapshotGrid').getStore();
+			store.setData(response.result.data);
+			store.sort('snapshot');
 		    },
 		    failure: function() {
 			// ignore failing api call, maybe catalog is missing
@@ -308,3 +332,104 @@ Ext.define('PBS.TapeManagement.DataStoreMappingGrid', {
 	},
     ],
 });
+
+Ext.define('PBS.TapeManagement.SnapshotGrid', {
+    extend: 'Ext.grid.Panel',
+    alias: 'widget.pbsTapeSnapshotGrid',
+    mixins: ['Ext.form.field.Field'],
+
+    getValue: function() {
+	let me = this;
+	let snapshots = [];
+
+	me.getStore().each((rec) => {
+	    if (rec.data.include) {
+		let store = rec.data.store;
+		let snap = rec.data.snapshot;
+		snapshots.push(`${store}:${snap}`);
+	    }
+	});
+
+	return snapshots;
+    },
+
+    setValue: function(value) {
+	let me = this;
+	// not implemented
+	return me;
+    },
+
+    getErrors: function(value) {
+	let me = this;
+	let firstSelected = me.getStore().findBy((rec) => !!rec.data.include);
+
+	if (firstSelected === -1) {
+	    me.addCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']);
+	    let errorMsg = gettext("Need at least one snapshot");
+	    me.getActionEl().dom.setAttribute('data-errorqtip', errorMsg);
+
+	    return [errorMsg];
+	}
+	me.removeCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']);
+	me.getActionEl().dom.setAttribute('data-errorqtip', "");
+	return [];
+    },
+
+    scrollable: true,
+    height: 200,
+
+    viewConfig: {
+	emptyText: gettext('No Snapshots'),
+	markDirty: false,
+    },
+
+    tbar: [
+	{
+	    fieldLabel: gettext('Filter'),
+	    xtype: 'textfield',
+	    isFormField: false,
+	    listeners: {
+		change: function(field, value) {
+		    let me = this;
+		    let grid = me.up('grid');
+		    let store = grid.getStore();
+		    store.clearFilter();
+		    store.filter({
+			property: 'snapshot',
+			anyMatch: true,
+			caseSensitive: true,
+			exactMatch: false,
+			value,
+		    });
+		    grid.checkChange();
+		},
+	    },
+	},
+    ],
+
+    store: { data: [] },
+
+    columns: [
+	{
+	    xtype: 'checkcolumn',
+	    text: gettext('Include'),
+	    dataIndex: 'include',
+	    listeners: {
+		checkchange: function(cb, value) {
+		    let grid = this.up('grid');
+		    grid.checkChange();
+		},
+	    },
+	},
+	{
+	    text: gettext('Source Datastore'),
+	    dataIndex: 'store',
+	    flex: 1,
+	},
+	{
+	    text: gettext('Snapshot'),
+	    dataIndex: 'snapshot',
+	    flex: 4,
+	},
+    ],
+});
-- 
2.20.1






More information about the pbs-devel mailing list