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