X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;ds=sidebyside;f=www%2Fmanager6%2Fwindow%2FGuestImport.js;h=7b6dce6c227595535099b4fb55a2d135f62d72cd;hb=c8c53aa41300267f6bfa2443fe261b8269193f26;hp=7b0105e61349e89dbadb8a6be5b932a651628343;hpb=d39e2492de3f96b1c391f88f6414068967b1f832;p=pve-manager.git
diff --git a/www/manager6/window/GuestImport.js b/www/manager6/window/GuestImport.js
index 7b0105e6..7b6dce6c 100644
--- a/www/manager6/window/GuestImport.js
+++ b/www/manager6/window/GuestImport.js
@@ -92,58 +92,87 @@ Ext.define('PVE.window.GuestImport', {
summaryGrid.getStore().setData(Object.entries(values).map(([key, value]) => ({ key, value })));
},
+ calculateAdditionalCDIdx: function() {
+ let me = this;
+
+ let maxIde = me.getMaxControllerId('ide');
+ let maxSata = me.getMaxControllerId('sata');
+ // only ide0 and ide2 can be used reliably for isos (e.g. for q35)
+ if (maxIde < 0) {
+ return 'ide0';
+ }
+ if (maxIde < 2) {
+ return 'ide2';
+ }
+ if (maxSata < PVE.Utils.diskControllerMaxIDs.sata - 1) {
+ return `sata${maxSata+1}`;
+ }
+
+ return '';
+ },
+
// assume assigned sata disks indices are continuous, so without holes
- getMaxSata: function() {
+ getMaxControllerId: function(controller) {
let me = this;
let view = me.getView();
- if (view.maxSata !== undefined) {
- return view.maxSata;
+ if (!controller) {
+ return -1;
+ }
+
+ let max = view[`max${controller}`];
+ if (max !== undefined) {
+ return max;
}
- view.maxSata = -1;
+ max = -1;
for (const key of Object.keys(me.getView().vmConfig)) {
- if (!key.toLowerCase().startsWith('sata')) {
+ if (!key.toLowerCase().startsWith(controller)) {
continue;
}
- let idx = parseInt(key.slice(4), 10);
- if (idx > view.maxSata) {
- view.maxSata = idx;
+ let idx = parseInt(key.slice(controller.length), 10);
+ if (idx > max) {
+ max = idx;
}
}
me.lookup('diskGrid').getStore().each(rec => {
- if (!rec.data.id.toLowerCase().startsWith('sata')) {
+ if (!rec.data.id.toLowerCase().startsWith(controller)) {
return;
}
- let idx = parseInt(rec.data.id.slice(4), 10);
- if (idx > view.maxSata) {
- view.maxSata = idx;
+ let idx = parseInt(rec.data.id.slice(controller.length), 10);
+ if (idx > max) {
+ max = idx;
}
});
me.lookup('cdGrid').getStore().each(rec => {
- if (!rec.data.id.toLowerCase().startsWith('sata')) {
+ if (!rec.data.id.toLowerCase().startsWith(controller) || rec.data.hidden) {
return;
}
- let idx = parseInt(rec.data.id.slice(4), 10);
- if (idx > view.maxSata) {
- view.maxSata = idx;
+ let idx = parseInt(rec.data.id.slice(controller.length), 10);
+ if (idx > max) {
+ max = idx;
}
});
- return view.maxSata;
+ view[`max${controller}`] = max;
+ return max;
},
mapDisk: function(value, metaData) {
let me = this;
- let mapSata = me.lookup('mapSata');
- if (mapSata.isDisabled() || !mapSata.getValue()) {
+ let prepareForVirtIO = me.lookup('prepareForVirtIO');
+ if (prepareForVirtIO.isDisabled() || !prepareForVirtIO.getValue()) {
return value;
}
if (!value.toLowerCase().startsWith('scsi')) {
return value;
}
let offset = parseInt(value.slice(4), 10);
- let newIdx = offset + me.getMaxSata() + 1;
- if (newIdx > PVE.Utils.diskControllerMaxIDs.sata) {
+ let newIdx = offset + me.getMaxControllerId('sata') + 1;
+ if (me.getViewModel().get('isWindows') && me.getView().additionalCdIdx?.startsWith('sata')) {
+ // additionalCdIdx takes the highest sata port
+ newIdx++;
+ }
+ if (newIdx >= PVE.Utils.diskControllerMaxIDs.sata) {
let prefix = '';
if (metaData !== undefined) {
// we're in the renderer so put a warning here
@@ -155,8 +184,62 @@ Ext.define('PVE.window.GuestImport', {
return `sata${newIdx}`;
},
- refreshDiskGrid: function() {
+ refreshGrids: function() {
this.lookup('diskGrid').reconfigure();
+ this.lookup('cdGrid').reconfigure();
+ this.lookup('netGrid').reconfigure();
+ },
+
+ onOSTypeChange: function(_cb, value) {
+ let me = this;
+ if (!value) {
+ return;
+ }
+ let store = me.lookup('cdGrid').getStore();
+ let collection = store.getData().getSource() ?? store.getData();
+ let rec = collection.find('autogenerated', true);
+
+ let isWindows = (value ?? '').startsWith('w');
+ if (rec) {
+ rec.set('hidden', !isWindows);
+ rec.commit();
+ }
+ let prepareVirtio = me.lookup('prepareForVirtIO').getValue();
+ let defaultScsiHw = me.getView().vmConfig.scsihw ?? '__default__';
+ me.lookup('scsihw').setValue(prepareVirtio && isWindows ? 'virtio-scsi-single' : defaultScsiHw);
+
+ me.refreshGrids();
+ },
+
+ onPrepareVirtioChange: function(_cb, value) {
+ let me = this;
+
+ let scsihw = me.lookup('scsihw');
+ scsihw.suspendEvents();
+ scsihw.setValue(value ? 'virtio-scsi-single' : me.getView().vmConfig.scsihw);
+ scsihw.resumeEvents();
+
+ me.refreshGrids();
+ },
+
+ onScsiHwChange: function(_field, value) {
+ let me = this;
+ me.getView().vmConfig.scsihw = value;
+ },
+
+ onUniqueMACChange: function(_cb, value) {
+ let me = this;
+
+ me.getViewModel().set('uniqueMACAdresses', value);
+
+ me.lookup('netGrid').reconfigure();
+ },
+
+ renderMacAddress: function(value, metaData, record, rowIndex, colIndex, store, view) {
+ let me = this;
+ let vm = me.getViewModel();
+
+ return !vm.get('uniqueMACAdresses') && value ? value : 'auto';
},
control: {
@@ -180,11 +263,17 @@ Ext.define('PVE.window.GuestImport', {
'panel[reference=summaryTab]': {
activate: 'calculateConfig',
},
- 'proxmoxcheckbox[reference=mapSata]': {
- change: 'refreshDiskGrid',
+ 'proxmoxcheckbox[reference=prepareForVirtIO]': {
+ change: 'onPrepareVirtioChange',
},
'combobox[name=ostype]': {
- change: 'refreshDiskGrid',
+ change: 'onOSTypeChange',
+ },
+ 'pveScsiHwSelector': {
+ change: 'onScsiHwChange',
+ },
+ 'proxmoxcheckbox[name=uniqueMACs]': {
+ change: 'onUniqueMACChange',
},
},
},
@@ -194,7 +283,9 @@ Ext.define('PVE.window.GuestImport', {
coreCount: 1,
socketCount: 1,
liveImport: false,
- os: '',
+ os: 'l26',
+ maxCdDrives: false,
+ uniqueMACAdresses: false,
warnings: [],
},
@@ -205,541 +296,576 @@ Ext.define('PVE.window.GuestImport', {
+ get('warnings').map(w => `
${w}`).join('') + '',
liveImportNote: get => !get('liveImport') ? ''
: gettext('Note: If anything goes wrong during the live-import, new data written by the VM may be lost.'),
- isWindows: get => (get('os') ?? '').startsWith('win'),
+ isWindows: get => (get('os') ?? '').startsWith('w'),
},
},
width: 700,
bodyPadding: 0,
- items: [
- {
- xtype: 'tabpanel',
- defaults: {
- bodyPadding: 10,
- },
- items: [
- {
- title: gettext('General'),
- xtype: 'inputpanel',
- reference: 'mainInputPanel',
- onGetValues: function(values) {
- let me = this;
- let grid = me.up('pveGuestImportWindow');
-
- // from pveDiskStorageSelector
- let defaultStorage = values.hdstorage;
- let defaultFormat = values.diskformat;
- delete values.hdstorage;
- delete values.diskformat;
-
- let defaultBridge = values.defaultBridge;
- delete values.defaultBridge;
-
- let config = Ext.apply(grid.vmConfig, values);
-
- if (config.scsi0) {
- config.scsi0 = config.scsi0.replace('local:0,', 'local:0,format=qcow2,');
- }
+ items: [{
+ xtype: 'tabpanel',
+ defaults: {
+ bodyPadding: 10,
+ },
+ items: [
+ {
+ title: gettext('General'),
+ xtype: 'inputpanel',
+ reference: 'mainInputPanel',
+ onGetValues: function(values) {
+ let me = this;
+ let grid = me.up('pveGuestImportWindow');
+ let vm = grid.getViewModel();
+
+ // from pveDiskStorageSelector
+ let defaultStorage = values.hdstorage;
+ let defaultFormat = values.diskformat;
+ delete values.hdstorage;
+ delete values.diskformat;
+
+ let defaultBridge = values.defaultBridge;
+ delete values.defaultBridge;
+
+ let config = Ext.apply(grid.vmConfig, values);
+
+ if (config.scsi0) {
+ config.scsi0 = config.scsi0.replace('local:0,', 'local:0,format=qcow2,');
+ }
- let parsedBoot = PVE.Parser.parsePropertyString(config.boot ?? '');
- if (parsedBoot.order) {
- parsedBoot.order = parsedBoot.order.split(';');
- }
+ let parsedBoot = PVE.Parser.parsePropertyString(config.boot ?? '');
+ if (parsedBoot.order) {
+ parsedBoot.order = parsedBoot.order.split(';');
+ }
- grid.lookup('diskGrid').getStore().each((rec) => {
- if (!rec.data.enable) {
- return;
- }
- let id = grid.getController().mapDisk(rec.data.id);
- if (id !== rec.data.id && parsedBoot?.order) {
- let idx = parsedBoot.order.indexOf(rec.data.id);
- if (idx !== -1) {
- parsedBoot.order[idx] = id;
- }
- }
- let data = {
- ...rec.data,
- };
- delete data.enable;
- delete data.id;
- delete data.size;
- if (!data.file) {
- data.file = defaultStorage;
- data.format = defaultFormat;
- }
- data.file += ':0'; // for our special api format
- if (id === 'efidisk0') {
- delete data['import-from'];
+ grid.lookup('diskGrid').getStore().each((rec) => {
+ if (!rec.data.enable) {
+ return;
+ }
+ let id = grid.getController().mapDisk(rec.data.id);
+ if (id !== rec.data.id && parsedBoot?.order) {
+ let idx = parsedBoot.order.indexOf(rec.data.id);
+ if (idx !== -1) {
+ parsedBoot.order[idx] = id;
}
- config[id] = PVE.Parser.printQemuDrive(data);
- });
+ }
+ let data = {
+ ...rec.data,
+ };
+ delete data.enable;
+ delete data.id;
+ delete data.size;
+ if (!data.file) {
+ data.file = defaultStorage;
+ data.format = defaultFormat;
+ }
+ data.file += ':0'; // for our special api format
+ if (id === 'efidisk0') {
+ delete data['import-from'];
+ }
+ config[id] = PVE.Parser.printQemuDrive(data);
+ });
- if (parsedBoot.order) {
- parsedBoot.order = parsedBoot.order.join(';');
+ if (parsedBoot.order) {
+ parsedBoot.order = parsedBoot.order.join(';');
+ }
+ config.boot = PVE.Parser.printPropertyString(parsedBoot);
+
+ grid.lookup('netGrid').getStore().each((rec) => {
+ if (!rec.data.enable) {
+ return;
+ }
+ let id = rec.data.id;
+ let data = {
+ ...rec.data,
+ };
+ delete data.enable;
+ delete data.id;
+ if (!data.bridge) {
+ data.bridge = defaultBridge;
}
- config.boot = PVE.Parser.printPropertyString(parsedBoot);
+ if (vm.get('uniqueMACAdresses')) {
+ data.macaddr = undefined;
+ }
+ config[id] = PVE.Parser.printQemuNetwork(data);
+ });
- grid.lookup('netGrid').getStore().each((rec) => {
- if (!rec.data.enable) {
- return;
- }
- let id = rec.data.id;
- let data = {
- ...rec.data,
- };
- delete data.enable;
- delete data.id;
- if (!data.bridge) {
- data.bridge = defaultBridge;
- }
- config[id] = PVE.Parser.printQemuNetwork(data);
- });
+ grid.lookup('cdGrid').getStore().each((rec) => {
+ if (!rec.data.enable) {
+ return;
+ }
+ let id = rec.data.id;
+ let cd = {
+ media: 'cdrom',
+ file: rec.data.file ? rec.data.file : 'none',
+ };
+ config[id] = PVE.Parser.printPropertyString(cd);
+ });
- grid.lookup('cdGrid').getStore().each((rec) => {
- if (!rec.data.enable) {
- return;
- }
- let id = rec.data.id;
- let cd = {
- media: 'cdrom',
- file: rec.data.file ? rec.data.file : 'none',
- };
- config[id] = PVE.Parser.printPropertyString(cd);
- });
-
- if (grid.lookup('liveimport').getValue()) {
- config['live-restore'] = 1;
+ config.scsihw = grid.lookup('scsihw').getValue();
+
+ if (grid.lookup('liveimport').getValue()) {
+ config['live-restore'] = 1;
+ }
+
+ // remove __default__ values
+ for (const [key, value] of Object.entries(config)) {
+ if (value === '__default__') {
+ delete config[key];
}
+ }
- return config;
- },
+ return config;
+ },
- column1: [
- {
- xtype: 'pveGuestIDSelector',
- name: 'vmid',
- fieldLabel: 'VM',
- guestType: 'qemu',
- loadNextFreeID: true,
- },
- {
- xtype: 'proxmoxintegerfield',
- fieldLabel: gettext('Sockets'),
- name: 'sockets',
- reference: 'socketsField',
- value: 1,
- minValue: 1,
- maxValue: 4,
- allowBlank: true,
- bind: {
- value: '{socketCount}',
- },
+ column1: [
+ {
+ xtype: 'pveGuestIDSelector',
+ name: 'vmid',
+ fieldLabel: 'VM',
+ guestType: 'qemu',
+ loadNextFreeID: true,
+ },
+ {
+ xtype: 'proxmoxintegerfield',
+ fieldLabel: gettext('Sockets'),
+ name: 'sockets',
+ reference: 'socketsField',
+ value: 1,
+ minValue: 1,
+ maxValue: 128,
+ allowBlank: true,
+ bind: {
+ value: '{socketCount}',
},
- {
- xtype: 'proxmoxintegerfield',
- fieldLabel: gettext('Cores'),
- name: 'cores',
- reference: 'coresField',
- value: 1,
- minValue: 1,
- maxValue: 128,
- allowBlank: true,
- bind: {
- value: '{coreCount}',
- },
+ },
+ {
+ xtype: 'proxmoxintegerfield',
+ fieldLabel: gettext('Cores'),
+ name: 'cores',
+ reference: 'coresField',
+ value: 1,
+ minValue: 1,
+ maxValue: 1024,
+ allowBlank: true,
+ bind: {
+ value: '{coreCount}',
},
- {
- xtype: 'pveMemoryField',
- fieldLabel: gettext('Memory'),
- name: 'memory',
- reference: 'memoryField',
- value: 512,
- allowBlank: true,
+ },
+ {
+ xtype: 'pveMemoryField',
+ fieldLabel: gettext('Memory') + ' (MiB)',
+ name: 'memory',
+ reference: 'memoryField',
+ value: 512,
+ allowBlank: true,
+ },
+ { xtype: 'displayfield' }, // spacer
+ { xtype: 'displayfield' }, // spacer
+ {
+ xtype: 'pveDiskStorageSelector',
+ reference: 'defaultStorage',
+ storageLabel: gettext('Default Storage'),
+ storageContent: 'images',
+ autoSelect: true,
+ hideSize: true,
+ name: 'defaultStorage',
+ },
+ ],
+
+ column2: [
+ {
+ xtype: 'textfield',
+ fieldLabel: gettext('Name'),
+ name: 'name',
+ vtype: 'DnsName',
+ reference: 'nameField',
+ allowBlank: true,
+ },
+ {
+ xtype: 'CPUModelSelector',
+ name: 'cpu',
+ reference: 'cputype',
+ value: 'x86-64-v2-AES',
+ fieldLabel: gettext('CPU Type'),
+ },
+ {
+ xtype: 'displayfield',
+ fieldLabel: gettext('Total cores'),
+ name: 'totalcores',
+ isFormField: false,
+ bind: {
+ value: '{totalCoreCount}',
},
- {
- //spacer
- xtype: 'displayfield',
+ },
+ {
+ xtype: 'combobox',
+ submitValue: false,
+ name: 'osbase',
+ fieldLabel: gettext('OS Type'),
+ editable: false,
+ queryMode: 'local',
+ value: 'Linux',
+ store: Object.keys(PVE.Utils.kvm_ostypes),
+ },
+ {
+ xtype: 'combobox',
+ name: 'ostype',
+ reference: 'ostype',
+ fieldLabel: gettext('Version'),
+ value: 'l26',
+ allowBlank: false,
+ editable: false,
+ queryMode: 'local',
+ valueField: 'val',
+ displayField: 'desc',
+ bind: {
+ value: '{os}',
},
- {
- xtype: 'pveDiskStorageSelector',
- reference: 'defaultStorage',
- storageLabel: gettext('Default Storage'),
- storageContent: 'images',
- autoSelect: true,
- hideSize: true,
- name: 'defaultStorage',
+ store: {
+ fields: ['desc', 'val'],
+ data: PVE.Utils.kvm_ostypes.Linux,
},
- ],
-
- column2: [
- {
- xtype: 'textfield',
- fieldLabel: gettext('Name'),
- name: 'name',
- vtype: 'DnsName',
- reference: 'nameField',
- allowBlank: true,
+ },
+ { xtype: 'displayfield' }, // spacer
+ {
+ xtype: 'PVE.form.BridgeSelector',
+ reference: 'defaultBridge',
+ name: 'defaultBridge',
+ allowBlank: false,
+ fieldLabel: gettext('Default Bridge'),
+ },
+ ],
+
+ columnB: [
+ {
+ xtype: 'proxmoxcheckbox',
+ fieldLabel: gettext('Live Import'),
+ reference: 'liveimport',
+ isFormField: false,
+ boxLabelCls: 'pmx-hint black x-form-cb-label',
+ bind: {
+ value: '{liveImport}',
+ boxLabel: '{liveImportNote}',
},
- {
- xtype: 'CPUModelSelector',
- name: 'cpu',
- reference: 'cputype',
- value: 'x86-64-v2-AES',
- fieldLabel: gettext('Type'),
+ },
+ {
+ xtype: 'displayfield',
+ fieldLabel: gettext('Warnings'),
+ labelWidth: 200,
+ hidden: true,
+ bind: {
+ hidden: '{hideWarnings}',
},
- {
- xtype: 'displayfield',
- fieldLabel: gettext('Total cores'),
- name: 'totalcores',
- isFormField: false,
- bind: {
- value: '{totalCoreCount}',
- },
+ },
+ {
+ xtype: 'displayfield',
+ reference: 'warningText',
+ userCls: 'pmx-hint',
+ hidden: true,
+ bind: {
+ hidden: '{hideWarnings}',
+ value: '{warningsText}',
},
- {
- xtype: 'combobox',
- submitValue: false,
- name: 'osbase',
- fieldLabel: gettext('OS Type'),
- editable: false,
- queryMode: 'local',
- value: 'Linux',
- store: Object.keys(PVE.Utils.kvm_ostypes),
+ },
+ ],
+ },
+ {
+ title: gettext('Advanced'),
+ xtype: 'inputpanel',
+
+ // the first inputpanel handles all values, so prevent value leakage here
+ onGetValues: () => ({}),
+
+ columnT: [
+ {
+ xtype: 'displayfield',
+ fieldLabel: gettext('Disks'),
+ labelWidth: 200,
+ },
+ {
+ xtype: 'grid',
+ reference: 'diskGrid',
+ minHeight: 60,
+ maxHeight: 150,
+ store: {
+ data: [],
+ sorters: [
+ 'id',
+ ],
},
- {
- xtype: 'combobox',
- name: 'ostype',
- reference: 'ostype',
- fieldLabel: gettext('Version'),
- value: 'l26',
- allowBlank: false,
- editable: false,
- queryMode: 'local',
- valueField: 'val',
- displayField: 'desc',
- bind: {
- value: '{os}',
- },
- store: {
- fields: ['desc', 'val'],
- data: PVE.Utils.kvm_ostypes.Linux,
+ columns: [
+ {
+ xtype: 'checkcolumn',
+ header: gettext('Use'),
+ width: 50,
+ dataIndex: 'enable',
+ listeners: {
+ checkchange: function(_column, _rowIndex, _checked, record) {
+ record.commit();
+ },
+ },
},
- },
- {
- xtype: 'PVE.form.BridgeSelector',
- reference: 'defaultBridge',
- name: 'defaultBridge',
- allowBlank: false,
- fieldLabel: gettext('Default Bridge'),
- },
- ],
-
- columnB: [
- {
- xtype: 'proxmoxcheckbox',
- fieldLabel: gettext('Live Import'),
- reference: 'liveimport',
- isFormField: false,
- boxLabelCls: 'pmx-hint black x-form-cb-label',
- bind: {
- value: '{liveImport}',
- boxLabel: '{liveImportNote}',
+ {
+ text: gettext('Disk'),
+ dataIndex: 'id',
+ renderer: 'mapDisk',
},
- },
- {
- xtype: 'displayfield',
- fieldLabel: gettext('Warnings'),
- labelWidth: 200,
- hidden: true,
- bind: {
- hidden: '{hideWarnings}',
+ {
+ text: gettext('Source'),
+ dataIndex: 'import-from',
+ flex: 1,
+ renderer: function(value) {
+ return value.replace(/^.*\//, '');
+ },
},
- },
- {
- xtype: 'displayfield',
- reference: 'warningText',
- userCls: 'pmx-hint',
- hidden: true,
- bind: {
- hidden: '{hideWarnings}',
- value: '{warningsText}',
+ {
+ text: gettext('Size'),
+ dataIndex: 'size',
+ renderer: (value) => {
+ if (Ext.isNumeric(value)) {
+ return Proxmox.Utils.render_size(value);
+ }
+ return value ?? Proxmox.Utils.unknownText;
+ },
},
- },
- ],
- },
- {
- title: gettext('Advanced'),
- xtype: 'inputpanel',
-
- column1: [
- {
- xtype: 'proxmoxcheckbox',
- fieldLabel: gettext('Map SCSI to SATA'),
- labelWidth: 120,
- reference: 'mapSata',
- isFormField: false,
- hidden: true,
- disabled: true,
- bind: {
- hidden: '{!isWindows}',
- disabled: '{!isWindows}',
+ {
+ text: gettext('Storage'),
+ dataIndex: 'file',
+ xtype: 'widgetcolumn',
+ width: 150,
+ widget: {
+ xtype: 'pveStorageSelector',
+ isFormField: false,
+ autoSelect: false,
+ allowBlank: true,
+ emptyText: gettext('From Default'),
+ name: 'file',
+ storageContent: 'images',
+ },
+ onWidgetAttach: 'setNodename',
},
- autoEl: {
- tag: 'div',
- 'data-qtip': gettext('Useful when wanting to use VirtIO-SCSI'),
+ {
+ text: gettext('Format'),
+ dataIndex: 'format',
+ xtype: 'widgetcolumn',
+ width: 150,
+ widget: {
+ xtype: 'pveDiskFormatSelector',
+ name: 'format',
+ disabled: true,
+ isFormField: false,
+ matchFieldWidth: false,
+ },
},
+ ],
+ },
+ ],
+
+ column1: [
+ {
+ xtype: 'proxmoxcheckbox',
+ fieldLabel: gettext('Prepare for VirtIO-SCSI'),
+ labelWidth: 200,
+ reference: 'prepareForVirtIO',
+ name: 'prepareForVirtIO',
+ submitValue: false,
+ disabled: true,
+ bind: {
+ disabled: '{!isWindows}',
},
- ],
-
- columnB: [
- {
- xtype: 'displayfield',
- fieldLabel: gettext('Disks'),
- labelWidth: 200,
+ autoEl: {
+ tag: 'div',
+ 'data-qtip': gettext('Maps SCSI disks to SATA and changes the SCSI Controller. Useful for a quicker switch to VirtIO-SCSI attached disks'),
},
- {
- xtype: 'grid',
- reference: 'diskGrid',
- minHeight: 60,
- maxHeight: 150,
- store: {
- data: [],
- sorters: [
- 'id',
- ],
- },
- columns: [
- {
- xtype: 'checkcolumn',
- header: gettext('Use'),
- width: 50,
- dataIndex: 'enable',
- listeners: {
- checkchange: function(_column, _rowIndex, _checked, record) {
- record.commit();
- },
- },
- },
- {
- text: gettext('Disk'),
- dataIndex: 'id',
- renderer: 'mapDisk',
- },
- {
- text: gettext('Source'),
- dataIndex: 'import-from',
- flex: 1,
- renderer: function(value) {
- return value.replace(/^.*\//, '');
- },
- },
- {
- text: gettext('Size'),
- dataIndex: 'size',
- renderer: (value) => {
- if (Ext.isNumeric(value)) {
- return Proxmox.Utils.render_size(value);
- }
- return value ?? Proxmox.Utils.unknownText;
- },
- },
- {
- text: gettext('Storage'),
- dataIndex: 'file',
- xtype: 'widgetcolumn',
- width: 150,
- widget: {
- xtype: 'pveStorageSelector',
- isFormField: false,
- autoSelect: false,
- allowBlank: true,
- emptyText: gettext('From Default'),
- name: 'file',
- storageContent: 'images',
- },
- onWidgetAttach: 'setNodename',
- },
- {
- text: gettext('Format'),
- dataIndex: 'format',
- xtype: 'widgetcolumn',
- width: 150,
- widget: {
- xtype: 'pveDiskFormatSelector',
- name: 'format',
- disabled: true,
- isFormField: false,
- matchFieldWidth: false,
- },
+ },
+ ],
+
+ column2: [
+ {
+ xtype: 'pveScsiHwSelector',
+ reference: 'scsihw',
+ name: 'scsihw',
+ value: '__default__',
+ submitValue: false,
+ fieldLabel: gettext('SCSI Controller'),
+ },
+ ],
+
+ columnB: [
+ {
+ xtype: 'displayfield',
+ fieldLabel: gettext('CD/DVD Drives'),
+ labelWidth: 200,
+ },
+ {
+ xtype: 'grid',
+ reference: 'cdGrid',
+ minHeight: 60,
+ maxHeight: 150,
+ store: {
+ data: [],
+ sorters: [
+ 'id',
+ ],
+ filters: [
+ function(rec) {
+ return !rec.data.hidden;
},
],
},
- {
- xtype: 'displayfield',
- fieldLabel: gettext('CD/DVD Drives'),
- labelWidth: 200,
- style: {
- paddingTop: '10px',
- },
- },
- {
- xtype: 'grid',
- reference: 'cdGrid',
- minHeight: 60,
- maxHeight: 150,
- store: {
- data: [],
- sorters: [
- 'id',
- ],
- },
- columns: [
- {
- xtype: 'checkcolumn',
- header: gettext('Use'),
- width: 50,
- dataIndex: 'enable',
- listeners: {
- checkchange: function(_column, _rowIndex, _checked, record) {
- record.commit();
- },
+ columns: [
+ {
+ xtype: 'checkcolumn',
+ header: gettext('Use'),
+ width: 50,
+ dataIndex: 'enable',
+ listeners: {
+ checkchange: function(_column, _rowIndex, _checked, record) {
+ record.commit();
},
},
- {
- text: gettext('Slot'),
- dataIndex: 'id',
- sorted: true,
- },
- {
- text: gettext('Storage'),
- xtype: 'widgetcolumn',
- width: 150,
- widget: {
- xtype: 'pveStorageSelector',
- isFormField: false,
- autoSelect: false,
- allowBlank: true,
- emptyText: Proxmox.Utils.noneText,
- storageContent: 'iso',
- },
- onWidgetAttach: 'setNodename',
+ },
+ {
+ text: gettext('Slot'),
+ dataIndex: 'id',
+ sorted: true,
+ },
+ {
+ text: gettext('Storage'),
+ xtype: 'widgetcolumn',
+ width: 150,
+ widget: {
+ xtype: 'pveStorageSelector',
+ isFormField: false,
+ autoSelect: false,
+ allowBlank: true,
+ emptyText: Proxmox.Utils.noneText,
+ storageContent: 'iso',
},
- {
- text: gettext('ISO'),
- dataIndex: 'file',
- xtype: 'widgetcolumn',
- flex: 1,
- widget: {
- xtype: 'pveFileSelector',
- name: 'file',
- isFormField: false,
- allowBlank: true,
- emptyText: Proxmox.Utils.noneText,
- storageContent: 'iso',
- },
- onWidgetAttach: 'setNodename',
+ onWidgetAttach: 'setNodename',
+ },
+ {
+ text: gettext('ISO'),
+ dataIndex: 'file',
+ xtype: 'widgetcolumn',
+ flex: 1,
+ widget: {
+ xtype: 'pveFileSelector',
+ name: 'file',
+ isFormField: false,
+ allowBlank: true,
+ emptyText: Proxmox.Utils.noneText,
+ storageContent: 'iso',
},
- ],
- },
- {
- xtype: 'displayfield',
- fieldLabel: gettext('Network Interfaces'),
- labelWidth: 200,
- style: {
- paddingTop: '10px',
+ onWidgetAttach: 'setNodename',
},
+ ],
+ },
+ {
+ xtype: 'displayfield',
+ fieldLabel: gettext('Network Interfaces'),
+ labelWidth: 200,
+ style: {
+ paddingTop: '10px',
},
- {
- xtype: 'grid',
- minHeight: 58,
- maxHeight: 150,
- reference: 'netGrid',
- store: {
- data: [],
- sorters: [
- 'id',
- ],
- },
- columns: [
- {
- xtype: 'checkcolumn',
- header: gettext('Use'),
- width: 50,
- dataIndex: 'enable',
- listeners: {
- checkchange: function(_column, _rowIndex, _checked, record) {
- record.commit();
- },
+ },
+ {
+ xtype: 'grid',
+ minHeight: 58,
+ maxHeight: 150,
+ reference: 'netGrid',
+ store: {
+ data: [],
+ sorters: [
+ 'id',
+ ],
+ },
+ columns: [
+ {
+ xtype: 'checkcolumn',
+ header: gettext('Use'),
+ width: 50,
+ dataIndex: 'enable',
+ listeners: {
+ checkchange: function(_column, _rowIndex, _checked, record) {
+ record.commit();
},
},
- {
- text: gettext('ID'),
- dataIndex: 'id',
- },
- {
- text: gettext('MAC address'),
- flex: 1,
- dataIndex: 'macaddr',
- renderer: value => value ?? 'auto',
- },
- {
- text: gettext('Model'),
- flex: 1,
- dataIndex: 'model',
- xtype: 'widgetcolumn',
- widget: {
- xtype: 'pveNetworkCardSelector',
- name: 'model',
- isFormField: false,
- allowBlank: false,
- },
+ },
+ {
+ text: gettext('ID'),
+ dataIndex: 'id',
+ },
+ {
+ text: gettext('MAC address'),
+ flex: 1,
+ dataIndex: 'macaddr',
+ renderer: 'renderMacAddress',
+ },
+ {
+ text: gettext('Model'),
+ flex: 1,
+ dataIndex: 'model',
+ xtype: 'widgetcolumn',
+ widget: {
+ xtype: 'pveNetworkCardSelector',
+ name: 'model',
+ isFormField: false,
+ allowBlank: false,
},
- {
- text: gettext('Bridge'),
- dataIndex: 'bridge',
- xtype: 'widgetcolumn',
- flex: 1,
- widget: {
- xtype: 'PVE.form.BridgeSelector',
- name: 'bridge',
- isFormField: false,
- autoSelect: false,
- allowBlank: true,
- emptyText: gettext('From Default'),
- },
- onWidgetAttach: 'setNodename',
+ },
+ {
+ text: gettext('Bridge'),
+ dataIndex: 'bridge',
+ xtype: 'widgetcolumn',
+ flex: 1,
+ widget: {
+ xtype: 'PVE.form.BridgeSelector',
+ name: 'bridge',
+ isFormField: false,
+ autoSelect: false,
+ allowBlank: true,
+ emptyText: gettext('From Default'),
},
- ],
- },
- ],
- },
- {
- title: gettext('Resulting Config'),
- reference: 'summaryTab',
- items: [
- {
- xtype: 'grid',
- reference: 'summaryGrid',
- maxHeight: 400,
- scrollable: true,
- store: {
- model: 'KeyValue',
- sorters: [{
- property: 'key',
- direction: 'ASC',
- }],
+ onWidgetAttach: 'setNodename',
},
- columns: [
- { header: 'Key', width: 150, dataIndex: 'key' },
- { header: 'Value', flex: 1, dataIndex: 'value' },
- ],
+ ],
+ },
+ {
+ xtype: 'proxmoxcheckbox',
+ name: 'uniqueMACs',
+ boxLabel: gettext('Unique MAC addresses'),
+ uncheckedValue: false,
+ value: false,
+ },
+ ],
+ },
+ {
+ title: gettext('Resulting Config'),
+ reference: 'summaryTab',
+ items: [
+ {
+ xtype: 'grid',
+ reference: 'summaryGrid',
+ maxHeight: 400,
+ scrollable: true,
+ store: {
+ model: 'KeyValue',
+ sorters: [{
+ property: 'key',
+ direction: 'ASC',
+ }],
},
- ],
- },
- ],
- },
- ],
+ columns: [
+ { header: 'Key', width: 150, dataIndex: 'key' },
+ { header: 'Value', flex: 1, dataIndex: 'value' },
+ ],
+ },
+ ],
+ },
+ ],
+ }],
initComponent: function() {
let me = this;
@@ -770,6 +896,10 @@ Ext.define('PVE.window.GuestImport', {
'ovmf-with-lsi-unsupported': gettext("OVMF is built without LSI drivers, scsi hardware was set to '{1}'"),
'serial-port-socket-only': gettext("Serial socket '{0}' will be mapped to a socket"),
'guest-is-running': gettext('Virtual guest seems to be running on source host. Import might fail or have inconsistent state!'),
+ 'efi-state-lost': Ext.String.format(
+ gettext('EFI state cannot be imported, you may need to reconfigure the boot order (see {0})'),
+ 'OVMF/UEFI Boot Entries',
+ ),
};
let message = warningsCatalogue[w.type];
if (!w.type || !message) {
@@ -814,22 +944,41 @@ Ext.define('PVE.window.GuestImport', {
}
cdroms.push({
enable: true,
+ hidden: false,
id,
});
delete me.vmConfig[id];
}
+
me.lookup('diskGrid').getStore().setData(disks);
me.lookup('netGrid').getStore().setData(nets);
me.lookup('cdGrid').getStore().setData(cdroms);
+ let additionalCdIdx = me.getController().calculateAdditionalCDIdx();
+ if (additionalCdIdx === '') {
+ me.getViewModel().set('maxCdDrives', true);
+ } else if (cdroms.length === 0) {
+ me.additionalCdIdx = additionalCdIdx;
+ me.lookup('cdGrid').getStore().add({
+ enable: true,
+ hidden: !(me.vmConfig.ostype ?? '').startsWith('w'),
+ id: additionalCdIdx,
+ autogenerated: true,
+ });
+ }
+
me.getViewModel().set('warnings', data.warnings.map(w => renderWarning(w)));
let osinfo = PVE.Utils.get_kvm_osinfo(me.vmConfig.ostype ?? '');
+ let prepareForVirtIO = (me.vmConfig.ostype ?? '').startsWith('w') && (me.vmConfig.bios ?? '').indexOf('ovmf') !== -1;
me.setValues({
osbase: osinfo.base,
...me.vmConfig,
});
+
+
+ me.lookup('prepareForVirtIO').setValue(prepareForVirtIO);
},
});
},