fix #8015: ui: upload: let the user choose the .img image format
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 <me@dualfroz.com> Link: https://lore.proxmox.com/20260929135840.2748665-2-me@dualfroz.com
This commit is contained in:
1 parent
f353e94052
commit
baaeedd60a
1 file changed
+33
-12
@@ -14,11 +14,10 @@ Ext.define('PVE.window.UploadToStorage', {
|
|||||||
vztmpl: ['.tar.gz', '.tar.xz', '.tar.zst'],
|
vztmpl: ['.tar.gz', '.tar.xz', '.tar.zst'],
|
||||||
},
|
},
|
||||||
|
|
||||||
// accepted for file selection, will be renamed to real extension
|
// accepted for file selection, but the extension does not tell the image format, so the user
|
||||||
extensionAliases: {
|
// has to select it and it gets appended as real extension
|
||||||
import: {
|
formatAliases: {
|
||||||
'.img': '.raw',
|
import: ['.img'],
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
cbindData: function (initialConfig) {
|
cbindData: function (initialConfig) {
|
||||||
@@ -27,7 +26,7 @@ Ext.define('PVE.window.UploadToStorage', {
|
|||||||
|
|
||||||
me.url = `/nodes/${me.nodename}/storage/${me.storage}/upload`;
|
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 {
|
return {
|
||||||
extensions: fileSelectorExt.join(', '),
|
extensions: fileSelectorExt.join(', '),
|
||||||
@@ -40,6 +39,7 @@ Ext.define('PVE.window.UploadToStorage', {
|
|||||||
size: '-',
|
size: '-',
|
||||||
mimetype: '-',
|
mimetype: '-',
|
||||||
filename: '',
|
filename: '',
|
||||||
|
needsFormat: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -154,12 +154,12 @@ Ext.define('PVE.window.UploadToStorage', {
|
|||||||
const me = this;
|
const me = this;
|
||||||
const vm = me.getViewModel();
|
const vm = me.getViewModel();
|
||||||
const view = me.getView();
|
const view = me.getView();
|
||||||
let name = input.value.replace(/^.*(\/|\\)/, '');
|
const name = input.value.replace(/^.*(\/|\\)/, '');
|
||||||
for (const [alias, real] of Object.entries(view.extensionAliases[view.content] ?? {})) {
|
const aliases = view.formatAliases[view.content] ?? [];
|
||||||
if (name.endsWith(alias)) {
|
const needsFormat = aliases.some((alias) => name.endsWith(alias));
|
||||||
name += real;
|
me.selectedName = name;
|
||||||
}
|
vm.set('needsFormat', needsFormat);
|
||||||
}
|
me.lookup('imageFormat').setValue(null);
|
||||||
const fileInput = input.fileInputEl.dom;
|
const fileInput = input.fileInputEl.dom;
|
||||||
vm.set('filename', name);
|
vm.set('filename', name);
|
||||||
vm.set(
|
vm.set(
|
||||||
@@ -180,6 +180,12 @@ Ext.define('PVE.window.UploadToStorage', {
|
|||||||
checksum.setDisabled(false);
|
checksum.setDisabled(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
formatChange: function (field, format) {
|
||||||
|
if (format) {
|
||||||
|
this.getViewModel().set('filename', `${this.selectedName}.${format}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
items: [
|
items: [
|
||||||
@@ -222,6 +228,21 @@ Ext.define('PVE.window.UploadToStorage', {
|
|||||||
},
|
},
|
||||||
regexText: gettext('Wrong file extension'),
|
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',
|
xtype: 'displayfield',
|
||||||
name: 'size',
|
name: 'size',
|
||||||
|
|||||||
Reference in new issue
Block a user