[pve-devel] [PATCH proxmox-widget-toolkit 1/3] window: add FileBrowser

Stefan Reiter s.reiter at proxmox.com
Thu Apr 1 17:34:42 CEST 2021


from proxmox-backup, only names changed

Signed-off-by: Stefan Reiter <s.reiter at proxmox.com>
---
 src/Makefile              |   1 +
 src/window/FileBrowser.js | 248 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 249 insertions(+)
 create mode 100644 src/window/FileBrowser.js

diff --git a/src/Makefile b/src/Makefile
index 44c11ea..f97c74a 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -64,6 +64,7 @@ JSSRC=					\
 	window/ACMEAccount.js		\
 	window/ACMEPluginEdit.js	\
 	window/ACMEDomains.js		\
+	window/FileBrowser.js		\
 	node/APT.js			\
 	node/NetworkEdit.js		\
 	node/NetworkView.js		\
diff --git a/src/window/FileBrowser.js b/src/window/FileBrowser.js
new file mode 100644
index 0000000..82fd1b2
--- /dev/null
+++ b/src/window/FileBrowser.js
@@ -0,0 +1,248 @@
+Ext.define('proxmox-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("Proxmox.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";
+	    }
+
+	    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: 'proxmox-file-tree',
+		defaultRootId: '/',
+		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,
+	},
+    ],
+});
-- 
2.20.1





More information about the pve-devel mailing list