]> git.proxmox.com Git - pve-manager.git/blob - www/manager/qemu/HardwareView.js
4de9cc63aedb2d3048cfadcf1f7a861cd5a4a07c
[pve-manager.git] / www / manager / qemu / HardwareView.js
1 // fixme: howto avoid jslint type confusion?
2 /*jslint confusion: true */
3 Ext.define('PVE.qemu.HardwareView', {
4 extend: 'PVE.grid.ObjectGrid',
5 alias: ['widget.PVE.qemu.HardwareView'],
6
7 renderKey: function(key, metaData, record, rowIndex, colIndex, store) {
8 var me = this;
9 var rows = me.rows;
10 var rowdef = rows[key] || {};
11
12 if (rowdef.tdCls) {
13 metaData.tdCls = rowdef.tdCls;
14 if (rowdef.tdCls == 'pve-itype-icon-storage') {
15 if (record.data.value.match(/media=cdrom/)) {
16 metaData.tdCls = 'pve-itype-icon-cdrom';
17 return rowdef.cdheader;
18 }
19 }
20 }
21 return rowdef.header || key;
22 },
23
24 initComponent : function() {
25 var me = this;
26 var i, confid;
27
28 var nodename = me.pveSelNode.data.node;
29 if (!nodename) {
30 throw "no node name specified";
31 }
32
33 var vmid = me.pveSelNode.data.vmid;
34 if (!vmid) {
35 throw "no VM ID specified";
36 }
37
38 var caps = Ext.state.Manager.get('GuiCap');
39
40 var rows = {
41 memory: {
42 header: gettext('Memory'),
43 editor: caps.vms['VM.Config.Memory'] ? 'PVE.qemu.MemoryEdit' : undefined,
44 never_delete: true,
45 defaultValue: 512,
46 tdCls: 'pve-itype-icon-memory',
47 renderer: function(value, metaData, record) {
48 var balloon = me.getObjectValue('balloon');
49 if (balloon) {
50 return PVE.Utils.format_size(balloon*1024*1024) + "/" +
51 PVE.Utils.format_size(value*1024*1024);
52
53 }
54 return PVE.Utils.format_size(value*1024*1024);
55 }
56 },
57 sockets: {
58 header: gettext('Processors'),
59 never_delete: true,
60 editor: (caps.vms['VM.Config.CPU'] || caps.vms['VM.Config.HWType']) ?
61 'PVE.qemu.ProcessorEdit' : undefined,
62 tdCls: 'pve-itype-icon-processor',
63 defaultValue: 1,
64 renderer: function(value, metaData, record, rowIndex, colIndex, store) {
65 var model = me.getObjectValue('cpu');
66 var cores = me.getObjectValue('cores');
67 var res = '';
68 if (!cores || (cores <= 1)) {
69 res = value;
70 } else {
71 res = (value*cores) + ' (' + value + ' sockets, ' + cores + ' cores)';
72 }
73 if (model) {
74 res += ' [' + model + ']';
75 }
76 return res;
77 }
78 },
79 keyboard: {
80 header: gettext('Keyboard Layout'),
81 never_delete: true,
82 editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.KeyboardEdit' : undefined,
83 tdCls: 'pve-itype-icon-keyboard',
84 defaultValue: '',
85 renderer: PVE.Utils.render_kvm_language
86 },
87 vga: {
88 header: gettext('Display'),
89 editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.DisplayEdit' : undefined,
90 never_delete: true,
91 tdCls: 'pve-itype-icon-display',
92 defaultValue: '',
93 renderer: PVE.Utils.render_kvm_vga_driver
94 },
95 cores: {
96 visible: false
97 },
98 cpu: {
99 visible: false
100 },
101 balloon: {
102 visible: false
103 }
104 };
105
106 for (i = 0; i < 4; i++) {
107 confid = "ide" + i;
108 rows[confid] = {
109 group: 1,
110 tdCls: 'pve-itype-icon-storage',
111 editor: 'PVE.qemu.HDEdit',
112 never_delete: caps.vms['VM.Config.Disk'] ? false : true,
113 header: gettext('Hard Disk') + ' (' + confid +')',
114 cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
115 };
116 }
117 for (i = 0; i < 6; i++) {
118 confid = "sata" + i;
119 rows[confid] = {
120 group: 1,
121 tdCls: 'pve-itype-icon-storage',
122 editor: 'PVE.qemu.HDEdit',
123 never_delete: caps.vms['VM.Config.Disk'] ? false : true,
124 header: gettext('Hard Disk') + ' (' + confid +')',
125 cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
126 };
127 }
128 for (i = 0; i < 16; i++) {
129 confid = "scsi" + i;
130 rows[confid] = {
131 group: 1,
132 tdCls: 'pve-itype-icon-storage',
133 editor: 'PVE.qemu.HDEdit',
134 never_delete: caps.vms['VM.Config.Disk'] ? false : true,
135 header: gettext('Hard Disk') + ' (' + confid +')',
136 cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
137 };
138 }
139 for (i = 0; i < 16; i++) {
140 confid = "virtio" + i;
141 rows[confid] = {
142 group: 1,
143 tdCls: 'pve-itype-icon-storage',
144 editor: 'PVE.qemu.HDEdit',
145 never_delete: caps.vms['VM.Config.Disk'] ? false : true,
146 header: gettext('Hard Disk') + ' (' + confid +')',
147 cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
148 };
149 }
150 for (i = 0; i < 32; i++) {
151 confid = "net" + i;
152 rows[confid] = {
153 group: 2,
154 tdCls: 'pve-itype-icon-network',
155 editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.NetworkEdit' : undefined,
156 never_delete: caps.vms['VM.Config.Network'] ? false : true,
157 header: gettext('Network Device') + ' (' + confid +')'
158 };
159 }
160 for (i = 0; i < 8; i++) {
161 rows["unused" + i] = {
162 group: 3,
163 tdCls: 'pve-itype-icon-storage',
164 editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.HDEdit' : undefined,
165 header: gettext('Unused Disk') + ' ' + i
166 };
167 }
168
169 var sorterFn = function(rec1, rec2) {
170 var v1 = rec1.data.key;
171 var v2 = rec2.data.key;
172 var g1 = rows[v1].group || 0;
173 var g2 = rows[v2].group || 0;
174
175 return (g1 !== g2) ?
176 (g1 > g2 ? 1 : -1) : (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
177 };
178
179 var reload = function() {
180 me.rstore.load();
181 };
182
183 var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
184
185 var sm = Ext.create('Ext.selection.RowModel', {});
186
187 var run_editor = function() {
188 var rec = sm.getSelection()[0];
189 if (!rec) {
190 return;
191 }
192
193 var rowdef = rows[rec.data.key];
194 if (!rowdef.editor) {
195 return;
196 }
197
198 var editor = rowdef.editor;
199 if (rowdef.tdCls == 'pve-itype-icon-storage') {
200 if (rec.data.value.match(/media=cdrom/)) {
201 editor = 'PVE.qemu.CDEdit';
202 }
203 }
204
205 var win = Ext.create(editor, {
206 pveSelNode: me.pveSelNode,
207 confid: rec.data.key,
208 url: '/api2/extjs/' + baseurl
209 });
210
211 win.show();
212 win.on('destroy', reload);
213 };
214
215 var run_resize = function() {
216 var rec = sm.getSelection()[0];
217 if (!rec) {
218 return;
219 }
220
221 var rowdef = rows[rec.data.key];
222 if (!rowdef.editor) {
223 return;
224 }
225
226 var win = Ext.create('PVE.window.HDResize', {
227 disk: rec.data.key,
228 nodename: nodename,
229 vmid: vmid
230 });
231
232 win.show();
233
234 win.on('destroy', reload);
235 };
236
237 var run_move = function() {
238 var rec = sm.getSelection()[0];
239 if (!rec) {
240 return;
241 }
242
243 var rowdef = rows[rec.data.key];
244 if (!rowdef.editor) {
245 return;
246 }
247
248 var win = Ext.create('PVE.window.HDMove', {
249 disk: rec.data.key,
250 nodename: nodename,
251 vmid: vmid
252 });
253
254 win.show();
255
256 win.on('destroy', reload);
257 };
258
259 var edit_btn = new PVE.button.Button({
260 text: gettext('Edit'),
261 selModel: sm,
262 disabled: true,
263 enableFn: function(rec) {
264 if (!rec) {
265 return false;
266 }
267 var rowdef = rows[rec.data.key];
268 return !!rowdef.editor;
269 },
270 handler: run_editor
271 });
272
273 var resize_btn = new PVE.button.Button({
274 text: gettext('Resize disk'),
275 selModel: sm,
276 disabled: true,
277 enableFn: function(rec) {
278 if (!rec) {
279 return false;
280 }
281 var rowdef = rows[rec.data.key];
282 return rowdef.tdCls == 'pve-itype-icon-storage' && !rec.data.value.match(/media=cdrom/);
283 },
284 handler: run_resize
285 });
286
287
288 var move_btn = new PVE.button.Button({
289 text: gettext('Move disk'),
290 selModel: sm,
291 disabled: true,
292 enableFn: function(rec) {
293 if (!rec || rec.data.key.match(/^unused\d+/)) {
294 return false;
295 }
296 var rowdef = rows[rec.data.key];
297 return rowdef.tdCls == 'pve-itype-icon-storage' && !rec.data.value.match(/media=cdrom/)
298 },
299 handler: run_move
300 });
301
302 var remove_btn = new PVE.button.Button({
303 text: gettext('Remove'),
304 selModel: sm,
305 disabled: true,
306 dangerous: true,
307 confirmMsg: function(rec) {
308 var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
309 "'" + me.renderKey(rec.data.key, {}, rec) + "'");
310 if (rec.data.key.match(/^unused\d+$/)) {
311 msg += " " + gettext('This will permanently erase all image data.');
312 }
313
314 return msg;
315 },
316 enableFn: function(rec) {
317 if (!rec) {
318 return false;
319 }
320 var rowdef = rows[rec.data.key];
321
322 return rowdef.never_delete !== true;
323 },
324 handler: function(b, e, rec) {
325 PVE.Utils.API2Request({
326 url: '/api2/extjs/' + baseurl,
327 waitMsgTarget: me,
328 method: 'PUT',
329 params: {
330 'delete': rec.data.key
331 },
332 callback: function() {
333 reload();
334 },
335 failure: function (response, opts) {
336 Ext.Msg.alert('Error',response.htmlStatus);
337 }
338 });
339 }
340 });
341
342 Ext.applyIf(me, {
343 url: '/api2/json/' + baseurl,
344 selModel: sm,
345 cwidth1: 170,
346 tbar: [
347 {
348 text: gettext('Add'),
349 menu: new Ext.menu.Menu({
350 items: [
351 {
352 text: gettext('Hard Disk'),
353 iconCls: 'pve-itype-icon-storage',
354 disabled: !caps.vms['VM.Config.Disk'],
355 handler: function() {
356 var win = Ext.create('PVE.qemu.HDEdit', {
357 url: '/api2/extjs/' + baseurl,
358 pveSelNode: me.pveSelNode
359 });
360 win.on('destroy', reload);
361 win.show();
362 }
363 },
364 {
365 text: gettext('CD/DVD Drive'),
366 iconCls: 'pve-itype-icon-cdrom',
367 disabled: !caps.vms['VM.Config.Disk'],
368 handler: function() {
369 var win = Ext.create('PVE.qemu.CDEdit', {
370 url: '/api2/extjs/' + baseurl,
371 pveSelNode: me.pveSelNode
372 });
373 win.on('destroy', reload);
374 win.show();
375 }
376 },
377 {
378 text: gettext('Network Device'),
379 iconCls: 'pve-itype-icon-network',
380 disabled: !caps.vms['VM.Config.Network'],
381 handler: function() {
382 var win = Ext.create('PVE.qemu.NetworkEdit', {
383 url: '/api2/extjs/' + baseurl,
384 pveSelNode: me.pveSelNode
385 });
386 win.on('destroy', reload);
387 win.show();
388 }
389 }
390 ]
391 })
392 },
393 remove_btn,
394 edit_btn,
395 resize_btn,
396 move_btn
397 ],
398 rows: rows,
399 sorterFn: sorterFn,
400 listeners: {
401 show: reload,
402 itemdblclick: run_editor
403 }
404 });
405
406 me.callParent();
407 }
408 });