ui: add BackupFileDownloader
enables to be able to download whole files from the backup (e.g. the decoded didx/fidx/blobs) for unencrypted backups Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
parent
7b1e26699d
commit
98425309b0
@ -195,6 +195,25 @@ Ext.define('PBS.DataStoreContent', {
|
|||||||
});
|
});
|
||||||
win.on('destroy', this.reload, this);
|
win.on('destroy', this.reload, this);
|
||||||
win.show();
|
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',
|
parentXType: 'pbsDataStoreContent',
|
||||||
enableFn: function(record) { return !record.data.leaf; },
|
enableFn: function(record) { return !record.data.leaf; },
|
||||||
handler: 'onPrune',
|
handler: 'onPrune',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
xtype: 'proxmoxButton',
|
||||||
|
text: gettext('Download Files'),
|
||||||
|
disabled: true,
|
||||||
|
parentXType: 'pbsDataStoreContent',
|
||||||
|
handler: 'openBackupFileDownloader',
|
||||||
|
enableFn: function(record) {
|
||||||
|
return !!record.data.leaf;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -19,6 +19,7 @@ JSSRC= \
|
|||||||
window/ACLEdit.js \
|
window/ACLEdit.js \
|
||||||
window/DataStoreEdit.js \
|
window/DataStoreEdit.js \
|
||||||
window/CreateDirectory.js \
|
window/CreateDirectory.js \
|
||||||
|
window/BackupFileDownloader.js \
|
||||||
dashboard/DataStoreStatistics.js \
|
dashboard/DataStoreStatistics.js \
|
||||||
dashboard/LongestTasks.js \
|
dashboard/LongestTasks.js \
|
||||||
dashboard/RunningTasks.js \
|
dashboard/RunningTasks.js \
|
||||||
|
132
www/window/BackupFileDownloader.js
Normal file
132
www/window/BackupFileDownloader.js
Normal file
@ -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,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user