]>
Commit | Line | Data |
---|---|---|
f97670f5 | 1 | Ext.define('PVE.qemu.HardwareView', { |
bc0eaf58 | 2 | extend: 'Proxmox.grid.PendingObjectGrid', |
f97670f5 DM |
3 | alias: ['widget.PVE.qemu.HardwareView'], |
4 | ||
ba93a9c6 DC |
5 | onlineHelp: 'qm_virtual_machines_settings', |
6 | ||
f97670f5 DM |
7 | renderKey: function(key, metaData, rec, rowIndex, colIndex, store) { |
8 | var me = this; | |
9 | var rows = me.rows; | |
10 | var rowdef = rows[key] || {}; | |
11 | ||
12 | metaData.tdAttr = "valign=middle"; | |
13 | ||
14 | if (rowdef.tdCls) { | |
15 | metaData.tdCls = rowdef.tdCls; | |
16 | if (rowdef.tdCls == 'pve-itype-icon-storage') { | |
17 | var value = me.getObjectValue(key, '', true); | |
18 | if (value.match(/media=cdrom/)) { | |
19 | metaData.tdCls = 'pve-itype-icon-cdrom'; | |
20 | return rowdef.cdheader; | |
21 | } | |
22 | } | |
23 | } | |
24 | return rowdef.header || key; | |
25 | }, | |
26 | ||
27 | initComponent : function() { | |
28 | var me = this; | |
29 | var i, confid; | |
30 | ||
31 | var nodename = me.pveSelNode.data.node; | |
32 | if (!nodename) { | |
33 | throw "no node name specified"; | |
34 | } | |
35 | ||
36 | var vmid = me.pveSelNode.data.vmid; | |
37 | if (!vmid) { | |
38 | throw "no VM ID specified"; | |
39 | } | |
40 | ||
41 | var caps = Ext.state.Manager.get('GuiCap'); | |
42 | ||
43 | var rows = { | |
44 | memory: { | |
45 | header: gettext('Memory'), | |
46 | editor: caps.vms['VM.Config.Memory'] ? 'PVE.qemu.MemoryEdit' : undefined, | |
47 | never_delete: true, | |
72408db9 | 48 | defaultValue: '512', |
f97670f5 DM |
49 | tdCls: 'pve-itype-icon-memory', |
50 | renderer: function(value, metaData, record) { | |
51 | var balloon = me.getObjectValue('balloon'); | |
52 | if (balloon) { | |
e7ade592 DC |
53 | return Proxmox.Utils.format_size(balloon*1024*1024) + "/" + |
54 | Proxmox.Utils.format_size(value*1024*1024); | |
f97670f5 DM |
55 | |
56 | } | |
e7ade592 | 57 | return Proxmox.Utils.format_size(value*1024*1024); |
f97670f5 DM |
58 | } |
59 | }, | |
60 | sockets: { | |
61 | header: gettext('Processors'), | |
62 | never_delete: true, | |
63 | editor: (caps.vms['VM.Config.CPU'] || caps.vms['VM.Config.HWType']) ? | |
64 | 'PVE.qemu.ProcessorEdit' : undefined, | |
65 | tdCls: 'pve-itype-icon-processor', | |
72408db9 | 66 | defaultValue: '1', |
f97670f5 DM |
67 | multiKey: ['sockets', 'cpu', 'cores', 'numa', 'vcpus', 'cpulimit', 'cpuunits'], |
68 | renderer: function(value, metaData, record, rowIndex, colIndex, store, pending) { | |
69 | ||
70 | var sockets = me.getObjectValue('sockets', 1, pending); | |
71 | var model = me.getObjectValue('cpu', undefined, pending); | |
72 | var cores = me.getObjectValue('cores', 1, pending); | |
73 | var numa = me.getObjectValue('numa', undefined, pending); | |
74 | var vcpus = me.getObjectValue('vcpus', undefined, pending); | |
75 | var cpulimit = me.getObjectValue('cpulimit', undefined, pending); | |
76 | var cpuunits = me.getObjectValue('cpuunits', undefined, pending); | |
77 | ||
72408db9 EK |
78 | var res = Ext.String.format('{0} ({1} sockets, {2} cores)', |
79 | sockets*cores, sockets, cores); | |
80 | ||
f97670f5 DM |
81 | if (model) { |
82 | res += ' [' + model + ']'; | |
83 | } | |
84 | ||
85 | if (numa) { | |
86 | res += ' [numa=' + numa +']'; | |
87 | } | |
88 | ||
89 | if (vcpus) { | |
90 | res += ' [vcpus=' + vcpus +']'; | |
91 | } | |
92 | ||
93 | if (cpulimit) { | |
94 | res += ' [cpulimit=' + cpulimit +']'; | |
95 | } | |
96 | ||
97 | if (cpuunits) { | |
98 | res += ' [cpuunits=' + cpuunits +']'; | |
99 | } | |
100 | ||
101 | return res; | |
102 | } | |
103 | }, | |
104 | keyboard: { | |
105 | header: gettext('Keyboard Layout'), | |
106 | never_delete: true, | |
107 | editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.KeyboardEdit' : undefined, | |
108 | tdCls: 'pve-itype-icon-keyboard', | |
109 | defaultValue: '', | |
110 | renderer: PVE.Utils.render_kvm_language | |
111 | }, | |
112 | vga: { | |
113 | header: gettext('Display'), | |
114 | editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.DisplayEdit' : undefined, | |
115 | never_delete: true, | |
116 | tdCls: 'pve-itype-icon-display', | |
117 | defaultValue: '', | |
118 | renderer: PVE.Utils.render_kvm_vga_driver | |
119 | }, | |
120 | cores: { | |
121 | visible: false | |
122 | }, | |
123 | cpu: { | |
124 | visible: false | |
125 | }, | |
126 | numa: { | |
127 | visible: false | |
128 | }, | |
129 | balloon: { | |
130 | visible: false | |
131 | }, | |
132 | hotplug: { | |
133 | visible: false | |
134 | }, | |
135 | vcpus: { | |
136 | visible: false | |
137 | }, | |
138 | cpuunits: { | |
139 | visible: false | |
140 | }, | |
141 | cpulimit: { | |
142 | visible: false | |
3b37ab6d DC |
143 | }, |
144 | bios: { | |
145 | visible: false | |
f97670f5 DM |
146 | } |
147 | ||
148 | }; | |
149 | ||
150 | for (i = 0; i < 4; i++) { | |
72408db9 | 151 | confid = "ide" + i.toString(); |
f97670f5 DM |
152 | rows[confid] = { |
153 | group: 1, | |
154 | tdCls: 'pve-itype-icon-storage', | |
155 | editor: 'PVE.qemu.HDEdit', | |
156 | never_delete: caps.vms['VM.Config.Disk'] ? false : true, | |
157 | header: gettext('Hard Disk') + ' (' + confid +')', | |
158 | cdheader: gettext('CD/DVD Drive') + ' (' + confid +')' | |
159 | }; | |
160 | } | |
161 | for (i = 0; i < 6; i++) { | |
72408db9 | 162 | confid = "sata" + i.toString(); |
f97670f5 DM |
163 | rows[confid] = { |
164 | group: 1, | |
165 | tdCls: 'pve-itype-icon-storage', | |
166 | editor: 'PVE.qemu.HDEdit', | |
167 | never_delete: caps.vms['VM.Config.Disk'] ? false : true, | |
168 | header: gettext('Hard Disk') + ' (' + confid +')', | |
169 | cdheader: gettext('CD/DVD Drive') + ' (' + confid +')' | |
170 | }; | |
171 | } | |
172 | for (i = 0; i < 16; i++) { | |
72408db9 | 173 | confid = "scsi" + i.toString(); |
f97670f5 DM |
174 | rows[confid] = { |
175 | group: 1, | |
176 | tdCls: 'pve-itype-icon-storage', | |
177 | editor: 'PVE.qemu.HDEdit', | |
178 | never_delete: caps.vms['VM.Config.Disk'] ? false : true, | |
179 | header: gettext('Hard Disk') + ' (' + confid +')', | |
180 | cdheader: gettext('CD/DVD Drive') + ' (' + confid +')' | |
181 | }; | |
182 | } | |
183 | for (i = 0; i < 16; i++) { | |
72408db9 | 184 | confid = "virtio" + i.toString(); |
f97670f5 DM |
185 | rows[confid] = { |
186 | group: 1, | |
187 | tdCls: 'pve-itype-icon-storage', | |
188 | editor: 'PVE.qemu.HDEdit', | |
189 | never_delete: caps.vms['VM.Config.Disk'] ? false : true, | |
190 | header: gettext('Hard Disk') + ' (' + confid +')', | |
191 | cdheader: gettext('CD/DVD Drive') + ' (' + confid +')' | |
192 | }; | |
193 | } | |
194 | for (i = 0; i < 32; i++) { | |
72408db9 | 195 | confid = "net" + i.toString(); |
f97670f5 DM |
196 | rows[confid] = { |
197 | group: 2, | |
198 | tdCls: 'pve-itype-icon-network', | |
199 | editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.NetworkEdit' : undefined, | |
200 | never_delete: caps.vms['VM.Config.Network'] ? false : true, | |
201 | header: gettext('Network Device') + ' (' + confid +')' | |
202 | }; | |
203 | } | |
194c9b09 DC |
204 | rows.efidisk0 = { |
205 | group: 3, | |
206 | tdCls: 'pve-itype-icon-storage', | |
207 | editor: null, | |
208 | never_delete: caps.vms['VM.Config.Disk'] ? false : true, | |
209 | header: gettext('EFI Disk') | |
210 | }; | |
fa522e48 | 211 | for (i = 0; i < 5; i++) { |
72408db9 | 212 | confid = "usb" + i.toString(); |
fa522e48 DC |
213 | rows[confid] = { |
214 | group: 4, | |
215 | tdCls: 'pve-itype-icon-usb', | |
2668ba64 DC |
216 | editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.USBEdit' : undefined, |
217 | never_delete: caps.nodes['Sys.Console'] ? false : true, | |
fa522e48 DC |
218 | header: gettext('USB Device') + ' (' + confid + ')' |
219 | }; | |
220 | } | |
ec3d8372 | 221 | for (i = 0; i < 4; i++) { |
72408db9 | 222 | confid = "hostpci" + i.toString(); |
ec3d8372 DC |
223 | rows[confid] = { |
224 | group: 5, | |
225 | tdCls: 'pve-itype-icon-pci', | |
226 | never_delete: caps.nodes['Sys.Console'] ? false : true, | |
227 | header: gettext('PCI Device') + ' (' + confid + ')' | |
228 | }; | |
229 | } | |
a488da8c DC |
230 | for (i = 0; i < 4; i++) { |
231 | confid = "serial" + i.toString(); | |
232 | rows[confid] = { | |
233 | group: 6, | |
234 | tdCls: 'pve-itype-icon-serial', | |
235 | never_delete: caps.nodes['Sys.Console'] ? false : true, | |
236 | header: gettext('Serial Port') + ' (' + confid + ')' | |
237 | }; | |
238 | } | |
f97670f5 | 239 | for (i = 0; i < 8; i++) { |
72408db9 | 240 | rows["unused" + i.toString()] = { |
cd86ab24 | 241 | group: 99, |
f97670f5 DM |
242 | tdCls: 'pve-itype-icon-storage', |
243 | editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.HDEdit' : undefined, | |
72408db9 | 244 | header: gettext('Unused Disk') + ' ' + i.toString() |
f97670f5 DM |
245 | }; |
246 | } | |
247 | ||
248 | var sorterFn = function(rec1, rec2) { | |
249 | var v1 = rec1.data.key; | |
250 | var v2 = rec2.data.key; | |
251 | var g1 = rows[v1].group || 0; | |
252 | var g2 = rows[v2].group || 0; | |
253 | ||
254 | return (g1 !== g2) ? | |
255 | (g1 > g2 ? 1 : -1) : (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)); | |
256 | }; | |
257 | ||
258 | var reload = function() { | |
259 | me.rstore.load(); | |
260 | }; | |
261 | ||
262 | var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config'; | |
263 | ||
264 | var sm = Ext.create('Ext.selection.RowModel', {}); | |
265 | ||
266 | var run_editor = function() { | |
267 | var rec = sm.getSelection()[0]; | |
268 | if (!rec) { | |
269 | return; | |
270 | } | |
271 | ||
272 | var rowdef = rows[rec.data.key]; | |
273 | if (!rowdef.editor) { | |
274 | return; | |
275 | } | |
276 | ||
277 | var editor = rowdef.editor; | |
278 | if (rowdef.tdCls == 'pve-itype-icon-storage') { | |
279 | var value = me.getObjectValue(rec.data.key, '', true); | |
280 | if (value.match(/media=cdrom/)) { | |
281 | editor = 'PVE.qemu.CDEdit'; | |
282 | } | |
283 | } | |
284 | ||
285 | var win; | |
286 | ||
287 | if (Ext.isString(editor)) { | |
288 | win = Ext.create(editor, { | |
289 | pveSelNode: me.pveSelNode, | |
290 | confid: rec.data.key, | |
291 | url: '/api2/extjs/' + baseurl | |
292 | }); | |
293 | } else { | |
294 | var config = Ext.apply({ | |
295 | pveSelNode: me.pveSelNode, | |
296 | confid: rec.data.key, | |
297 | url: '/api2/extjs/' + baseurl | |
298 | }, rowdef.editor); | |
299 | win = Ext.createWidget(rowdef.editor.xtype, config); | |
300 | win.load(); | |
301 | } | |
302 | ||
303 | win.show(); | |
304 | win.on('destroy', reload); | |
305 | }; | |
306 | ||
307 | var run_diskthrottle = function() { | |
308 | var rec = sm.getSelection()[0]; | |
309 | if (!rec) { | |
310 | return; | |
311 | } | |
312 | ||
313 | var win = Ext.create('PVE.qemu.HDThrottle', { | |
314 | pveSelNode: me.pveSelNode, | |
315 | confid: rec.data.key, | |
316 | url: '/api2/extjs/' + baseurl | |
317 | }); | |
318 | ||
319 | win.show(); | |
320 | win.on('destroy', reload); | |
321 | }; | |
322 | ||
323 | var run_resize = function() { | |
324 | var rec = sm.getSelection()[0]; | |
325 | if (!rec) { | |
326 | return; | |
327 | } | |
328 | ||
329 | var win = Ext.create('PVE.window.HDResize', { | |
330 | disk: rec.data.key, | |
331 | nodename: nodename, | |
332 | vmid: vmid | |
333 | }); | |
334 | ||
335 | win.show(); | |
336 | ||
337 | win.on('destroy', reload); | |
338 | }; | |
339 | ||
340 | var run_cpuoptions = function() { | |
341 | var sockets = me.getObjectValue('sockets', 1); | |
342 | var cores = me.getObjectValue('cores', 1); | |
343 | ||
344 | var win = Ext.create('PVE.qemu.CPUOptions', { | |
345 | maxvcpus: sockets * cores, | |
346 | vmid: vmid, | |
347 | pveSelNode: me.pveSelNode, | |
348 | url: '/api2/extjs/' + baseurl | |
349 | }); | |
350 | ||
351 | win.show(); | |
352 | ||
353 | win.on('destroy', reload); | |
354 | }; | |
355 | ||
356 | var run_move = function() { | |
357 | var rec = sm.getSelection()[0]; | |
358 | if (!rec) { | |
359 | return; | |
360 | } | |
361 | ||
362 | var win = Ext.create('PVE.window.HDMove', { | |
363 | disk: rec.data.key, | |
364 | nodename: nodename, | |
365 | vmid: vmid | |
366 | }); | |
367 | ||
368 | win.show(); | |
369 | ||
370 | win.on('destroy', reload); | |
371 | }; | |
372 | ||
5720fafa | 373 | var edit_btn = new Proxmox.button.Button({ |
f97670f5 DM |
374 | text: gettext('Edit'), |
375 | selModel: sm, | |
376 | disabled: true, | |
377 | handler: run_editor | |
378 | }); | |
379 | ||
5720fafa | 380 | var resize_btn = new Proxmox.button.Button({ |
f97670f5 DM |
381 | text: gettext('Resize disk'), |
382 | selModel: sm, | |
383 | disabled: true, | |
384 | handler: run_resize | |
385 | }); | |
386 | ||
5720fafa | 387 | var move_btn = new Proxmox.button.Button({ |
f97670f5 DM |
388 | text: gettext('Move disk'), |
389 | selModel: sm, | |
390 | disabled: true, | |
391 | handler: run_move | |
392 | }); | |
393 | ||
5720fafa | 394 | var diskthrottle_btn = new Proxmox.button.Button({ |
f97670f5 DM |
395 | text: gettext('Disk Throttle'), |
396 | selModel: sm, | |
397 | disabled: true, | |
398 | handler: run_diskthrottle | |
399 | }); | |
400 | ||
401 | var cpuoptions_btn = new Ext.Button({ | |
402 | text: gettext('CPU options'), | |
403 | handler: run_cpuoptions | |
404 | }); | |
405 | ||
5720fafa | 406 | var remove_btn = new Proxmox.button.Button({ |
f97670f5 | 407 | text: gettext('Remove'), |
877fce54 EK |
408 | defaultText: gettext('Remove'), |
409 | altText: gettext('Detach'), | |
f97670f5 DM |
410 | selModel: sm, |
411 | disabled: true, | |
412 | dangerous: true, | |
413 | confirmMsg: function(rec) { | |
ff5a8a9b EK |
414 | var warn = gettext('Are you sure you want to remove entry {0}'); |
415 | if (this.text === this.altText) { | |
416 | warn = gettext('Are you sure you want to detach entry {0}'); | |
417 | } | |
418 | ||
419 | var entry = rec.data.key; | |
420 | var msg = Ext.String.format(warn, "'" | |
421 | + me.renderKey(entry, {}, rec) + "'"); | |
422 | ||
423 | if (entry.match(/^unused\d+$/)) { | |
16152937 | 424 | msg += " " + gettext('This will permanently erase all data.'); |
f97670f5 DM |
425 | } |
426 | ||
427 | return msg; | |
428 | }, | |
429 | handler: function(b, e, rec) { | |
e7ade592 | 430 | Proxmox.Utils.API2Request({ |
f97670f5 DM |
431 | url: '/api2/extjs/' + baseurl, |
432 | waitMsgTarget: me, | |
433 | method: 'PUT', | |
434 | params: { | |
435 | 'delete': rec.data.key | |
436 | }, | |
437 | callback: function() { | |
438 | reload(); | |
439 | }, | |
440 | failure: function (response, opts) { | |
441 | Ext.Msg.alert('Error', response.htmlStatus); | |
442 | } | |
443 | }); | |
877fce54 EK |
444 | }, |
445 | listeners: { | |
446 | render: function(btn) { | |
447 | // hack: calculate an optimal button width on first display | |
448 | // to prevent the whole toolbar to move when we switch | |
449 | // between the "Remove" and "Detach" labels | |
450 | var def = btn.getSize().width; | |
451 | ||
452 | btn.setText(btn.altText); | |
453 | var alt = btn.getSize().width; | |
454 | ||
455 | btn.setText(btn.defaultText); | |
456 | ||
457 | var optimal = alt > def ? alt : def; | |
458 | btn.setSize({ width: optimal }); | |
459 | } | |
f97670f5 DM |
460 | } |
461 | }); | |
462 | ||
5720fafa | 463 | var revert_btn = new Proxmox.button.Button({ |
f97670f5 DM |
464 | text: gettext('Revert'), |
465 | selModel: sm, | |
466 | disabled: true, | |
467 | handler: function(b, e, rec) { | |
468 | var rowdef = me.rows[rec.data.key] || {}; | |
469 | var keys = rowdef.multiKey || [ rec.data.key ]; | |
470 | var revert = keys.join(','); | |
e7ade592 | 471 | Proxmox.Utils.API2Request({ |
f97670f5 DM |
472 | url: '/api2/extjs/' + baseurl, |
473 | waitMsgTarget: me, | |
474 | method: 'PUT', | |
475 | params: { | |
476 | 'revert': revert | |
477 | }, | |
478 | callback: function() { | |
479 | reload(); | |
480 | }, | |
481 | failure: function (response, opts) { | |
482 | Ext.Msg.alert('Error',response.htmlStatus); | |
483 | } | |
484 | }); | |
485 | } | |
486 | }); | |
487 | ||
3b37ab6d DC |
488 | var efidisk_menuitem = Ext.create('Ext.menu.Item',{ |
489 | text: gettext('EFI Disk'), | |
490 | iconCls: 'pve-itype-icon-storage', | |
491 | disabled: !caps.vms['VM.Config.Disk'], | |
492 | handler: function() { | |
1535df62 DC |
493 | |
494 | var rstoredata = me.rstore.getData().map; | |
495 | // check if ovmf is configured | |
496 | if (rstoredata.bios && rstoredata.bios.data.value === 'ovmf') { | |
497 | var win = Ext.create('PVE.qemu.EFIDiskEdit', { | |
498 | url: '/api2/extjs/' + baseurl, | |
499 | pveSelNode: me.pveSelNode | |
500 | }); | |
501 | win.on('destroy', reload); | |
502 | win.show(); | |
503 | } else { | |
504 | Ext.Msg.alert('Error',gettext('Please select OVMF(UEFI) as BIOS first.')); | |
505 | } | |
506 | ||
3b37ab6d DC |
507 | } |
508 | }); | |
509 | ||
f97670f5 DM |
510 | var set_button_status = function() { |
511 | var sm = me.getSelectionModel(); | |
512 | var rec = sm.getSelection()[0]; | |
513 | ||
1535df62 DC |
514 | // disable button when we have an efidisk already |
515 | // disable is ok in this case, because you can instantly | |
516 | // see that there is already one | |
517 | efidisk_menuitem.setDisabled(me.rstore.getData().map.efidisk0 !== undefined); | |
2668ba64 DC |
518 | // en/disable usb add button |
519 | var count = 0; | |
520 | me.rstore.getData().items.forEach(function(item){ | |
521 | if (/^usb\d+/.test(item.id)) { | |
522 | count++; | |
523 | } | |
524 | }); | |
525 | me.down('#addusb').setDisabled((count >= 5)); | |
3b37ab6d | 526 | |
f97670f5 DM |
527 | if (!rec) { |
528 | remove_btn.disable(); | |
529 | edit_btn.disable(); | |
530 | resize_btn.disable(); | |
531 | move_btn.disable(); | |
532 | diskthrottle_btn.disable(); | |
533 | revert_btn.disable(); | |
534 | return; | |
535 | } | |
536 | var key = rec.data.key; | |
537 | var value = rec.data.value; | |
538 | var rowdef = rows[key]; | |
539 | ||
540 | var pending = rec.data['delete'] || me.hasPendingChanges(key); | |
877fce54 | 541 | var isUsedDisk = !key.match(/^unused\d+/) && |
25e0bc2d DC |
542 | rowdef.tdCls == 'pve-itype-icon-storage' && |
543 | (value && !value.match(/media=cdrom/)); | |
f97670f5 | 544 | |
3b37ab6d DC |
545 | var isEfi = (key === 'efidisk0'); |
546 | ||
f97670f5 | 547 | remove_btn.setDisabled(rec.data['delete'] || (rowdef.never_delete === true)); |
877fce54 | 548 | remove_btn.setText(isUsedDisk ? remove_btn.altText : remove_btn.defaultText); |
f97670f5 DM |
549 | |
550 | edit_btn.setDisabled(rec.data['delete'] || !rowdef.editor); | |
551 | ||
877fce54 | 552 | resize_btn.setDisabled(pending || !isUsedDisk); |
f97670f5 | 553 | |
877fce54 | 554 | move_btn.setDisabled(pending || !isUsedDisk); |
f97670f5 | 555 | |
877fce54 | 556 | diskthrottle_btn.setDisabled(pending || !isUsedDisk || isEfi); |
f97670f5 DM |
557 | |
558 | revert_btn.setDisabled(!pending); | |
559 | ||
560 | }; | |
561 | ||
f09dd6c1 | 562 | Ext.apply(me, { |
f97670f5 DM |
563 | url: '/api2/json/' + 'nodes/' + nodename + '/qemu/' + vmid + '/pending', |
564 | interval: 5000, | |
565 | selModel: sm, | |
f97670f5 DM |
566 | tbar: [ |
567 | { | |
568 | text: gettext('Add'), | |
569 | menu: new Ext.menu.Menu({ | |
570 | items: [ | |
571 | { | |
572 | text: gettext('Hard Disk'), | |
573 | iconCls: 'pve-itype-icon-storage', | |
574 | disabled: !caps.vms['VM.Config.Disk'], | |
575 | handler: function() { | |
576 | var win = Ext.create('PVE.qemu.HDEdit', { | |
577 | url: '/api2/extjs/' + baseurl, | |
578 | pveSelNode: me.pveSelNode | |
579 | }); | |
580 | win.on('destroy', reload); | |
581 | win.show(); | |
582 | } | |
583 | }, | |
584 | { | |
585 | text: gettext('CD/DVD Drive'), | |
586 | iconCls: 'pve-itype-icon-cdrom', | |
587 | disabled: !caps.vms['VM.Config.Disk'], | |
588 | handler: function() { | |
589 | var win = Ext.create('PVE.qemu.CDEdit', { | |
590 | url: '/api2/extjs/' + baseurl, | |
591 | pveSelNode: me.pveSelNode | |
592 | }); | |
593 | win.on('destroy', reload); | |
594 | win.show(); | |
595 | } | |
596 | }, | |
597 | { | |
598 | text: gettext('Network Device'), | |
599 | iconCls: 'pve-itype-icon-network', | |
600 | disabled: !caps.vms['VM.Config.Network'], | |
601 | handler: function() { | |
602 | var win = Ext.create('PVE.qemu.NetworkEdit', { | |
603 | url: '/api2/extjs/' + baseurl, | |
604 | pveSelNode: me.pveSelNode | |
605 | }); | |
606 | win.on('destroy', reload); | |
607 | win.show(); | |
608 | } | |
3b37ab6d | 609 | }, |
2668ba64 DC |
610 | efidisk_menuitem, |
611 | { | |
612 | text: gettext('USB Device'), | |
613 | itemId: 'addusb', | |
614 | iconCls: 'pve-itype-icon-usb', | |
615 | disabled: !caps.nodes['Sys.Console'], | |
616 | handler: function() { | |
617 | var win = Ext.create('PVE.qemu.USBEdit', { | |
618 | url: '/api2/extjs/' + baseurl, | |
619 | pveSelNode: me.pveSelNode | |
620 | }); | |
621 | win.on('destroy', reload); | |
622 | win.show(); | |
623 | } | |
624 | } | |
f97670f5 DM |
625 | ] |
626 | }) | |
fa522e48 | 627 | }, |
f97670f5 DM |
628 | remove_btn, |
629 | edit_btn, | |
630 | resize_btn, | |
631 | move_btn, | |
632 | diskthrottle_btn, | |
633 | cpuoptions_btn, | |
634 | revert_btn | |
635 | ], | |
636 | rows: rows, | |
637 | sorterFn: sorterFn, | |
638 | listeners: { | |
639 | itemdblclick: run_editor, | |
640 | selectionchange: set_button_status | |
641 | } | |
642 | }); | |
643 | ||
644 | me.callParent(); | |
645 | ||
f09dd6c1 | 646 | me.on('activate', me.rstore.startUpdate); |
f97670f5 DM |
647 | me.on('destroy', me.rstore.stopUpdate); |
648 | ||
f09dd6c1 | 649 | me.mon(me.rstore, 'refresh', function() { |
f97670f5 DM |
650 | set_button_status(); |
651 | }); | |
652 | } | |
653 | }); |