[pbs-devel] [PATCH proxmox-backup v2 3/4] ui: datastore content: add snapshot information to context menu

Dominik Csapak d.csapak at proxmox.com
Tue Dec 5 11:53:44 CET 2023


contains a summary of snapshot information, especially interesting since
it contains the upload statistics. This may allow us to reduce the
default column count in the grid.

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 www/Makefile               |   1 +
 www/datastore/Content.js   |  22 ++++
 www/window/SnapshotInfo.js | 259 +++++++++++++++++++++++++++++++++++++
 3 files changed, 282 insertions(+)
 create mode 100644 www/window/SnapshotInfo.js

diff --git a/www/Makefile b/www/Makefile
index be7e27ab..071ef5d8 100644
--- a/www/Makefile
+++ b/www/Makefile
@@ -87,6 +87,7 @@ JSSRC=							\
 	window/ZFSCreate.js				\
 	window/InfluxDbEdit.js				\
 	window/DatastoreRepoInfo.js			\
+	window/SnapshotInfo.js				\
 	dashboard/DataStoreStatistics.js		\
 	dashboard/LongestTasks.js			\
 	dashboard/RunningTasks.js			\
diff --git a/www/datastore/Content.js b/www/datastore/Content.js
index 87317ec1..f715f814 100644
--- a/www/datastore/Content.js
+++ b/www/datastore/Content.js
@@ -712,6 +712,17 @@ Ext.define('PBS.DataStoreContent', {
 	    });
 	},
 
+	onShowInformation: function(view, rI, cI, item, e, rec) {
+	    let me = this;
+	    Ext.create('PBS.window.SnapshotInfo', {
+		autoShow: true,
+		datastore: view.datastore,
+		'backup-type': rec.data['backup-type'],
+		'backup-id': rec.data['backup-id'],
+		'backup-time': (rec.data["backup-time"].getTime()/1000).toFixed(0),
+	    });
+	},
+
 	onForget: function(table, rI, cI, item, e, { data }) {
 	    let me = this;
 	    let view = this.getView();
@@ -893,6 +904,7 @@ Ext.define('PBS.DataStoreContent', {
 		    title: gettext('Snapshot'),
 		    onVerify: createControllerCallback('onVerify'),
 		    onProtectionChange: createControllerCallback('onProtectionChange'),
+		    onShowInformation: createControllerCallback('onShowInformation'),
 		    onForget: createControllerCallback('onForget'),
 		});
 	    }
