From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 7A79A1FF0A7 for ; Wed, 30 Sep 2026 09:47:24 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 9A6352170E; Wed, 30 Sep 2026 09:46:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dualfroz.com; s=dkim; t=1790690322; h=from:subject:date:message-id:to:mime-version: content-transfer-encoding:in-reply-to:references; bh=aauGGEjjx/x49oio5K6LCA3zW/A6Krc0VB+MQEtMZA0=; b=PJLekQTrTvcKrsOVD48nUFstVgHr40eR4HwnYSoXwQFKq8/E1U6Ja2gr6f+uaoC76YSfpW aU/YShij+X67OQjss10Pq85CF5fmcK0nEa3Ek+tk7biYLDXpfLxclJgiNVPBk5jJi4ljMX ibJRMQROStYCFWLmfIoe9BouhDWwkHS+spZY3k+HKwUeCzouvUs8j3kKuxZEucee8CrfR+ gfW59jk5mQ7jDZcK0BMljF9okWrnC1WuqTW5xCJta4FcqyXdvPRwVePrQ0zmromzNMTWcz hIzSPo5CrRm37U3TKIf8+ei0yi4iQmk8DH/BDkLmtaKAVY4LILTYsbWQsyfJdg== From: Michal Fox To: pve-devel@lists.proxmox.com Subject: [PATCH manager 1/2] fix #8015: ui: upload: let the user choose the .img image format Date: Tue, 29 Sep 2026 15:58:39 +0200 Message-ID: <20260929135840.2748665-2-me@dualfroz.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260929135840.2748665-1-me@dualfroz.com> References: <20260929135840.2748665-1-me@dualfroz.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Last-TLS-Session-Version: TLSv1.3 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.041 Adjusted score from AWL reputation of From: address DKIM_INVALID 0.1 DKIM or DK signature exists, but is not valid DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DMARC_PASS -0.1 DMARC pass policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record X-MailFrom: me@dualfroz.com X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation Message-ID-Hash: IUCPB2DB3CGYCVTF2QE25XCKRAEKQ2ZT X-Message-ID-Hash: IUCPB2DB3CGYCVTF2QE25XCKRAEKQ2ZT X-Mailman-Approved-At: Wed, 30 Sep 2026 09:46:15 +0200 X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: When uploading a '.img' file as import content, '.raw' is appended to the file name, so the image is always treated as a raw image. But the '.img' extension is also commonly used for other formats, for example the Ubuntu cloud images are qcow2 images. Such an image is then imported as raw disk, which results in a disk with the size of the qcow2 file and a guest that does not boot. The format cannot be derived from the '.img' extension, so show a format selector for such files and only append the extension of the selected format to the file name. The upload stays disabled until a format is selected, so the choice is always an explicit one. Signed-off-by: Michal Fox --- www/manager6/window/UploadToStorage.js | 45 +++++++++++++++++++------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/www/manager6/window/UploadToStorage.js b/www/manager6/window/UploadToStorage.js index cc53596d..54af1603 100644 --- a/www/manager6/window/UploadToStorage.js +++ b/www/manager6/window/UploadToStorage.js @@ -14,11 +14,10 @@ Ext.define('PVE.window.UploadToStorage', { vztmpl: ['.tar.gz', '.tar.xz', '.tar.zst'], }, - // accepted for file selection, will be renamed to real extension - extensionAliases: { - import: { - '.img': '.raw', - }, + // accepted for file selection, but the extension does not tell the image format, so the user + // has to select it and it gets appended as real extension + formatAliases: { + import: ['.img'], }, cbindData: function (initialConfig) { @@ -27,7 +26,7 @@ Ext.define('PVE.window.UploadToStorage', { me.url = `/nodes/${me.nodename}/storage/${me.storage}/upload`; - let fileSelectorExt = ext.concat(Object.keys(me.extensionAliases[me.content] ?? {})); + let fileSelectorExt = ext.concat(me.formatAliases[me.content] ?? []); return { extensions: fileSelectorExt.join(', '), @@ -40,6 +39,7 @@ Ext.define('PVE.window.UploadToStorage', { size: '-', mimetype: '-', filename: '', + needsFormat: false, }, }, @@ -154,12 +154,12 @@ Ext.define('PVE.window.UploadToStorage', { const me = this; const vm = me.getViewModel(); const view = me.getView(); - let name = input.value.replace(/^.*(\/|\\)/, ''); - for (const [alias, real] of Object.entries(view.extensionAliases[view.content] ?? {})) { - if (name.endsWith(alias)) { - name += real; - } - } + const name = input.value.replace(/^.*(\/|\\)/, ''); + const aliases = view.formatAliases[view.content] ?? []; + const needsFormat = aliases.some((alias) => name.endsWith(alias)); + me.selectedName = name; + vm.set('needsFormat', needsFormat); + me.lookup('imageFormat').setValue(null); const fileInput = input.fileInputEl.dom; vm.set('filename', name); vm.set( @@ -178,6 +178,12 @@ Ext.define('PVE.window.UploadToStorage', { checksum.setDisabled(false); } }, + + formatChange: function (field, format) { + if (format) { + this.getViewModel().set('filename', `${this.selectedName}.${format}`); + } + }, }, items: [ @@ -220,6 +226,21 @@ Ext.define('PVE.window.UploadToStorage', { }, regexText: gettext('Wrong file extension'), }, + { + xtype: 'pveDiskFormatSelector', + reference: 'imageFormat', + fieldLabel: gettext('Format'), + allowBlank: false, + hidden: true, + disabled: true, + bind: { + hidden: '{!needsFormat}', + disabled: '{!needsFormat}', + }, + listeners: { + change: 'formatChange', + }, + }, { xtype: 'displayfield', name: 'size', -- 2.43.0