From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with UTF8SMTPS id EED306AF65 for ; Mon, 2 Aug 2021 16:34:33 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with UTF8SMTP id DBE7E9850 for ; Mon, 2 Aug 2021 16:34:03 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with UTF8SMTPS id 9DC7B9842 for ; Mon, 2 Aug 2021 16:34:02 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with UTF8SMTP id 668F340E7F; Mon, 2 Aug 2021 16:34:02 +0200 (CEST) Message-ID: <40bf2dd9-f5f4-53ed-3026-e901b620a02f@proxmox.com> Date: Mon, 2 Aug 2021 16:34:00 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.0 Content-Language: en-US To: Proxmox VE development discussion , Lorenz Stechauner References: <20210722130631.237107-1-l.stechauner@proxmox.com> <20210722130631.237107-7-l.stechauner@proxmox.com> From: Dominik Csapak In-Reply-To: <20210722130631.237107-7-l.stechauner@proxmox.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.527 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment NICE_REPLY_A -0.08 Looks like a legit reply (A) SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: Re: [pve-devel] [PATCH v2 manager 2/5] ui: refactor UploadToStorage.js X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 02 Aug 2021 14:34:34 -0000 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 > --- > 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(); > }, >