initComponent: function() {
var me = this;
- var i, confid;
- var nodename = me.pveSelNode.data.node;
+ const { node: nodename, vmid } = me.pveSelNode.data;
if (!nodename) {
throw "no node name specified";
- }
-
- var vmid = me.pveSelNode.data.vmid;
- if (!vmid) {
+ } else if (!vmid) {
throw "no VM ID specified";
}
- var caps = Ext.state.Manager.get('GuiCap');
- var diskCap = caps.vms['VM.Config.Disk'];
+ const caps = Ext.state.Manager.get('GuiCap');
+ const diskCap = caps.vms['VM.Config.Disk'];
+ const cdromCap = caps.vms['VM.Config.CDROM'];
- var rows = {
+ let isCloudInitKey = v => v && v.toString().match(/vm-.*-cloudinit/);
+
+ const nodeInfo = PVE.data.ResourceStore.getNodes().find(node => node.node === nodename);
+ let processorEditor = {
+ xtype: 'pveQemuProcessorEdit',
+ cgroupMode: nodeInfo['cgroup-mode'],
+ };
+
+ let rows = {
memory: {
header: gettext('Memory'),
editor: caps.vms['VM.Config.Memory'] ? 'PVE.qemu.MemoryEdit' : undefined,
header: gettext('Processors'),
never_delete: true,
editor: caps.vms['VM.Config.CPU'] || caps.vms['VM.Config.HWType']
- ? 'PVE.qemu.ProcessorEdit' : undefined,
- tdCls: 'pve-itype-icon-processor',
+ ? processorEditor : undefined,
+ tdCls: 'pve-itype-icon-cpu',
group: 3,
defaultValue: '1',
multiKey: ['sockets', 'cpu', 'cores', 'numa', 'vcpus', 'cpulimit', 'cpuunits'],
var cpulimit = me.getObjectValue('cpulimit', undefined, pending);
var cpuunits = me.getObjectValue('cpuunits', undefined, pending);
- var res = Ext.String.format('{0} ({1} sockets, {2} cores)',
- sockets*cores, sockets, cores);
+ let res = Ext.String.format(
+ '{0} ({1} sockets, {2} cores)', sockets * cores, sockets, cores);
if (model) {
res += ' [' + model + ']';
}
-
if (numa) {
res += ' [numa=' + numa +']';
}
-
if (vcpus) {
res += ' [vcpus=' + vcpus +']';
}
-
if (cpulimit) {
res += ' [cpulimit=' + cpulimit +']';
}
-
if (cpuunits) {
res += ' [cpuunits=' + cpuunits +']';
}
},
machine: {
header: gettext('Machine'),
- editor: caps.vms['VM.Config.HWType'] ? {
- xtype: 'proxmoxWindowEdit',
- subject: gettext('Machine'),
- width: 350,
- items: [{
- xtype: 'proxmoxKVComboBox',
- name: 'machine',
- value: '__default__',
- fieldLabel: gettext('Machine'),
- comboItems: [
- ['__default__', PVE.Utils.render_qemu_machine('')],
- ['q35', 'q35'],
- ],
- }]
-} : undefined,
+ editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.MachineEdit' : undefined,
iconCls: 'cogs',
never_delete: true,
group: 6,
defaultValue: '',
- renderer: PVE.Utils.render_qemu_machine,
+ renderer: function(value, metaData, record, rowIndex, colIndex, store, pending) {
+ let ostype = me.getObjectValue('ostype', undefined, pending);
+ if (PVE.Utils.is_windows(ostype) &&
+ (!value || value === 'pc' || value === 'q35')) {
+ return value === 'q35' ? 'pc-q35-5.1' : 'pc-i440fx-5.1';
+ }
+ return PVE.Utils.render_qemu_machine(value);
+ },
},
scsihw: {
header: gettext('SCSI Controller'),
shares: {
visible: false,
},
+ ostype: {
+ visible: false,
+ },
};
PVE.Utils.forEachBus(undefined, function(type, id) {
- var confid = type + id;
+ let confid = type + id;
rows[confid] = {
group: 10,
iconCls: 'hdd-o',
editor: 'PVE.qemu.HDEdit',
- never_delete: !caps.vms['VM.Config.Disk'],
isOnStorageBus: true,
header: gettext('Hard Disk') + ' (' + confid +')',
cdheader: gettext('CD/DVD Drive') + ' (' + confid +')',
cloudheader: gettext('CloudInit Drive') + ' (' + confid + ')',
};
});
- for (i = 0; i < PVE.Utils.hardware_counts.net; i++) {
- confid = "net" + i.toString();
+ for (let i = 0; i < PVE.Utils.hardware_counts.net; i++) {
+ let confid = "net" + i.toString();
rows[confid] = {
group: 15,
order: i,
never_delete: !caps.vms['VM.Config.Disk'],
header: gettext('EFI Disk'),
};
- for (i = 0; i < PVE.Utils.hardware_counts.usb; i++) {
- confid = "usb" + i.toString();
+ rows.tpmstate0 = {
+ group: 22,
+ iconCls: 'hdd-o',
+ editor: null,
+ never_delete: !caps.vms['VM.Config.Disk'],
+ header: gettext('TPM State'),
+ };
+ for (let i = 0; i < PVE.Utils.hardware_counts.usb; i++) {
+ let confid = "usb" + i.toString();
rows[confid] = {
group: 25,
order: i,
iconCls: 'usb',
- editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.USBEdit' : undefined,
- never_delete: !caps.nodes['Sys.Console'],
+ editor: caps.nodes['Sys.Console'] || caps.mapping['Mapping.Use'] ? 'PVE.qemu.USBEdit' : undefined,
+ never_delete: !caps.nodes['Sys.Console'] && !caps.mapping['Mapping.Use'],
header: gettext('USB Device') + ' (' + confid + ')',
};
}
- for (i = 0; i < PVE.Utils.hardware_counts.hostpci; i++) {
- confid = "hostpci" + i.toString();
+ for (let i = 0; i < PVE.Utils.hardware_counts.hostpci; i++) {
+ let confid = "hostpci" + i.toString();
rows[confid] = {
group: 30,
order: i,
tdCls: 'pve-itype-icon-pci',
- never_delete: !caps.nodes['Sys.Console'],
- editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.PCIEdit' : undefined,
+ never_delete: !caps.nodes['Sys.Console'] && !caps.mapping['Mapping.Use'],
+ editor: caps.nodes['Sys.Console'] || caps.mapping['Mapping.Use'] ? 'PVE.qemu.PCIEdit' : undefined,
header: gettext('PCI Device') + ' (' + confid + ')',
};
}
- for (i = 0; i < PVE.Utils.hardware_counts.serial; i++) {
- confid = "serial" + i.toString();
+ for (let i = 0; i < PVE.Utils.hardware_counts.serial; i++) {
+ let confid = "serial" + i.toString();
rows[confid] = {
group: 35,
order: i,
never_delete: !caps.vms['VM.Config.HWType'],
header: gettext('Audio Device'),
};
- for (i = 0; i < 256; i++) {
+ for (let i = 0; i < 256; i++) {
rows["unused" + i.toString()] = {
group: 99,
order: i,
}
};
- var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
+ let baseurl = `nodes/${nodename}/qemu/${vmid}/config`;
- var sm = Ext.create('Ext.selection.RowModel', {});
+ let sm = Ext.create('Ext.selection.RowModel', {});
- var run_editor = function() {
- var rec = sm.getSelection()[0];
- if (!rec) {
- return;
- }
-
- var rowdef = rows[rec.data.key];
- if (!rowdef.editor) {
+ let run_editor = function() {
+ let rec = sm.getSelection()[0];
+ if (!rec || !rows[rec.data.key]?.editor) {
return;
}
+ let rowdef = rows[rec.data.key];
+ let editor = rowdef.editor;
- var editor = rowdef.editor;
if (rowdef.isOnStorageBus) {
- var value = me.getObjectValue(rec.data.key, '', true);
- if (value.match(/vm-.*-cloudinit/)) {
+ let value = me.getObjectValue(rec.data.key, '', true);
+ if (isCloudInitKey(value)) {
return;
} else if (value.match(/media=cdrom/)) {
editor = 'PVE.qemu.CDEdit';
}
}
- var win;
+ let commonOpts = {
+ autoShow: true,
+ pveSelNode: me.pveSelNode,
+ confid: rec.data.key,
+ url: `/api2/extjs/${baseurl}`,
+ listeners: {
+ destroy: () => me.reload(),
+ },
+ };
if (Ext.isString(editor)) {
- win = Ext.create(editor, {
- pveSelNode: me.pveSelNode,
- confid: rec.data.key,
- url: '/api2/extjs/' + baseurl,
- });
+ Ext.create(editor, commonOpts);
} else {
- var config = Ext.apply({
- pveSelNode: me.pveSelNode,
- confid: rec.data.key,
- url: '/api2/extjs/' + baseurl,
- }, rowdef.editor);
- win = Ext.createWidget(rowdef.editor.xtype, config);
+ let win = Ext.createWidget(rowdef.editor.xtype, Ext.apply(commonOpts, rowdef.editor));
win.load();
}
-
- win.show();
- win.on('destroy', me.reload, me);
- };
-
- var run_resize = function() {
- var rec = sm.getSelection()[0];
- if (!rec) {
- return;
- }
-
- var win = Ext.create('PVE.window.HDResize', {
- disk: rec.data.key,
- nodename: nodename,
- vmid: vmid,
- });
-
- win.show();
-
- win.on('destroy', me.reload, me);
};
- var run_move = function() {
- var rec = sm.getSelection()[0];
- if (!rec) {
- return;
- }
-
- var win = Ext.create('PVE.window.HDMove', {
- disk: rec.data.key,
- nodename: nodename,
- vmid: vmid,
- });
-
- win.show();
-
- win.on('destroy', me.reload, me);
- };
-
- var edit_btn = new Proxmox.button.Button({
+ let edit_btn = new Proxmox.button.Button({
text: gettext('Edit'),
selModel: sm,
disabled: true,
handler: run_editor,
- });
+ });
- var resize_btn = new Proxmox.button.Button({
- text: gettext('Resize disk'),
+ let move_menuitem = new Ext.menu.Item({
+ text: gettext('Move Storage'),
+ tooltip: gettext('Move disk to another storage'),
+ iconCls: 'fa fa-database',
selModel: sm,
- disabled: true,
- handler: run_resize,
+ handler: () => {
+ let rec = sm.getSelection()[0];
+ if (!rec) {
+ return;
+ }
+ Ext.create('PVE.window.HDMove', {
+ autoShow: true,
+ disk: rec.data.key,
+ nodename: nodename,
+ vmid: vmid,
+ type: 'qemu',
+ listeners: {
+ destroy: () => me.reload(),
+ },
+ });
+ },
+ });
+
+ let reassign_menuitem = new Ext.menu.Item({
+ text: gettext('Reassign Owner'),
+ tooltip: gettext('Reassign disk to another VM'),
+ iconCls: 'fa fa-desktop',
+ selModel: sm,
+ handler: () => {
+ let rec = sm.getSelection()[0];
+ if (!rec) {
+ return;
+ }
+
+ Ext.create('PVE.window.GuestDiskReassign', {
+ autoShow: true,
+ disk: rec.data.key,
+ nodename: nodename,
+ vmid: vmid,
+ type: 'qemu',
+ listeners: {
+ destroy: () => me.reload(),
+ },
+ });
+ },
});
- var move_btn = new Proxmox.button.Button({
- text: gettext('Move disk'),
+ let resize_menuitem = new Ext.menu.Item({
+ text: gettext('Resize'),
+ iconCls: 'fa fa-plus',
selModel: sm,
+ handler: () => {
+ let rec = sm.getSelection()[0];
+ if (!rec) {
+ return;
+ }
+ Ext.create('PVE.window.HDResize', {
+ autoShow: true,
+ disk: rec.data.key,
+ nodename: nodename,
+ vmid: vmid,
+ listeners: {
+ destroy: () => me.reload(),
+ },
+ });
+ },
+ });
+
+ let diskaction_btn = new Proxmox.button.Button({
+ text: gettext('Disk Action'),
disabled: true,
- handler: run_move,
+ menu: {
+ items: [
+ move_menuitem,
+ reassign_menuitem,
+ resize_menuitem,
+ ],
+ },
});
- var remove_btn = new Proxmox.button.Button({
+
+ let remove_btn = new Proxmox.button.Button({
text: gettext('Remove'),
defaultText: gettext('Remove'),
altText: gettext('Detach'),
dangerous: true,
RESTMethod: 'PUT',
confirmMsg: function(rec) {
- var warn = gettext('Are you sure you want to remove entry {0}');
+ let warn = gettext('Are you sure you want to remove entry {0}');
if (this.text === this.altText) {
warn = gettext('Are you sure you want to detach entry {0}');
}
- var key = rec.data.key;
- var entry = rows[key];
+ let rendered = me.renderKey(rec.data.key, {}, rec);
+ let msg = Ext.String.format(warn, `'${rendered}'`);
- var rendered = me.renderKey(key, {}, rec);
- var msg = Ext.String.format(warn, "'" + rendered + "'");
-
- if (entry.del_extra_msg) {
- msg += '<br>' + entry.del_extra_msg;
+ if (rows[rec.data.key].del_extra_msg) {
+ msg += '<br>' + rows[rec.data.key].del_extra_msg;
}
-
return msg;
},
- handler: function(b, e, rec) {
+ handler: function(btn, e, rec) {
Proxmox.Utils.API2Request({
url: '/api2/extjs/' + baseurl,
waitMsgTarget: me,
- method: b.RESTMethod,
+ method: btn.RESTMethod,
params: {
'delete': rec.data.key,
},
callback: () => me.reload(),
- failure: function(response, opts) {
- Ext.Msg.alert('Error', response.htmlStatus);
- },
+ failure: response => Ext.Msg.alert('Error', response.htmlStatus),
success: function(response, options) {
- if (b.RESTMethod === 'POST') {
- var upid = response.result.data;
- var win = Ext.create('Proxmox.window.TaskProgress', {
- upid: upid,
+ if (btn.RESTMethod === 'POST') {
+ Ext.create('Proxmox.window.TaskProgress', {
+ autoShow: true,
+ upid: response.result.data,
listeners: {
destroy: () => me.reload(),
},
});
- win.show();
}
},
});
},
listeners: {
render: function(btn) {
- // hack: calculate an optimal button width on first display
- // to prevent the whole toolbar to move when we switch
- // between the "Remove" and "Detach" labels
+ // hack: calculate the max button width on first display to prevent the whole
+ // toolbar to move when we switch between the "Remove" and "Detach" labels
var def = btn.getSize().width;
btn.setText(btn.altText);
},
});
- var revert_btn = new PVE.button.PendingRevert({
+ let revert_btn = new PVE.button.PendingRevert({
apiurl: '/api2/extjs/' + baseurl,
});
- var efidisk_menuitem = Ext.create('Ext.menu.Item', {
+ let efidisk_menuitem = Ext.create('Ext.menu.Item', {
text: gettext('EFI Disk'),
iconCls: 'fa fa-fw fa-hdd-o black',
disabled: !caps.vms['VM.Config.Disk'],
handler: function() {
- let bios = me.rstore.getData().map.bios;
- let usesEFI = bios && (bios.data.value === 'ovmf' || bios.data.pending === 'ovmf');
+ let { data: bios } = me.rstore.getData().map.bios || {};
- var win = Ext.create('PVE.qemu.EFIDiskEdit', {
+ Ext.create('PVE.qemu.EFIDiskEdit', {
+ autoShow: true,
url: '/api2/extjs/' + baseurl,
pveSelNode: me.pveSelNode,
- usesEFI: usesEFI,
+ usesEFI: bios?.value === 'ovmf' || bios?.pending === 'ovmf',
+ listeners: {
+ destroy: () => me.reload(),
+ },
});
- win.on('destroy', me.reload, me);
- win.show();
},
});
let counts = {};
let isAtLimit = (type) => counts[type] >= PVE.Utils.hardware_counts[type];
+ let isAtUsbLimit = () => {
+ let ostype = me.getObjectValue('ostype');
+ let machine = me.getObjectValue('machine');
+ return counts.usb >= PVE.Utils.get_max_usb_count(ostype, machine);
+ };
+
+ let set_button_status = function() {
+ let selection_model = me.getSelectionModel();
+ let rec = selection_model.getSelection()[0];
- var set_button_status = function() {
- var sm = me.getSelectionModel();
- var rec = sm.getSelection()[0];
-
- // en/disable hardwarebuttons
- counts = {};
- var hasCloudInit = false;
- me.rstore.getData().items.forEach(function(item) {
- if (!hasCloudInit && (
- /vm-.*-cloudinit/.test(item.data.value) ||
- /vm-.*-cloudinit/.test(item.data.pending)
- )) {
+ counts = {}; // en/disable hardwarebuttons
+ let hasCloudInit = false;
+ me.rstore.getData().items.forEach(function({ id, data }) {
+ if (!hasCloudInit && (isCloudInitKey(data.value) || isCloudInitKey(data.pending))) {
hasCloudInit = true;
return;
}
- let match = item.id.match(/^([^\d]+)\d+$/);
- let type;
+ let match = id.match(/^([^\d]+)\d+$/);
if (match && PVE.Utils.hardware_counts[match[1]] !== undefined) {
- type = match[1];
- } else {
- return;
+ let type = match[1];
+ counts[type] = (counts[type] || 0) + 1;
}
-
- counts[type] = (counts[type] || 0) + 1;
});
// heuristic only for disabling some stuff, the backend has the final word.
- var noSysConsolePerm = !caps.nodes['Sys.Console'];
- var noVMConfigHWTypePerm = !caps.vms['VM.Config.HWType'];
- var noVMConfigNetPerm = !caps.vms['VM.Config.Network'];
-
-
- me.down('#addusb').setDisabled(noSysConsolePerm || isAtLimit('usb'));
- me.down('#addpci').setDisabled(noSysConsolePerm || isAtLimit('hostpci'));
- me.down('#addaudio').setDisabled(noVMConfigHWTypePerm || isAtLimit('audio'));
- me.down('#addserial').setDisabled(noVMConfigHWTypePerm || isAtLimit('serial'));
- me.down('#addnet').setDisabled(noVMConfigNetPerm || isAtLimit('net'));
- me.down('#addrng').setDisabled(noSysConsolePerm || isAtLimit('rng'));
- efidisk_menuitem.setDisabled(isAtLimit('efidisk'));
- me.down('#addci').setDisabled(noSysConsolePerm || hasCloudInit);
+ const noSysConsolePerm = !caps.nodes['Sys.Console'];
+ const noHWPerm = !caps.nodes['Sys.Console'] && !caps.mapping['Mapping.Use'];
+ const noVMConfigHWTypePerm = !caps.vms['VM.Config.HWType'];
+ const noVMConfigNetPerm = !caps.vms['VM.Config.Network'];
+ const noVMConfigDiskPerm = !caps.vms['VM.Config.Disk'];
+ const noVMConfigCDROMPerm = !caps.vms['VM.Config.CDROM'];
+ const noVMConfigCloudinitPerm = !caps.vms['VM.Config.Cloudinit'];
+
+ me.down('#addUsb').setDisabled(noHWPerm || isAtUsbLimit());
+ me.down('#addPci').setDisabled(noHWPerm || isAtLimit('hostpci'));
+ me.down('#addAudio').setDisabled(noVMConfigHWTypePerm || isAtLimit('audio'));
+ me.down('#addSerial').setDisabled(noVMConfigHWTypePerm || isAtLimit('serial'));
+ me.down('#addNet').setDisabled(noVMConfigNetPerm || isAtLimit('net'));
+ me.down('#addRng').setDisabled(noSysConsolePerm || isAtLimit('rng'));
+ efidisk_menuitem.setDisabled(noVMConfigDiskPerm || isAtLimit('efidisk'));
+ me.down('#addTpmState').setDisabled(noSysConsolePerm || isAtLimit('tpmstate'));
+ me.down('#addCloudinitDrive').setDisabled(noVMConfigCDROMPerm || noVMConfigCloudinitPerm || hasCloudInit);
if (!rec) {
remove_btn.disable();
edit_btn.disable();
- resize_btn.disable();
- move_btn.disable();
+ diskaction_btn.disable();
revert_btn.disable();
return;
}
- var key = rec.data.key;
- var value = rec.data.value;
- var rowdef = rows[key];
+ const { key, value } = rec.data;
+ const row = rows[key];
- var pending = rec.data.delete || me.hasPendingChanges(key);
- var isCDRom = value && !!value.toString().match(/media=cdrom/);
- var isUnusedDisk = key.match(/^unused\d+/);
- var isUsedDisk = !isUnusedDisk && rowdef.isOnStorageBus && !isCDRom;
+ const deleted = !!rec.data.delete;
+ const pending = deleted || me.hasPendingChanges(key);
- var isCloudInit = value && value.toString().match(/vm-.*-cloudinit/);
+ const isCloudInit = isCloudInitKey(value);
+ const isCDRom = value && !!value.toString().match(/media=cdrom/);
- var isEfi = key === 'efidisk0';
+ const isUnusedDisk = key.match(/^unused\d+/);
+ const isUsedDisk = !isUnusedDisk && row.isOnStorageBus && !isCDRom;
+ const isDisk = isUnusedDisk || isUsedDisk;
+ const isEfi = key === 'efidisk0';
+ const tpmMoveable = key === 'tpmstate0' && !me.pveSelNode.data.running;
+
+ let cannotDelete = deleted || row.never_delete;
+ cannotDelete ||= isCDRom && !cdromCap;
+ cannotDelete ||= isDisk && !diskCap;
+ cannotDelete ||= isCloudInit && noVMConfigCloudinitPerm;
+ remove_btn.setDisabled(cannotDelete);
- remove_btn.setDisabled(rec.data.delete || rowdef.never_delete === true || isUnusedDisk && !diskCap);
remove_btn.setText(isUsedDisk && !isCloudInit ? remove_btn.altText : remove_btn.defaultText);
remove_btn.RESTMethod = isUnusedDisk ? 'POST':'PUT';
- edit_btn.setDisabled(rec.data.delete || !rowdef.editor || isCloudInit || !isCDRom && !diskCap);
-
- resize_btn.setDisabled(pending || !isUsedDisk || !diskCap);
+ edit_btn.setDisabled(
+ deleted || !row.editor || isCloudInit || (isCDRom && !cdromCap) || (isDisk && !diskCap));
- move_btn.setDisabled(pending || !(isUsedDisk || isEfi) || !diskCap);
+ diskaction_btn.setDisabled(
+ pending ||
+ !diskCap ||
+ isCloudInit ||
+ !(isDisk || isEfi || tpmMoveable),
+ );
+ reassign_menuitem.setDisabled(pending || (isEfi || tpmMoveable));
+ resize_menuitem.setDisabled(pending || !isUsedDisk);
revert_btn.setDisabled(!pending);
};
+ let editorFactory = (classPath, extraOptions) => {
+ extraOptions = extraOptions || {};
+ return () => Ext.create(`PVE.qemu.${classPath}`, {
+ autoShow: true,
+ url: `/api2/extjs/${baseurl}`,
+ pveSelNode: me.pveSelNode,
+ listeners: {
+ destroy: () => me.reload(),
+ },
+ isAdd: true,
+ isCreate: true,
+ ...extraOptions,
+ });
+ };
+
Ext.apply(me, {
- url: '/api2/json/' + 'nodes/' + nodename + '/qemu/' + vmid + '/pending',
+ url: `/api2/json/nodes/${nodename}/qemu/${vmid}/pending`,
interval: 5000,
selModel: sm,
run_editor: run_editor,
text: gettext('Hard Disk'),
iconCls: 'fa fa-fw fa-hdd-o black',
disabled: !caps.vms['VM.Config.Disk'],
- handler: function() {
- var win = Ext.create('PVE.qemu.HDEdit', {
- url: '/api2/extjs/' + baseurl,
- pveSelNode: me.pveSelNode,
- });
- win.on('destroy', me.reload, me);
- win.show();
- },
+ handler: editorFactory('HDEdit'),
},
{
text: gettext('CD/DVD Drive'),
iconCls: 'pve-itype-icon-cdrom',
- disabled: !caps.vms['VM.Config.Disk'],
- handler: function() {
- var win = Ext.create('PVE.qemu.CDEdit', {
- url: '/api2/extjs/' + baseurl,
- pveSelNode: me.pveSelNode,
- });
- win.on('destroy', me.reload, me);
- win.show();
- },
+ disabled: !caps.vms['VM.Config.CDROM'],
+ handler: editorFactory('CDEdit'),
},
{
text: gettext('Network Device'),
- itemId: 'addnet',
+ itemId: 'addNet',
iconCls: 'fa fa-fw fa-exchange black',
disabled: !caps.vms['VM.Config.Network'],
- handler: function() {
- var win = Ext.create('PVE.qemu.NetworkEdit', {
- url: '/api2/extjs/' + baseurl,
- pveSelNode: me.pveSelNode,
- isCreate: true,
- });
- win.on('destroy', me.reload, me);
- win.show();
- },
+ handler: editorFactory('NetworkEdit'),
},
efidisk_menuitem,
+ {
+ text: gettext('TPM State'),
+ itemId: 'addTpmState',
+ iconCls: 'fa fa-fw fa-hdd-o black',
+ disabled: !caps.vms['VM.Config.Disk'],
+ handler: editorFactory('TPMDiskEdit'),
+ },
{
text: gettext('USB Device'),
- itemId: 'addusb',
+ itemId: 'addUsb',
iconCls: 'fa fa-fw fa-usb black',
- disabled: !caps.nodes['Sys.Console'],
- handler: function() {
- var win = Ext.create('PVE.qemu.USBEdit', {
- url: '/api2/extjs/' + baseurl,
- pveSelNode: me.pveSelNode,
- });
- win.on('destroy', me.reload, me);
- win.show();
- },
+ disabled: !caps.nodes['Sys.Console'] && !caps.mapping['Mapping.Use'],
+ handler: editorFactory('USBEdit'),
},
{
text: gettext('PCI Device'),
- itemId: 'addpci',
+ itemId: 'addPci',
iconCls: 'pve-itype-icon-pci',
- disabled: !caps.nodes['Sys.Console'],
- handler: function() {
- var win = Ext.create('PVE.qemu.PCIEdit', {
- url: '/api2/extjs/' + baseurl,
- pveSelNode: me.pveSelNode,
- });
- win.on('destroy', me.reload, me);
- win.show();
- },
+ disabled: !caps.nodes['Sys.Console'] && !caps.mapping['Mapping.Use'],
+ handler: editorFactory('PCIEdit'),
},
{
text: gettext('Serial Port'),
- itemId: 'addserial',
+ itemId: 'addSerial',
iconCls: 'pve-itype-icon-serial',
disabled: !caps.vms['VM.Config.Options'],
- handler: function() {
- var win = Ext.create('PVE.qemu.SerialEdit', {
- url: '/api2/extjs/' + baseurl,
- });
- win.on('destroy', me.reload, me);
- win.show();
- },
+ handler: editorFactory('SerialEdit'),
},
{
text: gettext('CloudInit Drive'),
- itemId: 'addci',
+ itemId: 'addCloudinitDrive',
iconCls: 'fa fa-fw fa-cloud black',
- disabled: !caps.nodes['Sys.Console'],
- handler: function() {
- var win = Ext.create('PVE.qemu.CIDriveEdit', {
- url: '/api2/extjs/' + baseurl,
- pveSelNode: me.pveSelNode,
- });
- win.on('destroy', me.reload, me);
- win.show();
- },
+ disabled: !caps.vms['VM.Config.CDROM'] || !caps.vms['VM.Config.Cloudinit'],
+ handler: editorFactory('CIDriveEdit'),
},
{
text: gettext('Audio Device'),
- itemId: 'addaudio',
+ itemId: 'addAudio',
iconCls: 'fa fa-fw fa-volume-up black',
disabled: !caps.vms['VM.Config.HWType'],
- handler: function() {
- var win = Ext.create('PVE.qemu.AudioEdit', {
- url: '/api2/extjs/' + baseurl,
- isCreate: true,
- isAdd: true,
- });
- win.on('destroy', me.reload, me);
- win.show();
- },
+ handler: editorFactory('AudioEdit'),
},
{
text: gettext("VirtIO RNG"),
- itemId: 'addrng',
+ itemId: 'addRng',
iconCls: 'pve-itype-icon-die',
disabled: !caps.nodes['Sys.Console'],
- handler: function() {
- var win = Ext.create('PVE.qemu.RNGEdit', {
- url: '/api2/extjs/' + baseurl,
- isCreate: true,
- isAdd: true,
- });
- win.on('destroy', me.reload, me);
- win.show();
- },
+ handler: editorFactory('RNGEdit'),
},
],
}),
},
remove_btn,
edit_btn,
- resize_btn,
- move_btn,
+ diskaction_btn,
revert_btn,
],
rows: rows,