@@ -1331,6 +1343,7 @@ Ext.define('PBS.datastore.SnapshotCmdMenu', {
 
     onVerify: undefined,
     onProtectionChange: undefined,
+    onShowInformation: undefined,
     onForget: undefined,
 
     items: [
@@ -1352,6 +1365,15 @@ Ext.define('PBS.datastore.SnapshotCmdMenu', {
 		disabled: '{!onProtectionChange}',
 	    },
 	},
+	{
+	    text: gettext('Show Information'),
+	    iconCls: 'fa fa-info-circle',
+	    handler: function() { this.up('menu').onShowInformation(); },
+	    cbind: {
+		hidden: '{!onShowInformation}',
+		disabled: '{!onShowInformation}',
+	    },
+	},
 	{ xtype: 'menuseparator' },
 	{
 	    text: gettext('Remove'),
diff --git a/www/window/SnapshotInfo.js b/www/window/SnapshotInfo.js
new file mode 100644
index 00000000..f2cc7a55
--- /dev/null
+++ b/www/window/SnapshotInfo.js
@@ -0,0 +1,259 @@
+Ext.define('PBS.window.SnapshotInfo', {
+    extend: 'Ext.window.Window',
+    alias: 'widget.pbsSnapshotInfo',
+
+    modal: true,
+    width: 700,
+    resizable: true,
+    referenceHolder: true,
+
+    bodyPadding: 25,
+    defaults: {
+	xtype: 'pmxInfoWidget',
+	printBar: false,
+	padding: '2 0',
+    },
+
+    items: [
+	{
+	    reference: 'backup-time',
+	    iconCls: 'fa fa-clock-o',
+	    title: gettext('Backup Time'),
+	},
+	{
+	    reference: 'protected',
+	    iconCls: 'fa fa-shield',
+	    title: gettext('Protected'),
+	},
+	{
+	    reference: 'size',
+	    iconCls: 'fa fa-hdd-o',
+	    title: gettext('Size'),
+	},
+	{
+	    reference: 'owner',
+	    iconCls: 'fa fa-user-o',
+	    title: gettext('Owner'),
+	},
+	{
+	    // spacer
+	    xtype: 'box',
+	    padding: 10,
+	},
+	{
+	    xtype: 'container',
+	    layout: {
+		type: 'hbox',
+		align: 'stretch',
+	    },
+	    items: [
+		{
+		    xtype: 'container',
+		    flex: 1,
+		    layout: {
+			type: 'vbox',
+			align: 'stretch',
+		    },
+		    defaults: {
+			xtype: 'pmxInfoWidget',
+			printBar: false,
+			padding: '2 0',
+		    },
+		    items: [
+			{
+			    xtype: 'box',
+			    html: `<i class="fa fa-upload"></i> ${gettext('Upload Statistics')}`,
+			    reference: 'upload-title',
+			    padding: '0 0 10 0',
+			},
+			{
+			    title: gettext('Size'),
+			    reference: 'upload-size',
+			},
+			{
+			    title: gettext('Compressed Size'),
+			    reference: 'compressed-size',
+			},
+			{
+			    title: gettext('Chunk Count'),
+			    reference: 'chunk-count',
+			},
+			{
+			    title: gettext('Duplicate Chunks'),
+			    reference: 'duplicate-chunks',
+			},
+		    ],
+		},
+		{
+		    // spacer
+		    xtype: 'box',
+		    padding: 10,
+		},
+		{
+		    xtype: 'container',
+		    flex: 1,
+		    layout: {
+			type: 'vbox',
+			align: 'stretch',
+		    },
+		    defaults: {
+			xtype: 'pmxInfoWidget',
+			printBar: false,
+			padding: '2 0',
+		    },
+		    items: [
+			{
+			    xtype: 'box',
+			    html: `<i class="pve-icon-verify-lettering"></i> ${gettext('Verification')}`,
+			    reference: 'verify-title',
+			    padding: '0 0 10 0',
+			},
+			{
+			    title: gettext('Verify State'),
+			    reference: 'verify-state',
+			},
+			{
+			    title: gettext('Last Verificaton'),
+			    iconCls: 'fa fa-list-alt',
+			    reference: 'verify-last',
+			},
+		    ],
+		},
+	    ],
+	},
+	{
+	    // spacer
+	    xtype: 'box',
+	    padding: 10,
+	},
+	{
+	    xtype: 'tabpanel',
+	    height: 200,
+	    items: [{
+		title: gettext('Files'),
+		xtype: 'grid',
+		reference: 'files',
+		store: {
+		    data: [],
+		},
+		scrollable: true,
+		columns: [
+		    {
+			dataIndex: 'filename',
+			text: gettext('Filename'),
+			flex: 1,
+		    },
+		    {
+			dataIndex: 'size',
+			text: gettext('Size'),
+			flex: 1,
+			renderer: (v) => v !== undefined ? Proxmox.Utils.format_size(v) : '',
+		    },
+		    {
+			dataIndex: 'crypt-mode',
+			text: gettext('Encrypted'),
+			flex: 1,
+			renderer: (v) => {
+			    let modeIdx = PBS.Utils.cryptmap.indexOf(v);
+			    if (modeIdx === -1) {
+				modeIdx = 0;
+			    }
+			    let iconCls = PBS.Utils.cryptIconCls[modeIdx];
+			    return `<i class="fa fa-${iconCls}"></i> ${PBS.Utils.cryptText[modeIdx]}`;
+			},
+		    },
+		],
+	    }, {
+		xtype: 'box',
+		padding: 10,
+		style: {
+		    'white-space': 'pre',
+		},
+		scrollable: true,
+		title: gettext('Comment'),
+		reference: 'comment',
+	    }, {
+		xtype: 'box',
+		padding: 10,
+		style: {
+		    'white-space': 'pre',
+		},
+		scrollable: true,
+		title: gettext('Group Comment'),
+		reference: 'group-comment',
+	    }],
+	},
+    ],
+
+    initComponent: function() {
+	let me = this;
+	let type = me['backup-type'];
+	let id = me['backup-id'];
+	let time = me['backup-time'];
+	let datetime = new Date(time*1000);
+	if (type === undefined || id === undefined || time === undefined) {
+	    throw "snapshot id not given";
+	}
+
+	let snapshotText = `${type}/${id}/${PBS.Utils.render_datetime_utc(datetime)}`;
+	me.title = Ext.String.format(gettext('Snapshot {0}'), snapshotText);
+
+	me.callParent();
+	Proxmox.Utils.API2Request({
+	    url: `/api2/extjs/admin/datastore/${me.datastore}/snapshot-information`,
+	    params: {
+		'backup-type': type,
+		'backup-id': id,
+		'backup-time': time,
+	    },
+	    method: 'GET',
+	    success: ({ result }) => {
+		me.lookup('backup-time').updateValue(datetime);
+		me.lookup('protected').updateValue(Proxmox.Utils.format_boolean(result.data.protected));
+		me.lookup('size').updateValue(Proxmox.Utils.format_size(result.data.size));
+		me.lookup('owner').updateValue(result.data.owner);
+		me.lookup('comment').setData(result.data.comment);
+		me.lookup('group-comment').setData(result.data['group-notes']);
+
+		me.lookup('files').getStore().setData(result.data.files);
+
+		let verification = result.data.verification;
+		if (verification !== undefined) {
+		    let iconCls = 'times critical';
+		    if (verification.state === 'ok') {
+			iconCls = 'check good';
+		    }
+		    let txt = Ext.htmlEncode(verification.state);
+		    let verifyState = `<i class="fa fa-${iconCls}"></i> ${txt}`;
+
+		    let task = Proxmox.Utils.parse_task_upid(verification.upid);
+		    let verifyTime = Proxmox.Utils.render_timestamp(task.starttime);
+		    me.lookup('verify-state').updateValue(verifyState);
+		    me.lookup('verify-last').updateValue(verifyTime);
+		} else {
+		    me.lookup('verify-state').updateValue(Proxmox.Utils.NoneText);
+		    me.lookup('verify-last').updateValue(Proxmox.Utils.NoneText);
+		}
+
+		let uploadStats = result.data['upload-statistics'];
+		if (uploadStats !== undefined) {
+		    me.lookup('upload-size').updateValue(Proxmox.Utils.format_size(uploadStats.size));
+		    me.lookup('compressed-size').updateValue(Proxmox.Utils.format_size(uploadStats['compressed-size']));
+		    me.lookup('chunk-count').updateValue(uploadStats.count);
+		    me.lookup('duplicate-chunks').updateValue(uploadStats.duplicates);
+		} else {
+		    me.lookup('upload-title').setVisible(false);
+		    me.lookup('upload-size').setVisible(false);
+		    me.lookup('compressed-size').setVisible(false);
+		    me.lookup('chunk-count').setVisible(false);
+		    me.lookup('duplicate-chunks').setVisible(false);
+		}
+	    },
+	    failure: function(response, opts) {
+		Ext.Msg.alert(gettext('Error'), response.htmlStatus, function() {
+		    me.close();
+		});
+	    },
+	});
+    },
+});
-- 
2.30.2





More information about the pbs-devel mailing list