proxmox-backup/www/window/FileBrowser.js
Dominik Csapak 804f61432d api2/admin/datastore/pxar_file_download: download directory as zip
by using the new ZipEncoder and recursively add files to it
the zip only contains directories, normal files and hardlinks (by simply
copying the content), no symlinks, etc.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
2020-10-21 10:04:24 +02:00

252 lines
5.2 KiB
JavaScript

Ext.define('pbs-file-tree', {
extend: 'Ext.data.Model',
fields: ['filepath', 'text', 'type', 'size',
{
name: 'mtime',
type: 'date',
dateFormat: 'timestamp',
},
{
name: 'iconCls',
calculate: function(data) {
let icon = 'file-o';
switch (data.type) {
case 'b': // block device
icon = 'cube';
break;
case 'c': // char device
icon = 'tty';
break;
case 'd':
icon = data.expanded ? 'folder-open-o' : 'folder-o';
break;
case 'f': //regular file
icon = 'file-text-o';
break;
case 'h': // hardlink
icon = 'file-o';
break;
case 'l': // softlink
icon = 'link';
break;
case 'p': // pipe/fifo
icon = 'exchange';
break;
case 's': // socket
icon = 'plug';
break;
default:
icon = 'file-o';
break;
}
return `fa fa-${icon}`;
},
},
],
idProperty: 'filepath',
});
Ext.define("PBS.window.FileBrowser", {
extend: "Ext.window.Window",
width: 800,
height: 600,
modal: true,
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 tree = me.lookup('tree');
let selection = tree.getSelection();
if (!selection || selection.length < 1) return;
let data = selection[0].data;
let atag = document.createElement('a');
atag.download = data.text;
let params = {
'backup-id': view['backup-id'],
'backup-type': view['backup-type'],
'backup-time': view['backup-time'],
};
params.filepath = data.filepath;
atag.download = data.text;
if (data.type === 'd') {
atag.download += ".zip";
}
atag.href = me
.buildUrl(`/api2/json/admin/datastore/${view.datastore}/pxar-file-download`, params);
atag.click();
},
fileChanged: function() {
let me = this;
let tree = me.lookup('tree');
let selection = tree.getSelection();
if (!selection || selection.length < 1) return;
let data = selection[0].data;
let canDownload = false;
switch (data.type) {
case 'h':
case 'f':
canDownload = true;
break;
case 'd':
if (data.depth > 1) {
canDownload = true;
}
break;
default: break;
}
me.lookup('downloadBtn').setDisabled(!canDownload);
},
init: function(view) {
let me = this;
let tree = me.lookup('tree');
if (!view['backup-id']) {
throw "no backup-id given";
}
if (!view['backup-type']) {
throw "no backup-id given";
}
if (!view['backup-time']) {
throw "no backup-id given";
}
if (!view.datastore) {
throw "no datastore given";
}
let store = tree.getStore();
let proxy = store.getProxy();
Proxmox.Utils.monStoreErrors(tree, store, true);
proxy.setUrl(`/api2/json/admin/datastore/${view.datastore}/catalog`);
proxy.setExtraParams({
'backup-id': view['backup-id'],
'backup-type': view['backup-type'],
'backup-time': view['backup-time'],
});
store.load(() => {
let root = store.getRoot();
root.expand(); // always expand invisible root node
if (view.archive) {
let child = root.findChild('text', view.archive);
if (child) {
child.expand();
setTimeout(function() {
tree.setSelection(child);
tree.getView().focusRow(child);
}, 10);
}
} else if (root.childNodes.length === 1) {
root.firstChild.expand();
}
});
},
control: {
'treepanel': {
selectionchange: 'fileChanged',
},
},
},
layout: 'fit',
items: [
{
xtype: 'treepanel',
scrollable: true,
rootVisible: false,
reference: 'tree',
store: {
autoLoad: false,
model: 'pbs-file-tree',
nodeParam: 'filepath',
sorters: 'text',
proxy: {
appendId: false,
type: 'proxmox',
},
},
columns: [
{
text: gettext('Name'),
xtype: 'treecolumn',
flex: 1,
dataIndex: 'text',
renderer: Ext.String.htmlEncode,
},
{
text: gettext('Size'),
dataIndex: 'size',
renderer: value => value === undefined ? '' : Proxmox.Utils.format_size(value),
sorter: {
sorterFn: function(a, b) {
let asize = a.data.size || 0;
let bsize = b.data.size || 0;
return asize - bsize;
},
},
},
{
text: gettext('Modified'),
dataIndex: 'mtime',
minWidth: 200,
},
{
text: gettext('Type'),
dataIndex: 'type',
renderer: function(value) {
switch (value) {
case 'b': return gettext('Block Device');
case 'c': return gettext('Character Device');
case 'd': return gettext('Directory');
case 'f': return gettext('File');
case 'h': return gettext('Hardlink');
case 'l': return gettext('Softlink');
case 'p': return gettext('Pipe/Fifo');
case 's': return gettext('Socket');
default: return Proxmox.Utils.unknownText;
}
},
},
],
},
],
buttons: [
{
text: gettext('Download'),
handler: 'downloadFile',
reference: 'downloadBtn',
disabled: true,
},
],
});