]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/qemu/HardwareView.js
1 // fixme: howto avoid jslint type confusion?
2 /*jslint confusion: true */
3 Ext
.define('PVE.qemu.HardwareView', {
4 extend
: 'PVE.grid.PendingObjectGrid',
5 alias
: ['widget.PVE.qemu.HardwareView'],
7 onlineHelp
: 'qm_virtual_machines_settings',
9 renderKey: function(key
, metaData
, rec
, rowIndex
, colIndex
, store
) {
12 var rowdef
= rows
[key
] || {};
14 metaData
.tdAttr
= "valign=middle";
17 metaData
.tdCls
= rowdef
.tdCls
;
18 if (rowdef
.tdCls
== 'pve-itype-icon-storage') {
19 var value
= me
.getObjectValue(key
, '', true);
20 if (value
.match(/media=cdrom/)) {
21 metaData
.tdCls
= 'pve-itype-icon-cdrom';
22 return rowdef
.cdheader
;
26 return rowdef
.header
|| key
;
29 initComponent : function() {
33 var nodename
= me
.pveSelNode
.data
.node
;
35 throw "no node name specified";
38 var vmid
= me
.pveSelNode
.data
.vmid
;
40 throw "no VM ID specified";
43 var caps
= Ext
.state
.Manager
.get('GuiCap');
47 header
: gettext('Memory'),
48 editor
: caps
.vms
['VM.Config.Memory'] ? 'PVE.qemu.MemoryEdit' : undefined,
51 tdCls
: 'pve-itype-icon-memory',
52 renderer: function(value
, metaData
, record
) {
53 var balloon
= me
.getObjectValue('balloon');
55 return PVE
.Utils
.format_size(balloon
*1024*1024) + "/" +
56 PVE
.Utils
.format_size(value
*1024*1024);
59 return PVE
.Utils
.format_size(value
*1024*1024);
63 header
: gettext('Processors'),
65 editor
: (caps
.vms
['VM.Config.CPU'] || caps
.vms
['VM.Config.HWType']) ?
66 'PVE.qemu.ProcessorEdit' : undefined,
67 tdCls
: 'pve-itype-icon-processor',
69 multiKey
: ['sockets', 'cpu', 'cores', 'numa', 'vcpus', 'cpulimit', 'cpuunits'],
70 renderer: function(value
, metaData
, record
, rowIndex
, colIndex
, store
, pending
) {
72 var sockets
= me
.getObjectValue('sockets', 1, pending
);
73 var model
= me
.getObjectValue('cpu', undefined, pending
);
74 var cores
= me
.getObjectValue('cores', 1, pending
);
75 var numa
= me
.getObjectValue('numa', undefined, pending
);
76 var vcpus
= me
.getObjectValue('vcpus', undefined, pending
);
77 var cpulimit
= me
.getObjectValue('cpulimit', undefined, pending
);
78 var cpuunits
= me
.getObjectValue('cpuunits', undefined, pending
);
80 var res
= (sockets
*cores
) + ' (' + sockets
+ ' sockets, ' + cores
+ ' cores)';
83 res
+= ' [' + model
+ ']';
87 res
+= ' [numa=' + numa
+']';
91 res
+= ' [vcpus=' + vcpus
+']';
95 res
+= ' [cpulimit=' + cpulimit
+']';
99 res
+= ' [cpuunits=' + cpuunits
+']';
106 header
: gettext('Keyboard Layout'),
108 editor
: caps
.vms
['VM.Config.Options'] ? 'PVE.qemu.KeyboardEdit' : undefined,
109 tdCls
: 'pve-itype-icon-keyboard',
111 renderer
: PVE
.Utils
.render_kvm_language
114 header
: gettext('Display'),
115 editor
: caps
.vms
['VM.Config.HWType'] ? 'PVE.qemu.DisplayEdit' : undefined,
117 tdCls
: 'pve-itype-icon-display',
119 renderer
: PVE
.Utils
.render_kvm_vga_driver
151 for (i
= 0; i
< 4; i
++) {
155 tdCls
: 'pve-itype-icon-storage',
156 editor
: 'PVE.qemu.HDEdit',
157 never_delete
: caps
.vms
['VM.Config.Disk'] ? false : true,
158 header
: gettext('Hard Disk') + ' (' + confid
+')',
159 cdheader
: gettext('CD/DVD Drive') + ' (' + confid
+')'
162 for (i
= 0; i
< 6; i
++) {
166 tdCls
: 'pve-itype-icon-storage',
167 editor
: 'PVE.qemu.HDEdit',
168 never_delete
: caps
.vms
['VM.Config.Disk'] ? false : true,
169 header
: gettext('Hard Disk') + ' (' + confid
+')',
170 cdheader
: gettext('CD/DVD Drive') + ' (' + confid
+')'
173 for (i
= 0; i
< 16; i
++) {
177 tdCls
: 'pve-itype-icon-storage',
178 editor
: 'PVE.qemu.HDEdit',
179 never_delete
: caps
.vms
['VM.Config.Disk'] ? false : true,
180 header
: gettext('Hard Disk') + ' (' + confid
+')',
181 cdheader
: gettext('CD/DVD Drive') + ' (' + confid
+')'
184 for (i
= 0; i
< 16; i
++) {
185 confid
= "virtio" + i
;
188 tdCls
: 'pve-itype-icon-storage',
189 editor
: 'PVE.qemu.HDEdit',
190 never_delete
: caps
.vms
['VM.Config.Disk'] ? false : true,
191 header
: gettext('Hard Disk') + ' (' + confid
+')',
192 cdheader
: gettext('CD/DVD Drive') + ' (' + confid
+')'
195 for (i
= 0; i
< 32; i
++) {
199 tdCls
: 'pve-itype-icon-network',
200 editor
: caps
.vms
['VM.Config.Network'] ? 'PVE.qemu.NetworkEdit' : undefined,
201 never_delete
: caps
.vms
['VM.Config.Network'] ? false : true,
202 header
: gettext('Network Device') + ' (' + confid
+')'
207 tdCls
: 'pve-itype-icon-storage',
209 never_delete
: caps
.vms
['VM.Config.Disk'] ? false : true,
210 header
: gettext('EFI Disk')
212 for (i
= 0; i
< 5; i
++) {
216 tdCls
: 'pve-itype-icon-usb',
217 editor
: caps
.nodes
['Sys.Console'] ? 'PVE.qemu.USBEdit' : undefined,
218 never_delete
: caps
.nodes
['Sys.Console'] ? false : true,
219 header
: gettext('USB Device') + ' (' + confid
+ ')'
222 for (i
= 0; i
< 4; i
++) {
223 confid
= "hostpci" + i
;
226 tdCls
: 'pve-itype-icon-pci',
227 never_delete
: caps
.nodes
['Sys.Console'] ? false : true,
228 header
: gettext('PCI Device') + ' (' + confid
+ ')'
231 for (i
= 0; i
< 8; i
++) {
232 rows
["unused" + i
] = {
234 tdCls
: 'pve-itype-icon-storage',
235 editor
: caps
.vms
['VM.Config.Disk'] ? 'PVE.qemu.HDEdit' : undefined,
236 header
: gettext('Unused Disk') + ' ' + i
240 var sorterFn = function(rec1
, rec2
) {
241 var v1
= rec1
.data
.key
;
242 var v2
= rec2
.data
.key
;
243 var g1
= rows
[v1
].group
|| 0;
244 var g2
= rows
[v2
].group
|| 0;
247 (g1
> g2
? 1 : -1) : (v1
> v2
? 1 : (v1
< v2
? -1 : 0));
250 var reload = function() {
254 var baseurl
= 'nodes/' + nodename
+ '/qemu/' + vmid
+ '/config';
256 var sm
= Ext
.create('Ext.selection.RowModel', {});
258 var run_editor = function() {
259 var rec
= sm
.getSelection()[0];
264 var rowdef
= rows
[rec
.data
.key
];
265 if (!rowdef
.editor
) {
269 var editor
= rowdef
.editor
;
270 if (rowdef
.tdCls
== 'pve-itype-icon-storage') {
271 var value
= me
.getObjectValue(rec
.data
.key
, '', true);
272 if (value
.match(/media=cdrom/)) {
273 editor
= 'PVE.qemu.CDEdit';
279 if (Ext
.isString(editor
)) {
280 win
= Ext
.create(editor
, {
281 pveSelNode
: me
.pveSelNode
,
282 confid
: rec
.data
.key
,
283 url
: '/api2/extjs/' + baseurl
286 var config
= Ext
.apply({
287 pveSelNode
: me
.pveSelNode
,
288 confid
: rec
.data
.key
,
289 url
: '/api2/extjs/' + baseurl
291 win
= Ext
.createWidget(rowdef
.editor
.xtype
, config
);
296 win
.on('destroy', reload
);
299 var run_diskthrottle = function() {
300 var rec
= sm
.getSelection()[0];
305 var win
= Ext
.create('PVE.qemu.HDThrottle', {
306 pveSelNode
: me
.pveSelNode
,
307 confid
: rec
.data
.key
,
308 url
: '/api2/extjs/' + baseurl
312 win
.on('destroy', reload
);
315 var run_resize = function() {
316 var rec
= sm
.getSelection()[0];
321 var win
= Ext
.create('PVE.window.HDResize', {
329 win
.on('destroy', reload
);
332 var run_cpuoptions = function() {
333 var sockets
= me
.getObjectValue('sockets', 1);
334 var cores
= me
.getObjectValue('cores', 1);
336 var win
= Ext
.create('PVE.qemu.CPUOptions', {
337 maxvcpus
: sockets
* cores
,
339 pveSelNode
: me
.pveSelNode
,
340 url
: '/api2/extjs/' + baseurl
345 win
.on('destroy', reload
);
348 var run_move = function() {
349 var rec
= sm
.getSelection()[0];
354 var win
= Ext
.create('PVE.window.HDMove', {
362 win
.on('destroy', reload
);
365 var edit_btn
= new PVE
.button
.Button({
366 text
: gettext('Edit'),
372 var resize_btn
= new PVE
.button
.Button({
373 text
: gettext('Resize disk'),
379 var move_btn
= new PVE
.button
.Button({
380 text
: gettext('Move disk'),
386 var diskthrottle_btn
= new PVE
.button
.Button({
387 text
: gettext('Disk Throttle'),
390 handler
: run_diskthrottle
393 var cpuoptions_btn
= new Ext
.Button({
394 text
: gettext('CPU options'),
395 handler
: run_cpuoptions
398 var remove_btn
= new PVE
.button
.Button({
399 text
: gettext('Remove'),
403 confirmMsg: function(rec
) {
404 var msg
= Ext
.String
.format(gettext('Are you sure you want to remove entry {0}'),
405 "'" + me
.renderKey(rec
.data
.key
, {}, rec
) + "'");
406 if (rec
.data
.key
.match(/^unused\d+$/)) {
407 msg
+= " " + gettext('This will permanently erase all data.');
412 handler: function(b
, e
, rec
) {
413 PVE
.Utils
.API2Request({
414 url
: '/api2/extjs/' + baseurl
,
418 'delete': rec
.data
.key
420 callback: function() {
423 failure: function (response
, opts
) {
424 Ext
.Msg
.alert('Error', response
.htmlStatus
);
430 var revert_btn
= new PVE
.button
.Button({
431 text
: gettext('Revert'),
434 handler: function(b
, e
, rec
) {
435 var rowdef
= me
.rows
[rec
.data
.key
] || {};
436 var keys
= rowdef
.multiKey
|| [ rec
.data
.key
];
437 var revert
= keys
.join(',');
438 PVE
.Utils
.API2Request({
439 url
: '/api2/extjs/' + baseurl
,
445 callback: function() {
448 failure: function (response
, opts
) {
449 Ext
.Msg
.alert('Error',response
.htmlStatus
);
455 var efidisk_menuitem
= Ext
.create('Ext.menu.Item',{
456 text
: gettext('EFI Disk'),
457 iconCls
: 'pve-itype-icon-storage',
458 disabled
: !caps
.vms
['VM.Config.Disk'],
459 handler: function() {
461 var rstoredata
= me
.rstore
.getData().map
;
462 // check if ovmf is configured
463 if (rstoredata
.bios
&& rstoredata
.bios
.data
.value
=== 'ovmf') {
464 var win
= Ext
.create('PVE.qemu.EFIDiskEdit', {
465 url
: '/api2/extjs/' + baseurl
,
466 pveSelNode
: me
.pveSelNode
468 win
.on('destroy', reload
);
471 Ext
.Msg
.alert('Error',gettext('Please select OVMF(UEFI) as BIOS first.'));
477 var set_button_status = function() {
478 var sm
= me
.getSelectionModel();
479 var rec
= sm
.getSelection()[0];
481 // disable button when we have an efidisk already
482 // disable is ok in this case, because you can instantly
483 // see that there is already one
484 efidisk_menuitem
.setDisabled(me
.rstore
.getData().map
.efidisk0
!== undefined);
485 // en/disable usb add button
487 me
.rstore
.getData().items
.forEach(function(item
){
488 if (/^usb\d+/.test(item
.id
)) {
492 me
.down('#addusb').setDisabled((count
>= 5));
495 remove_btn
.disable();
497 resize_btn
.disable();
499 diskthrottle_btn
.disable();
500 revert_btn
.disable();
503 var key
= rec
.data
.key
;
504 var value
= rec
.data
.value
;
505 var rowdef
= rows
[key
];
507 var pending
= rec
.data
['delete'] || me
.hasPendingChanges(key
);
508 var isDisk
= !key
.match(/^unused\d+/) &&
509 rowdef
.tdCls
== 'pve-itype-icon-storage' &&
510 (value
&& !value
.match(/media=cdrom/));
512 var isEfi
= (key
=== 'efidisk0');
515 remove_btn
.setDisabled(rec
.data
['delete'] || (rowdef
.never_delete
=== true));
517 edit_btn
.setDisabled(rec
.data
['delete'] || !rowdef
.editor
);
519 resize_btn
.setDisabled(pending
|| !isDisk
);
521 move_btn
.setDisabled(pending
|| !isDisk
);
523 diskthrottle_btn
.setDisabled(pending
|| !isDisk
|| isEfi
);
525 revert_btn
.setDisabled(!pending
);
530 url
: '/api2/json/' + 'nodes/' + nodename
+ '/qemu/' + vmid
+ '/pending',
535 text
: gettext('Add'),
536 menu
: new Ext
.menu
.Menu({
539 text
: gettext('Hard Disk'),
540 iconCls
: 'pve-itype-icon-storage',
541 disabled
: !caps
.vms
['VM.Config.Disk'],
542 handler: function() {
543 var win
= Ext
.create('PVE.qemu.HDEdit', {
544 url
: '/api2/extjs/' + baseurl
,
545 pveSelNode
: me
.pveSelNode
547 win
.on('destroy', reload
);
552 text
: gettext('CD/DVD Drive'),
553 iconCls
: 'pve-itype-icon-cdrom',
554 disabled
: !caps
.vms
['VM.Config.Disk'],
555 handler: function() {
556 var win
= Ext
.create('PVE.qemu.CDEdit', {
557 url
: '/api2/extjs/' + baseurl
,
558 pveSelNode
: me
.pveSelNode
560 win
.on('destroy', reload
);
565 text
: gettext('Network Device'),
566 iconCls
: 'pve-itype-icon-network',
567 disabled
: !caps
.vms
['VM.Config.Network'],
568 handler: function() {
569 var win
= Ext
.create('PVE.qemu.NetworkEdit', {
570 url
: '/api2/extjs/' + baseurl
,
571 pveSelNode
: me
.pveSelNode
573 win
.on('destroy', reload
);
579 text
: gettext('USB Device'),
581 iconCls
: 'pve-itype-icon-usb',
582 disabled
: !caps
.nodes
['Sys.Console'],
583 handler: function() {
584 var win
= Ext
.create('PVE.qemu.USBEdit', {
585 url
: '/api2/extjs/' + baseurl
,
586 pveSelNode
: me
.pveSelNode
588 win
.on('destroy', reload
);
606 itemdblclick
: run_editor
,
607 selectionchange
: set_button_status
613 me
.on('activate', me
.rstore
.startUpdate
);
614 me
.on('destroy', me
.rstore
.stopUpdate
);
616 me
.mon(me
.rstore
, 'refresh', function() {