[pve-devel] [PATCH v2 manager 2/5] ui: refactor UploadToStorage.js

Dominik Csapak d.csapak at proxmox.com
Mon Aug 2 16:34:00 CEST 2021


comments inline:

On 7/22/21 15:06, Lorenz Stechauner wrote:
> this also removes the "content" selector from the window.
> as far as it seems, this selector was never able to select
> more than one entry, so it was useless.
> 
> the check for FormData() is also removed, because this is
> supported by all major browsers for a long time. therefore
> doStandardSubmit() is also not necessary.
> 
> Signed-off-by: Lorenz Stechauner <l.stechauner at proxmox.com>
> ---
>   www/manager6/storage/ContentView.js    |   2 +-
>   www/manager6/window/UploadToStorage.js | 360 ++++++++++++++-----------
>   2 files changed, 209 insertions(+), 153 deletions(-)
> 
> diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
> index ca0ad664..00a94f3c 100644
> --- a/www/manager6/storage/ContentView.js
> +++ b/www/manager6/storage/ContentView.js
> @@ -69,7 +69,7 @@ Ext.define('PVE.storage.ContentView', {
>   			Ext.create('PVE.window.UploadToStorage', {
>   			    nodename: nodename,
>   			    storage: storage,
> -			    contents: [content],
> +			    content: content,
>   			    autoShow: true,
>   			    taskDone: () => reload(),
>   			});
> diff --git a/www/manager6/window/UploadToStorage.js b/www/manager6/window/UploadToStorage.js
> index 3c35020a..fb9850b3 100644
> --- a/www/manager6/window/UploadToStorage.js
> +++ b/www/manager6/window/UploadToStorage.js
> @@ -1,191 +1,247 @@
>   Ext.define('PVE.window.UploadToStorage', {
>       extend: 'Ext.window.Window',
>       alias: 'widget.pveStorageUpload',
> +    mixins: ['Proxmox.Mixin.CBind'],
>   
>       resizable: false,
> -
>       modal: true,
>   
> -    initComponent: function() {
> -        var me = this;
> +    title: gettext('Upload'),
>   
> -	if (!me.nodename) {
> -	    throw "no node name specified";
> -	}
> -	if (!me.storage) {
> -	    throw "no storage ID specified";
> -	}
> +    acceptedExtensions: {
> +	iso: ['.img', '.iso'],
> +	vztmpl: ['.tar.gz', '.tar.xz'],
> +    },
> +
> +    cbindData: function(initialConfig) {
> +	const me = this;
> +	return {
> +	    nodename: me.nodename,
> +	    storage: me.storage,
> +	    content: me.content,

these should not be necessary, all properties of the view should 
automatically also be cbindable (maybe a default needs to be set)

> +	    extensions: me.acceptedExtensions[me.content].join(', '),

i'd prefer to check if me.content is actually a valid type,
and maybe erroring out if not (e.g 'throw ...')

> +	};
> +    },
>   
> -	let baseurl = `/nodes/${me.nodename}/storage/${me.storage}/upload`;
> +    cbind: {
> +	url: `/nodes/{nodename}/storage/{storage}/upload`,
> +    },

we normally do this in the cbindData function above

me.url = ``;

>   
> -	let pbar = Ext.create('Ext.ProgressBar', {
> -            text: 'Ready',
> -	    hidden: true,
> -	});
> +    viewModel: {
> +	data: {
> +	    size: '-',
> +	    mimetype: '-',
> +	    filename: '',
> +	},
> +    },
>   
> -	let acceptedExtensions = {
> -	    iso: ".img, .iso",
> -	    vztmpl: ".tar.gz, .tar.xz",
> -	};
> +    controller: {
> +	submit: function(button) {
> +	    const view = this.getView();
> +	    const form = Ext.getCmp('formPanel').getForm();
> +	    const abortBtn = Ext.getCmp('abortBtn');
> +	    const pbar = Ext.getCmp('progressBar');
> +
> +	    const updateProgress = function(per, bytes) {
> +		let text = (per * 100).toFixed(2) + '%';
> +		if (bytes) {
> +		    text += " (" + Proxmox.Utils.format_size(bytes) + ')';
> +		}
> +		pbar.updateProgress(per, text);
> +	    };
>   
> -	let defaultContent = me.contents[0] || '';
> -
> -	let fileField = Ext.create('Ext.form.field.File', {
> -	    name: 'filename',
> -	    buttonText: gettext('Select File...'),
> -	    allowBlank: false,
> -	    setAccept: function(content) {
> -		let acceptString = acceptedExtensions[content] || '';
> -		this.fileInputEl.set({
> -		    accept: acceptString,
> -		});
> -	    },
> -	    listeners: {
> -		afterrender: function(cmp) {
> -		    cmp.setAccept(defaultContent);
> -		},
> -	    },
> -	});
> +	    const fd = new FormData();
> +
> +	    button.setDisabled(true);
> +	    abortBtn.setDisabled(false);
>   
> -	me.formPanel = Ext.create('Ext.form.Panel', {
> +	    const contentField = form.findField('content');
> +	    fd.append("content", contentField.getValue());
> +	    contentField.setDisabled(true);

why use a separate input field for this?
you could simply access view.content, no?
would make the code here and below a bit shorter.

> +
> +	    const fileField = form.findField('file');
> +	    const file = fileField.fileInputEl.dom.files[0];
> +	    fileField.setDisabled(true);
> +
> +	    const filenameField = form.findField('filename');
> +	    const filename = filenameField.getValue();
> +	    filenameField.setDisabled(true);

why do you get the filename field here?
we already have the info in the viewModel (since we 'bind' the value)

const vm = view.getViewModel();
const filename = vm.get('filename');


> +
> +	    const algorithmField = form.findField('checksum-algorithm');
> +	    algorithmField.setDisabled(true);
> +	    if (algorithmField.getValue() !== '__default__') {
> +		fd.append("checksum-algorithm", algorithmField.getValue());
> +
> +		const checksumField = form.findField('checksum');
> +		fd.append("checksum", checksumField.getValue());
> +		checksumField.setDisabled(true);
> +	    }

it seems this belongs in the next patch?
at least here it would fail since it would not find the field

> +
> +	    fd.append("filename", file, filename);
> +
> +	    pbar.setVisible(true);
> +	    updateProgress(0);
> +
> +	    const xhr = new XMLHttpRequest();
> +	    view.xhr = xhr;
> +
> +	    xhr.addEventListener("load", function(e) {
> +		if (xhr.status === 200) {
> +		    view.close();
> +		    return;
> +		}
> +		const err = Ext.htmlEncode(xhr.statusText);
> +		let msg = `${gettext('Error')} ${xhr.status.toString()}: ${err}`;
> +		if (xhr.responseText !== "") {
> +		    const result = Ext.decode(xhr.responseText);
> +		    result.message = msg;
> +		    msg = Proxmox.Utils.extractRequestError(result, true);
> +		}
> +		Ext.Msg.alert(gettext('Error'), msg, btn => view.close());
> +	    }, false);
> +
> +	    xhr.addEventListener("error", function(e) {
> +		const err = e.target.status.toString();
> +		const msg = `Error '${err}' occurred while receiving the document.`;
> +		Ext.Msg.alert(gettext('Error'), msg, btn => view.close());
> +	    });
> +
> +	    xhr.upload.addEventListener("progress", function(evt) {
> +		if (evt.lengthComputable) {
> +		    const percentComplete = evt.loaded / evt.total;
> +		    updateProgress(percentComplete, evt.loaded);
> +		}
> +	    }, false);
> +
> +	    xhr.open("POST", `/api2/json${view.url}`, true);
> +	    xhr.send(fd);
> +	},
> +
> +	validitychange: function(f, valid) {
> +	    const submitBtn = Ext.getCmp('submitBtn');
> +	    submitBtn.setDisabled(!valid);
> +	},
> +
> +	fileChange: function(input) {
> +	    const vm = this.getViewModel();
> +	    const name = input.value.replace(/^.*(\/|\\)/, '');
> +	    const fileInput = input.fileInputEl.dom;
> +	    vm.set('filename', name);
> +	    vm.set('size', (fileInput.files[0] && Proxmox.Utils.format_size(fileInput.files[0].size)) || '-');
> +	    vm.set('mimetype', (fileInput.files[0] && fileInput.files[0].type) || '-');
> +	},
> +    },
> +
> +    items: [
> +	{
> +	    xtype: 'form',
> +	    id: 'formPanel',
>   	    method: 'POST',
>   	    waitMsgTarget: true,
>   	    bodyPadding: 10,
>   	    border: false,
> -	    width: 300,
> +	    width: 400,
>   	    fieldDefaults: {
>   		labelWidth: 100,
>   		anchor: '100%',
>               },
>   	    items: [
>   		{
> -		    xtype: 'pveContentTypeSelector',
> -		    cts: me.contents,
> -		    fieldLabel: gettext('Content'),
> -		    name: 'content',
> -		    value: defaultContent,
> +		    xtype: 'filefield',
> +		    name: 'file',
> +		    buttonText: gettext('Select File'),
>   		    allowBlank: false,
> +		    fieldLabel: gettext('File'),
> +		    cbind: {
> +			accept: '{extensions}',
> +		    },
>   		    listeners: {
> -			change: function(cmp, newValue, oldValue) {
> -			    fileField.setAccept(newValue);
> -			},
> +			change: 'fileChange',
>   		    },
>   		},
> -		fileField,
> -		pbar,
> -	    ],
> -	});
> -
> -	let form = me.formPanel.getForm();
> -
> -	let doStandardSubmit = function() {
> -	    form.submit({
> -		url: "/api2/htmljs" + baseurl,
> -		waitMsg: gettext('Uploading file...'),
> -		success: function(f, action) {
> -		    me.close();
> +		{
> +		    xtype: 'textfield',
> +		    name: 'filename',
> +		    allowBlank: false,
> +		    fieldLabel: gettext('File name'),
> +		    bind: {
> +			value: '{filename}',
> +		    },
>   		},
> -		failure: function(f, action) {
> -		    var msg = PVE.Utils.extractFormActionError(action);
> -                    Ext.Msg.alert(gettext('Error'), msg);
> +		{
> +		    xtype: 'displayfield',
> +		    name: 'size',
> +		    fieldLabel: gettext('File size'),
> +		    bind: {
> +			value: '{size}',
> +		    },
>   		},
> -	    });
> -	};
> -
> -	let updateProgress = function(per, bytes) {
> -	    var text = (per * 100).toFixed(2) + '%';
> -	    if (bytes) {
> -		text += " (" + Proxmox.Utils.format_size(bytes) + ')';
> -	    }
> -	    pbar.updateProgress(per, text);
> -	};
> -
> -	let abortBtn = Ext.create('Ext.Button', {
> +		{
> +		    xtype: 'displayfield',
> +		    name: 'mimetype',
> +		    fieldLabel: gettext('MIME type'),
> +		    bind: {
> +			value: '{mimetype}',
> +		    },
> +		},
> +		{
> +		    xtype: 'progressbar',
> +		    text: 'Ready',
> +		    hidden: true,
> +		    id: 'progressBar',
> +		},
> +		{
> +		    xtype: 'hiddenfield',
> +		    name: 'content',
> +		    cbind: {
> +			value: '{content}',
> +		    },
> +		},
> +	    ],
> +	   listeners: {
> +		validitychange: 'validitychange',
> +	   },
> +	},
> +    ],
> +
> +    buttons: [
> +	{
> +	    xtype: 'button',
>   	    text: gettext('Abort'),
> +	    id: 'abortBtn',
>   	    disabled: true,
>   	    handler: function() {
> -		me.close();
> +		const me = this;
> +		me.up('pveStorageUpload').close();
>   	    },
> -	});
> -
> -	let submitBtn = Ext.create('Ext.Button', {
> +	},
> +	{
>   	    text: gettext('Upload'),
> +	    id: 'submitBtn',
>   	    disabled: true,
> -	    handler: function(button) {
> -		var fd;
> -		try {
> -		    fd = new FormData();
> -		} catch (err) {
> -		    doStandardSubmit();
> -		    return;
> -		}
> +	    handler: 'submit',
> +	},
> +    ],
> +
> +    listeners: {
> +	close: function() {
> +	    const me = this;
> +	    if (me.xhr) {
> +		me.xhr.abort();
> +		delete me.xhr;
> +	    }
> +	},
> +    },
>   
> -		button.setDisabled(true);
> -		abortBtn.setDisabled(false);
> -
> -		var field = form.findField('content');
> -		fd.append("content", field.getValue());
> -		field.setDisabled(true);
> -
> -		field = form.findField('filename');
> -		var file = field.fileInputEl.dom;
> -		fd.append("filename", file.files[0]);
> -		field.setDisabled(true);
> -
> -		pbar.setVisible(true);
> -		updateProgress(0);
> -
> -		let xhr = new XMLHttpRequest();
> -		me.xhr = xhr;
> -
> -		xhr.addEventListener("load", function(e) {
> -		    if (xhr.status === 200) {
> -			me.close();
> -			return;
> -		    }
> -		    let err = Ext.htmlEncode(xhr.statusText);
> -		    let msg = `${gettext('Error')} ${xhr.status.toString()}: ${err}`;
> -		    if (xhr.responseText !== "") {
> -			let result = Ext.decode(xhr.responseText);
> -			result.message = msg;
> -			msg = Proxmox.Utils.extractRequestError(result, true);
> -		    }
> -		    Ext.Msg.alert(gettext('Error'), msg, btn => me.close());
> -		}, false);
> -
> -		xhr.addEventListener("error", function(e) {
> -		    let err = e.target.status.toString();
> -		    let msg = `Error '${err}' occurred while receiving the document.`;
> -		    Ext.Msg.alert(gettext('Error'), msg, btn => me.close());
> -		});
> -
> -		xhr.upload.addEventListener("progress", function(evt) {
> -		    if (evt.lengthComputable) {
> -			let percentComplete = evt.loaded / evt.total;
> -			updateProgress(percentComplete, evt.loaded);
> -		    }
> -		}, false);
> -
> -		xhr.open("POST", `/api2/json${baseurl}`, true);
> -		xhr.send(fd);
> -	    },
> -	});
> -
> -	form.on('validitychange', (f, valid) => submitBtn.setDisabled(!valid));
> -
> -	Ext.apply(me, {
> -	    title: gettext('Upload'),
> -	    items: me.formPanel,
> -	    buttons: [abortBtn, submitBtn],
> -	    listeners: {
> -		close: function() {
> -		    if (me.xhr) {
> -			me.xhr.abort();
> -			delete me.xhr;
> -		    }
> -		},
> -	    },
> -	});
> +    initComponent: function() {
> +        const me = this;
> +
> +	if (!me.nodename) {
> +	    throw "no node name specified";
> +	}
> +	if (!me.storage) {
> +	    throw "no storage ID specified";
> +	}
>   
>           me.callParent();
>       },
> 






More information about the pve-devel mailing list