]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/lxc/Network.js
ui: lxc/net: s/i.e./e.g./ and transform to emptyText
[pve-manager.git] / www / manager6 / lxc / Network.js
1 Ext.define('PVE.lxc.NetworkInputPanel', {
2 extend: 'Proxmox.panel.InputPanel',
3 alias: 'widget.pveLxcNetworkInputPanel',
4
5 insideWizard: false,
6
7 onlineHelp: 'pct_container_network',
8
9 setNodename: function(nodename) {
10 var me = this;
11
12 if (!nodename || (me.nodename === nodename)) {
13 return;
14 }
15
16 me.nodename = nodename;
17
18 var bridgesel = me.query("[isFormField][name=bridge]")[0];
19 bridgesel.setNodename(nodename);
20 },
21
22 onGetValues: function(values) {
23 var me = this;
24
25 var id;
26 if (me.isCreate) {
27 id = values.id;
28 delete values.id;
29 } else {
30 id = me.ifname;
31 }
32
33 if (!id) {
34 return {};
35 }
36
37 var newdata = {};
38
39 if (values.ipv6mode !== 'static') {
40 values.ip6 = values.ipv6mode;
41 }
42 if (values.ipv4mode !== 'static') {
43 values.ip = values.ipv4mode;
44 }
45 newdata[id] = PVE.Parser.printLxcNetwork(values);
46 return newdata;
47 },
48
49 initComponent : function() {
50 var me = this;
51
52 var cdata = {};
53
54 if (me.insideWizard) {
55 me.ifname = 'net0';
56 cdata.name = 'eth0';
57 me.dataCache = {};
58 }
59
60 if (!me.dataCache) {
61 throw "no dataCache specified";
62 }
63
64 if (!me.isCreate) {
65 if (!me.ifname) {
66 throw "no interface name specified";
67 }
68 if (!me.dataCache[me.ifname]) {
69 throw "no such interface '" + me.ifname + "'";
70 }
71
72 cdata = PVE.Parser.parseLxcNetwork(me.dataCache[me.ifname]);
73 }
74
75 var i;
76 for (i = 0; i < 10; i++) {
77 if (me.isCreate && !me.dataCache['net'+i.toString()]) {
78 me.ifname = 'net' + i.toString();
79 break;
80 }
81 }
82
83 var idselector = {
84 xtype: 'hidden',
85 name: 'id',
86 value: me.ifname
87 };
88
89 me.column1 = [
90 idselector,
91 {
92 xtype: 'textfield',
93 name: 'name',
94 fieldLabel: gettext('Name'),
95 emptyText: '(e.g., eth0)',
96 allowBlank: false,
97 value: cdata.name,
98 validator: function(value) {
99 var result = '';
100 Ext.Object.each(me.dataCache, function(key, netstr) {
101 if (!key.match(/^net\d+/) || key === me.ifname) {
102 return; // continue
103 }
104 var net = PVE.Parser.parseLxcNetwork(netstr);
105 if (net.name === value) {
106 result = "interface name already in use";
107 return false;
108 }
109 });
110 if (result !== '') {
111 return result;
112 }
113 // validator can return bool/string
114 /*jslint confusion:true*/
115 return true;
116 }
117 },
118 {
119 xtype: 'textfield',
120 name: 'hwaddr',
121 fieldLabel: gettext('MAC address'),
122 vtype: 'MacAddress',
123 value: cdata.hwaddr,
124 allowBlank: true,
125 emptyText: 'auto'
126 },
127 {
128 xtype: 'PVE.form.BridgeSelector',
129 name: 'bridge',
130 nodename: me.nodename,
131 fieldLabel: gettext('Bridge'),
132 value: cdata.bridge,
133 allowBlank: false
134 },
135 {
136 xtype: 'pveVlanField',
137 name: 'tag',
138 value: cdata.tag
139 },
140 {
141 xtype: 'numberfield',
142 name: 'rate',
143 fieldLabel: gettext('Rate limit') + ' (MB/s)',
144 minValue: 0,
145 maxValue: 10*1024,
146 value: cdata.rate,
147 emptyText: 'unlimited',
148 allowBlank: true
149 },
150 {
151 xtype: 'proxmoxcheckbox',
152 fieldLabel: gettext('Firewall'),
153 name: 'firewall',
154 checked: cdata.firewall
155 }
156 ];
157
158 var dhcp4 = (cdata.ip === 'dhcp');
159 if (dhcp4) {
160 cdata.ip = '';
161 cdata.gw = '';
162 }
163
164 var auto6 = (cdata.ip6 === 'auto');
165 var dhcp6 = (cdata.ip6 === 'dhcp');
166 if (auto6 || dhcp6) {
167 cdata.ip6 = '';
168 cdata.gw6 = '';
169 }
170
171 me.column2 = [
172 {
173 layout: {
174 type: 'hbox',
175 align: 'middle'
176 },
177 border: false,
178 margin: '0 0 5 0',
179 items: [
180 {
181 xtype: 'label',
182 text: 'IPv4:' // do not localize
183 },
184 {
185 xtype: 'radiofield',
186 boxLabel: gettext('Static'),
187 name: 'ipv4mode',
188 inputValue: 'static',
189 checked: !dhcp4,
190 margin: '0 0 0 10',
191 listeners: {
192 change: function(cb, value) {
193 me.down('field[name=ip]').setDisabled(!value);
194 me.down('field[name=gw]').setDisabled(!value);
195 }
196 }
197 },
198 {
199 xtype: 'radiofield',
200 boxLabel: 'DHCP', // do not localize
201 name: 'ipv4mode',
202 inputValue: 'dhcp',
203 checked: dhcp4,
204 margin: '0 0 0 10'
205 }
206 ]
207 },
208 {
209 xtype: 'textfield',
210 name: 'ip',
211 vtype: 'IPCIDRAddress',
212 value: cdata.ip,
213 disabled: dhcp4,
214 fieldLabel: 'IPv4/CIDR' // do not localize
215 },
216 {
217 xtype: 'textfield',
218 name: 'gw',
219 value: cdata.gw,
220 vtype: 'IPAddress',
221 disabled: dhcp4,
222 fieldLabel: gettext('Gateway') + ' (IPv4)',
223 margin: '0 0 3 0' // override bottom margin to account for the menuseparator
224 },
225 {
226 xtype: 'menuseparator',
227 height: '3',
228 margin: '0'
229 },
230 {
231 layout: {
232 type: 'hbox',
233 align: 'middle'
234 },
235 border: false,
236 margin: '0 0 5 0',
237 items: [
238 {
239 xtype: 'label',
240 text: 'IPv6:' // do not localize
241 },
242 {
243 xtype: 'radiofield',
244 boxLabel: gettext('Static'),
245 name: 'ipv6mode',
246 inputValue: 'static',
247 checked: !(auto6 || dhcp6),
248 margin: '0 0 0 10',
249 listeners: {
250 change: function(cb, value) {
251 me.down('field[name=ip6]').setDisabled(!value);
252 me.down('field[name=gw6]').setDisabled(!value);
253 }
254 }
255 },
256 {
257 xtype: 'radiofield',
258 boxLabel: 'DHCP', // do not localize
259 name: 'ipv6mode',
260 inputValue: 'dhcp',
261 checked: dhcp6,
262 margin: '0 0 0 10'
263 },
264 {
265 xtype: 'radiofield',
266 boxLabel: 'SLAAC', // do not localize
267 name: 'ipv6mode',
268 inputValue: 'auto',
269 checked: auto6,
270 margin: '0 0 0 10'
271 }
272 ]
273 },
274 {
275 xtype: 'textfield',
276 name: 'ip6',
277 value: cdata.ip6,
278 vtype: 'IP6CIDRAddress',
279 disabled: (dhcp6 || auto6),
280 fieldLabel: 'IPv6/CIDR' // do not localize
281 },
282 {
283 xtype: 'textfield',
284 name: 'gw6',
285 vtype: 'IP6Address',
286 value: cdata.gw6,
287 disabled: (dhcp6 || auto6),
288 fieldLabel: gettext('Gateway') + ' (IPv6)'
289 }
290 ];
291
292 me.callParent();
293 }
294 });
295
296
297 Ext.define('PVE.lxc.NetworkEdit', {
298 extend: 'Proxmox.window.Edit',
299
300 isAdd: true,
301
302 initComponent : function() {
303 var me = this;
304
305 if (!me.dataCache) {
306 throw "no dataCache specified";
307 }
308
309 if (!me.nodename) {
310 throw "no node name specified";
311 }
312
313 var ipanel = Ext.create('PVE.lxc.NetworkInputPanel', {
314 ifname: me.ifname,
315 nodename: me.nodename,
316 dataCache: me.dataCache,
317 isCreate: me.isCreate
318 });
319
320 Ext.apply(me, {
321 subject: gettext('Network Device') + ' (veth)',
322 digest: me.dataCache.digest,
323 items: [ ipanel ]
324 });
325
326 me.callParent();
327 }
328 });
329
330 Ext.define('PVE.lxc.NetworkView', {
331 extend: 'Ext.grid.GridPanel',
332 alias: 'widget.pveLxcNetworkView',
333
334 onlineHelp: 'pct_container_network',
335
336 dataCache: {}, // used to store result of last load
337
338 stateful: true,
339 stateId: 'grid-lxc-network',
340
341 load: function() {
342 var me = this;
343
344 Proxmox.Utils.setErrorMask(me, true);
345
346 Proxmox.Utils.API2Request({
347 url: me.url,
348 failure: function(response, opts) {
349 Proxmox.Utils.setErrorMask(me, gettext('Error') + ': ' + response.htmlStatus);
350 },
351 success: function(response, opts) {
352 Proxmox.Utils.setErrorMask(me, false);
353 var result = Ext.decode(response.responseText);
354 var data = result.data || {};
355 me.dataCache = data;
356 var records = [];
357 Ext.Object.each(data, function(key, value) {
358 if (!key.match(/^net\d+/)) {
359 return; // continue
360 }
361 var net = PVE.Parser.parseLxcNetwork(value);
362 net.id = key;
363 records.push(net);
364 });
365 me.store.loadData(records);
366 me.down('button[name=addButton]').setDisabled((records.length >= 10));
367 }
368 });
369 },
370
371 initComponent : function() {
372 var me = this;
373
374 var nodename = me.pveSelNode.data.node;
375 if (!nodename) {
376 throw "no node name specified";
377 }
378
379 var vmid = me.pveSelNode.data.vmid;
380 if (!vmid) {
381 throw "no VM ID specified";
382 }
383
384 var caps = Ext.state.Manager.get('GuiCap');
385
386 me.url = '/nodes/' + nodename + '/lxc/' + vmid + '/config';
387
388 var store = new Ext.data.Store({
389 model: 'pve-lxc-network',
390 sorters: [
391 {
392 property : 'id',
393 direction: 'ASC'
394 }
395 ]
396 });
397
398 var sm = Ext.create('Ext.selection.RowModel', {});
399
400 var remove_btn = new Proxmox.button.Button({
401 text: gettext('Remove'),
402 disabled: true,
403 selModel: sm,
404 enableFn: function(rec) {
405 return !!caps.vms['VM.Config.Network'];
406 },
407 confirmMsg: function (rec) {
408 return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
409 "'" + rec.data.id + "'");
410 },
411 handler: function(btn, event, rec) {
412 Proxmox.Utils.API2Request({
413 url: me.url,
414 waitMsgTarget: me,
415 method: 'PUT',
416 params: { 'delete': rec.data.id, digest: me.dataCache.digest },
417 callback: function() {
418 me.load();
419 },
420 failure: function (response, opts) {
421 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
422 }
423 });
424 }
425 });
426
427 var run_editor = function() {
428 var rec = sm.getSelection()[0];
429 if (!rec) {
430 return;
431 }
432
433 if (!caps.vms['VM.Config.Network']) {
434 return false;
435 }
436
437 var win = Ext.create('PVE.lxc.NetworkEdit', {
438 url: me.url,
439 nodename: nodename,
440 dataCache: me.dataCache,
441 ifname: rec.data.id
442 });
443 win.on('destroy', me.load, me);
444 win.show();
445 };
446
447 var edit_btn = new Proxmox.button.Button({
448 text: gettext('Edit'),
449 selModel: sm,
450 disabled: true,
451 enableFn: function(rec) {
452 if (!caps.vms['VM.Config.Network']) {
453 return false;
454 }
455 return true;
456 },
457 handler: run_editor
458 });
459
460 Ext.apply(me, {
461 store: store,
462 selModel: sm,
463 tbar: [
464 {
465 text: gettext('Add'),
466 name: 'addButton',
467 disabled: !caps.vms['VM.Config.Network'],
468 handler: function() {
469 var win = Ext.create('PVE.lxc.NetworkEdit', {
470 url: me.url,
471 nodename: nodename,
472 isCreate: true,
473 dataCache: me.dataCache
474 });
475 win.on('destroy', me.load, me);
476 win.show();
477 }
478 },
479 remove_btn,
480 edit_btn
481 ],
482 columns: [
483 {
484 header: 'ID',
485 width: 50,
486 dataIndex: 'id'
487 },
488 {
489 header: gettext('Name'),
490 width: 80,
491 dataIndex: 'name'
492 },
493 {
494 header: gettext('Bridge'),
495 width: 80,
496 dataIndex: 'bridge'
497 },
498 {
499 header: gettext('Firewall'),
500 width: 80,
501 dataIndex: 'firewall',
502 renderer: Proxmox.Utils.format_boolean
503 },
504 {
505 header: gettext('VLAN Tag'),
506 width: 80,
507 dataIndex: 'tag'
508 },
509 {
510 header: gettext('MAC address'),
511 width: 110,
512 dataIndex: 'hwaddr'
513 },
514 {
515 header: gettext('IP address'),
516 width: 150,
517 dataIndex: 'ip',
518 renderer: function(value, metaData, rec) {
519 if (rec.data.ip && rec.data.ip6) {
520 return rec.data.ip + "<br>" + rec.data.ip6;
521 } else if (rec.data.ip6) {
522 return rec.data.ip6;
523 } else {
524 return rec.data.ip;
525 }
526 }
527 },
528 {
529 header: gettext('Gateway'),
530 width: 150,
531 dataIndex: 'gw',
532 renderer: function(value, metaData, rec) {
533 if (rec.data.gw && rec.data.gw6) {
534 return rec.data.gw + "<br>" + rec.data.gw6;
535 } else if (rec.data.gw6) {
536 return rec.data.gw6;
537 } else {
538 return rec.data.gw;
539 }
540 }
541 }
542 ],
543 listeners: {
544 activate: me.load,
545 itemdblclick: run_editor
546 }
547 });
548
549 me.callParent();
550 }
551 }, function() {
552
553 Ext.define('pve-lxc-network', {
554 extend: "Ext.data.Model",
555 proxy: { type: 'memory' },
556 fields: [ 'id', 'name', 'hwaddr', 'bridge',
557 'ip', 'gw', 'ip6', 'gw6', 'tag', 'firewall' ]
558 });
559
560 });
561