diff --git a/www/DataStoreContent.js b/www/DataStoreContent.js index 38daf8768..097e037ee 100644 --- a/www/DataStoreContent.js +++ b/www/DataStoreContent.js @@ -195,6 +195,25 @@ Ext.define('PBS.DataStoreContent', { }); win.on('destroy', this.reload, this); win.show(); + }, + + openBackupFileDownloader: function() { + let me = this; + let view = me.getView(); + + let rec = view.selModel.getSelection()[0]; + if (!(rec && rec.data)) return; + let data = rec.data; + + Ext.create('PBS.window.BackupFileDownloader', { + baseurl: `/api2/json/admin/datastore/${view.datastore}`, + params: { + 'backup-id': data['backup-id'], + 'backup-type': data['backup-type'], + 'backup-time': (data['backup-time'].getTime()/1000).toFixed(0), + }, + files: data.files, + }).show(); } }, @@ -277,6 +296,16 @@ Ext.define('PBS.DataStoreContent', { parentXType: 'pbsDataStoreContent', enableFn: function(record) { return !record.data.leaf; }, handler: 'onPrune', + }, + { + xtype: 'proxmoxButton', + text: gettext('Download Files'), + disabled: true, + parentXType: 'pbsDataStoreContent', + handler: 'openBackupFileDownloader', + enableFn: function(record) { + return !!record.data.leaf; + }, } ], }); diff --git a/www/Makefile b/www/Makefile index 5a84d43ea..be3117a25 100644 --- a/www/Makefile +++ b/www/Makefile @@ -19,6 +19,7 @@ JSSRC= \ window/ACLEdit.js \ window/DataStoreEdit.js \ window/CreateDirectory.js \ + window/BackupFileDownloader.js \ dashboard/DataStoreStatistics.js \ dashboard/LongestTasks.js \ dashboard/RunningTasks.js \ diff --git a/www/window/BackupFileDownloader.js b/www/window/BackupFileDownloader.js new file mode 100644 index 000000000..5f8566ee7 --- /dev/null +++ b/www/window/BackupFileDownloader.js @@ -0,0 +1,132 @@ +Ext.define('PBS.window.BackupFileDownloader', { + extend: 'Ext.window.Window', + alias: 'widget.pbsBackupFileDownloader', + + title: gettext('Download Files'), + bodyPadding: 10, + + width: 400, + modal: true, + resizable: false, + + layout: { + type: 'vbox', + align: 'stretch', + }, + + controller: { + xclass: 'Ext.app.ViewController', + + buildUrl: function(baseurl, params) { + let url = new URL(baseurl, window.location.origin); + for (const [key, value] of Object.entries(params)) { + url.searchParams.append(key, value); + } + + return url.href; + }, + + downloadFile: function() { + let me = this; + let view = me.getView(); + let combo = me.lookup('file'); + let file = combo.getValue(); + + let idx = file.lastIndexOf('.'); + let filename = file.slice(0, idx); + let atag = document.createElement('a'); + let params = view.params; + params['file-name'] = file; + atag.download = filename; + atag.href = me.buildUrl(`${view.baseurl}/download-decoded`, params); + atag.click(); + }, + + changeFile: function(comob, value) { + let me = this; + let combo = me.lookup('file'); + let rec = combo.getStore().findRecord('filename', value, 0, false, true, true); + let canDownload = !rec.data.encrypted; + me.lookup('encryptedHint').setVisible(!canDownload); + me.lookup('downloadBtn').setDisabled(!canDownload); + }, + + init: function(view) { + let me = this; + if (!view.baseurl) { + throw "no baseurl given"; + } + + if (!view.params) { + throw "no params given"; + } + + if (!view.files) { + throw "no files given"; + } + + me.lookup('file').getStore().loadData(view.files, false); + }, + + control: { + 'proxmoxComboGrid': { + change: 'changeFile' + }, + 'button': { + click: 'downloadFile', + } + }, + }, + + items: [ + { + xtype: 'proxmoxComboGrid', + valueField: 'filename', + allowBlank: false, + displayField: 'filename', + reference: 'file', + emptyText: gettext('No file selected'), + fieldLabel: gettext('File'), + store: { + fields: ['filename', 'size', 'encrypted',], + idProperty: ['filename'], + }, + listConfig: { + emptyText: gettext('No Data'), + columns: [ + { + text: gettext('Filename'), + dataIndex: 'filename', + renderer: Ext.String.htmlEncode, + flex: 1, + }, + { + text: gettext('Size'), + dataIndex: 'size', + renderer: val => val === undefined ? '' : Proxmox.Utils.format_size(val), + }, + { + text: gettext('Encrypted'), + dataIndex: 'encrypted', + renderer: Proxmox.Utils.format_boolean, + }, + ], + }, + }, + { + xtype: 'displayfield', + userCls: 'pmx-hint', + reference: 'encryptedHint', + hidden: true, + value: gettext('Encrypted Files cannot be decoded on the server directly. Please use the client where the decryption key is located.'), + } + ], + + buttons: [ + { + text: gettext('Download'), + reference: 'downloadBtn', + disabled: true, + }, + ], +});