pve-manager/www/manager6/qemu/HardwareView.js
Emmanuel Kasper 3c813f7416 Enlarge Object Grid first column default size
The framework value of 100 is not enough for many of our description
fields.
Setting this at the parent component level allow to remove
the end component setting.
2016-05-17 11:33:34 +02:00

538 lines
13 KiB
JavaScript

// fixme: howto avoid jslint type confusion?
/*jslint confusion: true */
Ext.define('PVE.qemu.HardwareView', {
extend: 'PVE.grid.PendingObjectGrid',
alias: ['widget.PVE.qemu.HardwareView'],
renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
var me = this;
var rows = me.rows;
var rowdef = rows[key] || {};
metaData.tdAttr = "valign=middle";
if (rowdef.tdCls) {
metaData.tdCls = rowdef.tdCls;
if (rowdef.tdCls == 'pve-itype-icon-storage') {
var value = me.getObjectValue(key, '', true);
if (value.match(/media=cdrom/)) {
metaData.tdCls = 'pve-itype-icon-cdrom';
return rowdef.cdheader;
}
}
}
return rowdef.header || key;
},
initComponent : function() {
var me = this;
var i, confid;
var nodename = me.pveSelNode.data.node;
if (!nodename) {
throw "no node name specified";
}
var vmid = me.pveSelNode.data.vmid;
if (!vmid) {
throw "no VM ID specified";
}
var caps = Ext.state.Manager.get('GuiCap');
var rows = {
memory: {
header: gettext('Memory'),
editor: caps.vms['VM.Config.Memory'] ? 'PVE.qemu.MemoryEdit' : undefined,
never_delete: true,
defaultValue: 512,
tdCls: 'pve-itype-icon-memory',
renderer: function(value, metaData, record) {
var balloon = me.getObjectValue('balloon');
if (balloon) {
return PVE.Utils.format_size(balloon*1024*1024) + "/" +
PVE.Utils.format_size(value*1024*1024);
}
return PVE.Utils.format_size(value*1024*1024);
}
},
sockets: {
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',
defaultValue: 1,
multiKey: ['sockets', 'cpu', 'cores', 'numa', 'vcpus', 'cpulimit', 'cpuunits'],
renderer: function(value, metaData, record, rowIndex, colIndex, store, pending) {
var sockets = me.getObjectValue('sockets', 1, pending);
var model = me.getObjectValue('cpu', undefined, pending);
var cores = me.getObjectValue('cores', 1, pending);
var numa = me.getObjectValue('numa', undefined, pending);
var vcpus = me.getObjectValue('vcpus', undefined, pending);
var cpulimit = me.getObjectValue('cpulimit', undefined, pending);
var cpuunits = me.getObjectValue('cpuunits', undefined, pending);
var res = (sockets*cores) + ' (' + sockets + ' sockets, ' + cores + ' 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 +']';
}
return res;
}
},
keyboard: {
header: gettext('Keyboard Layout'),
never_delete: true,
editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.KeyboardEdit' : undefined,
tdCls: 'pve-itype-icon-keyboard',
defaultValue: '',
renderer: PVE.Utils.render_kvm_language
},
vga: {
header: gettext('Display'),
editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.DisplayEdit' : undefined,
never_delete: true,
tdCls: 'pve-itype-icon-display',
defaultValue: '',
renderer: PVE.Utils.render_kvm_vga_driver
},
cores: {
visible: false
},
cpu: {
visible: false
},
numa: {
visible: false
},
balloon: {
visible: false
},
hotplug: {
visible: false
},
vcpus: {
visible: false
},
cpuunits: {
visible: false
},
cpulimit: {
visible: false
}
};
for (i = 0; i < 4; i++) {
confid = "ide" + i;
rows[confid] = {
group: 1,
tdCls: 'pve-itype-icon-storage',
editor: 'PVE.qemu.HDEdit',
never_delete: caps.vms['VM.Config.Disk'] ? false : true,
header: gettext('Hard Disk') + ' (' + confid +')',
cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
};
}
for (i = 0; i < 6; i++) {
confid = "sata" + i;
rows[confid] = {
group: 1,
tdCls: 'pve-itype-icon-storage',
editor: 'PVE.qemu.HDEdit',
never_delete: caps.vms['VM.Config.Disk'] ? false : true,
header: gettext('Hard Disk') + ' (' + confid +')',
cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
};
}
for (i = 0; i < 16; i++) {
confid = "scsi" + i;
rows[confid] = {
group: 1,
tdCls: 'pve-itype-icon-storage',
editor: 'PVE.qemu.HDEdit',
never_delete: caps.vms['VM.Config.Disk'] ? false : true,
header: gettext('Hard Disk') + ' (' + confid +')',
cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
};
}
for (i = 0; i < 16; i++) {
confid = "virtio" + i;
rows[confid] = {
group: 1,
tdCls: 'pve-itype-icon-storage',
editor: 'PVE.qemu.HDEdit',
never_delete: caps.vms['VM.Config.Disk'] ? false : true,
header: gettext('Hard Disk') + ' (' + confid +')',
cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
};
}
for (i = 0; i < 32; i++) {
confid = "net" + i;
rows[confid] = {
group: 2,
tdCls: 'pve-itype-icon-network',
editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.NetworkEdit' : undefined,
never_delete: caps.vms['VM.Config.Network'] ? false : true,
header: gettext('Network Device') + ' (' + confid +')'
};
}
for (i = 0; i < 8; i++) {
rows["unused" + i] = {
group: 3,
tdCls: 'pve-itype-icon-storage',
editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.HDEdit' : undefined,
header: gettext('Unused Disk') + ' ' + i
};
}
var sorterFn = function(rec1, rec2) {
var v1 = rec1.data.key;
var v2 = rec2.data.key;
var g1 = rows[v1].group || 0;
var g2 = rows[v2].group || 0;
return (g1 !== g2) ?
(g1 > g2 ? 1 : -1) : (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
};
var reload = function() {
me.rstore.load();
};
var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
var 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) {
return;
}
var editor = rowdef.editor;
if (rowdef.tdCls == 'pve-itype-icon-storage') {
var value = me.getObjectValue(rec.data.key, '', true);
if (value.match(/media=cdrom/)) {
editor = 'PVE.qemu.CDEdit';
}
}
var win;
if (Ext.isString(editor)) {
win = Ext.create(editor, {
pveSelNode: me.pveSelNode,
confid: rec.data.key,
url: '/api2/extjs/' + baseurl
});
} 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);
win.load();
}
win.show();
win.on('destroy', reload);
};
var run_diskthrottle = function() {
var rec = sm.getSelection()[0];
if (!rec) {
return;
}
var win = Ext.create('PVE.qemu.HDThrottle', {
pveSelNode: me.pveSelNode,
confid: rec.data.key,
url: '/api2/extjs/' + baseurl
});
win.show();
win.on('destroy', reload);
};
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', reload);
};
var run_cpuoptions = function() {
var sockets = me.getObjectValue('sockets', 1);
var cores = me.getObjectValue('cores', 1);
var win = Ext.create('PVE.qemu.CPUOptions', {
maxvcpus: sockets * cores,
vmid: vmid,
pveSelNode: me.pveSelNode,
url: '/api2/extjs/' + baseurl
});
win.show();
win.on('destroy', reload);
};
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', reload);
};
var edit_btn = new PVE.button.Button({
text: gettext('Edit'),
selModel: sm,
disabled: true,
handler: run_editor
});
var resize_btn = new PVE.button.Button({
text: gettext('Resize disk'),
selModel: sm,
disabled: true,
handler: run_resize
});
var move_btn = new PVE.button.Button({
text: gettext('Move disk'),
selModel: sm,
disabled: true,
handler: run_move
});
var diskthrottle_btn = new PVE.button.Button({
text: gettext('Disk Throttle'),
selModel: sm,
disabled: true,
handler: run_diskthrottle
});
var cpuoptions_btn = new Ext.Button({
text: gettext('CPU options'),
handler: run_cpuoptions
});
var remove_btn = new PVE.button.Button({
text: gettext('Remove'),
selModel: sm,
disabled: true,
dangerous: true,
confirmMsg: function(rec) {
var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
"'" + me.renderKey(rec.data.key, {}, rec) + "'");
if (rec.data.key.match(/^unused\d+$/)) {
msg += " " + gettext('This will permanently erase all data.');
}
return msg;
},
handler: function(b, e, rec) {
PVE.Utils.API2Request({
url: '/api2/extjs/' + baseurl,
waitMsgTarget: me,
method: 'PUT',
params: {
'delete': rec.data.key
},
callback: function() {
reload();
},
failure: function (response, opts) {
Ext.Msg.alert('Error', response.htmlStatus);
}
});
}
});
var revert_btn = new PVE.button.Button({
text: gettext('Revert'),
selModel: sm,
disabled: true,
handler: function(b, e, rec) {
var rowdef = me.rows[rec.data.key] || {};
var keys = rowdef.multiKey || [ rec.data.key ];
var revert = keys.join(',');
PVE.Utils.API2Request({
url: '/api2/extjs/' + baseurl,
waitMsgTarget: me,
method: 'PUT',
params: {
'revert': revert
},
callback: function() {
reload();
},
failure: function (response, opts) {
Ext.Msg.alert('Error',response.htmlStatus);
}
});
}
});
var set_button_status = function() {
var sm = me.getSelectionModel();
var rec = sm.getSelection()[0];
if (!rec) {
remove_btn.disable();
edit_btn.disable();
resize_btn.disable();
move_btn.disable();
diskthrottle_btn.disable();
revert_btn.disable();
return;
}
var key = rec.data.key;
var value = rec.data.value;
var rowdef = rows[key];
var pending = rec.data['delete'] || me.hasPendingChanges(key);
var isDisk = !key.match(/^unused\d+/) &&
rowdef.tdCls == 'pve-itype-icon-storage' &&
(value && !value.match(/media=cdrom/));
remove_btn.setDisabled(rec.data['delete'] || (rowdef.never_delete === true));
edit_btn.setDisabled(rec.data['delete'] || !rowdef.editor);
resize_btn.setDisabled(pending || !isDisk);
move_btn.setDisabled(pending || !isDisk);
diskthrottle_btn.setDisabled(pending || !isDisk);
revert_btn.setDisabled(!pending);
};
Ext.apply(me, {
url: '/api2/json/' + 'nodes/' + nodename + '/qemu/' + vmid + '/pending',
interval: 5000,
selModel: sm,
tbar: [
{
text: gettext('Add'),
menu: new Ext.menu.Menu({
items: [
{
text: gettext('Hard Disk'),
iconCls: 'pve-itype-icon-storage',
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', reload);
win.show();
}
},
{
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', reload);
win.show();
}
},
{
text: gettext('Network Device'),
iconCls: 'pve-itype-icon-network',
disabled: !caps.vms['VM.Config.Network'],
handler: function() {
var win = Ext.create('PVE.qemu.NetworkEdit', {
url: '/api2/extjs/' + baseurl,
pveSelNode: me.pveSelNode
});
win.on('destroy', reload);
win.show();
}
}
]
})
},
remove_btn,
edit_btn,
resize_btn,
move_btn,
diskthrottle_btn,
cpuoptions_btn,
revert_btn
],
rows: rows,
sorterFn: sorterFn,
listeners: {
itemdblclick: run_editor,
selectionchange: set_button_status
}
});
me.callParent();
me.on('activate', me.rstore.startUpdate);
me.on('hide', me.rstore.stopUpdate);
me.on('destroy', me.rstore.stopUpdate);
me.mon(me.rstore, 'refresh', function() {
set_button_status();
});
}
});