2020-06-23 10:09:54 +00:00
|
|
|
Ext.define('pbs-file-tree', {
|
|
|
|
extend: 'Ext.data.Model',
|
|
|
|
|
2020-09-25 16:40:03 +00:00
|
|
|
fields: ['filepath', 'text', 'type', 'size',
|
2020-06-23 10:09:54 +00:00
|
|
|
{
|
|
|
|
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}`;
|
|
|
|
},
|
2020-09-25 16:40:03 +00:00
|
|
|
},
|
2020-06-23 10:09:54 +00:00
|
|
|
],
|
|
|
|
idProperty: 'filepath',
|
|
|
|
});
|
|
|
|
|
|
|
|
Ext.define("PBS.window.FileBrowser", {
|
|
|
|
extend: "Ext.window.Window",
|
|
|
|
|
|
|
|
width: 800,
|
2020-06-25 09:54:22 +00:00
|
|
|
height: 600,
|
2020-06-23 10:09:54 +00:00
|
|
|
|
|
|
|
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'],
|
|
|
|
};
|
2020-09-25 16:40:03 +00:00
|
|
|
params.filepath = data.filepath;
|
2020-06-23 10:09:54 +00:00
|
|
|
atag.download = data.text;
|
2020-09-25 16:40:03 +00:00
|
|
|
atag.href = me
|
|
|
|
.buildUrl(`/api2/json/admin/datastore/${view.datastore}/pxar-file-download`, params);
|
2020-06-23 10:09:54 +00:00
|
|
|
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;
|
|
|
|
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'],
|
|
|
|
});
|
2020-06-25 09:54:46 +00:00
|
|
|
store.load(() => {
|
|
|
|
let root = store.getRoot();
|
|
|
|
root.expand(); // always expand invisible root node
|
2020-07-23 11:03:49 +00:00
|
|
|
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) {
|
2020-06-25 09:54:46 +00:00
|
|
|
root.firstChild.expand();
|
|
|
|
}
|
|
|
|
});
|
2020-06-23 10:09:54 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
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;
|
|
|
|
},
|
2020-09-25 16:40:03 +00:00
|
|
|
},
|
2020-06-23 10:09:54 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2020-09-25 16:40:03 +00:00
|
|
|
},
|
2020-06-23 10:09:54 +00:00
|
|
|
},
|
2020-09-25 16:40:03 +00:00
|
|
|
],
|
|
|
|
},
|
2020-06-23 10:09:54 +00:00
|
|
|
],
|
|
|
|
|
|
|
|
buttons: [
|
|
|
|
{
|
|
|
|
text: gettext('Download'),
|
|
|
|
handler: 'downloadFile',
|
|
|
|
reference: 'downloadBtn',
|
|
|
|
disabled: true,
|
2020-09-25 16:40:03 +00:00
|
|
|
},
|
2020-06-23 10:09:54 +00:00
|
|
|
],
|
|
|
|
});
|