]> git.proxmox.com Git - proxmox-widget-toolkit.git/blame - src/node/NetworkView.js
ui: network: add columns for vlan-id and vlan-raw-device
[proxmox-widget-toolkit.git] / src / node / NetworkView.js
CommitLineData
a58001dd
DM
1Ext.define('proxmox-networks', {
2 extend: 'Ext.data.Model',
3 fields: [
82b8bfb0
TL
4 'active',
5 'address',
6 'address6',
7 'autostart',
8 'bridge_ports',
9 'cidr',
10 'cidr6',
11 'comments',
12 'gateway',
13 'gateway6',
14 'iface',
15 'netmask',
16 'netmask6',
17 'slaves',
18 'type',
3d886f94
AL
19 'vlan-id',
20 'vlan-raw-device',
a58001dd 21 ],
01031528 22 idProperty: 'iface',
a58001dd
DM
23});
24
25Ext.define('Proxmox.node.NetworkView', {
26 extend: 'Ext.panel.Panel',
27
28 alias: ['widget.proxmoxNodeNetworkView'],
29
7c0e4c25
DC
30 // defines what types of network devices we want to create
31 // order is always the same
8aefd47c 32 types: ['bridge', 'bond', 'vlan', 'ovs'],
7c0e4c25 33
21cd6c09
DC
34 showApplyBtn: false,
35
01031528 36 initComponent: function() {
05a977a2 37 let me = this;
a58001dd
DM
38
39 if (!me.nodename) {
40 throw "no node name specified";
41 }
42
05a977a2 43 let baseUrl = '/nodes/' + me.nodename + '/network';
a58001dd 44
05a977a2 45 let store = Ext.create('Ext.data.Store', {
a58001dd
DM
46 model: 'proxmox-networks',
47 proxy: {
48 type: 'proxmox',
01031528 49 url: '/api2/json' + baseUrl,
a58001dd
DM
50 },
51 sorters: [
52 {
01031528
TL
53 property: 'iface',
54 direction: 'ASC',
55 },
56 ],
a58001dd
DM
57 });
58
05a977a2
TL
59 let reload = function() {
60 let changeitem = me.down('#changes');
61 let apply_btn = me.down('#apply');
62 let revert_btn = me.down('#revert');
a58001dd
DM
63 Proxmox.Utils.API2Request({
64 url: baseUrl,
65 failure: function(response, opts) {
a58001dd 66 store.loadData({});
b81cf173
DM
67 Proxmox.Utils.setErrorMask(me, response.htmlStatus);
68 changeitem.update('');
89f57452 69 changeitem.setHidden(true);
a58001dd
DM
70 },
71 success: function(response, opts) {
05a977a2 72 let result = Ext.decode(response.responseText);
a58001dd 73 store.loadData(result.data);
05a977a2 74 let changes = result.changes;
a58001dd
DM
75 if (changes === undefined || changes === '') {
76 changes = gettext("No changes");
89f57452 77 changeitem.setHidden(true);
21cd6c09 78 apply_btn.setDisabled(true);
03e93db5 79 revert_btn.setDisabled(true);
89f57452
DM
80 } else {
81 changeitem.update("<pre>" + Ext.htmlEncode(changes) + "</pre>");
82 changeitem.setHidden(false);
21cd6c09 83 apply_btn.setDisabled(false);
03e93db5 84 revert_btn.setDisabled(false);
a58001dd 85 }
01031528 86 },
a58001dd
DM
87 });
88 };
89
05a977a2
TL
90 let run_editor = function() {
91 let grid = me.down('gridpanel');
92 let sm = grid.getSelectionModel();
93 let rec = sm.getSelection()[0];
a58001dd
DM
94 if (!rec) {
95 return;
96 }
97
05a977a2 98 let win = Ext.create('Proxmox.node.NetworkEdit', {
a58001dd
DM
99 nodename: me.nodename,
100 iface: rec.data.iface,
01031528 101 iftype: rec.data.type,
a58001dd
DM
102 });
103 win.show();
104 win.on('destroy', reload);
105 };
106
05a977a2 107 let edit_btn = new Ext.Button({
a58001dd
DM
108 text: gettext('Edit'),
109 disabled: true,
01031528 110 handler: run_editor,
a58001dd
DM
111 });
112
05a977a2 113 let del_btn = new Ext.Button({
a58001dd
DM
114 text: gettext('Remove'),
115 disabled: true,
01031528 116 handler: function() {
05a977a2
TL
117 let grid = me.down('gridpanel');
118 let sm = grid.getSelectionModel();
119 let rec = sm.getSelection()[0];
a58001dd
DM
120 if (!rec) {
121 return;
122 }
123
05a977a2 124 let iface = rec.data.iface;
a58001dd
DM
125
126 Proxmox.Utils.API2Request({
127 url: baseUrl + '/' + iface,
128 method: 'DELETE',
129 waitMsgTarget: me,
130 callback: function() {
131 reload();
132 },
133 failure: function(response, opts) {
134 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
01031528 135 },
a58001dd 136 });
01031528 137 },
a58001dd
DM
138 });
139
05a977a2 140 let apply_btn = Ext.create('Proxmox.button.Button', {
21cd6c09
DC
141 text: gettext('Apply Configuration'),
142 itemId: 'apply',
143 disabled: true,
2877ddea 144 confirmMsg: 'Do you want to apply pending network changes?',
21cd6c09
DC
145 hidden: !me.showApplyBtn,
146 handler: function() {
147 Proxmox.Utils.API2Request({
148 url: baseUrl,
149 method: 'PUT',
150 waitMsgTarget: me,
151 success: function(response, opts) {
05a977a2 152 let upid = response.result.data;
21cd6c09 153
05a977a2 154 let win = Ext.create('Proxmox.window.TaskProgress', {
21cd6c09 155 taskDone: reload,
01031528 156 upid: upid,
21cd6c09
DC
157 });
158 win.show();
159 },
160 failure: function(response, opts) {
161 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
01031528 162 },
21cd6c09 163 });
01031528 164 },
21cd6c09
DC
165 });
166
05a977a2
TL
167 let set_button_status = function() {
168 let grid = me.down('gridpanel');
169 let sm = grid.getSelectionModel();
170 let rec = sm.getSelection()[0];
a58001dd
DM
171
172 edit_btn.setDisabled(!rec);
173 del_btn.setDisabled(!rec);
174 };
175
05a977a2 176 let render_ports = function(value, metaData, record) {
a58001dd
DM
177 if (value === 'bridge') {
178 return record.data.bridge_ports;
179 } else if (value === 'bond') {
180 return record.data.slaves;
181 } else if (value === 'OVSBridge') {
182 return record.data.ovs_ports;
183 } else if (value === 'OVSBond') {
184 return record.data.ovs_bonds;
185 }
05a977a2 186 return '';
a58001dd
DM
187 };
188
05a977a2
TL
189 let find_next_iface_id = function(prefix) {
190 let next;
a58001dd
DM
191 for (next = 0; next <= 9999; next++) {
192 if (!store.getById(prefix + next.toString())) {
193 break;
194 }
195 }
196 return prefix + next.toString();
197 };
198
05a977a2 199 let menu_items = [];
7c0e4c25
DC
200
201 if (me.types.indexOf('bridge') !== -1) {
202 menu_items.push({
203 text: Proxmox.Utils.render_network_iface_type('bridge'),
204 handler: function() {
05a977a2 205 let win = Ext.create('Proxmox.node.NetworkEdit', {
7c0e4c25
DC
206 nodename: me.nodename,
207 iftype: 'bridge',
25f37cbf
TL
208 iface_default: find_next_iface_id('vmbr'),
209 onlineHelp: 'sysadmin_network_configuration',
7c0e4c25
DC
210 });
211 win.on('destroy', reload);
212 win.show();
01031528 213 },
7c0e4c25
DC
214 });
215 }
216
217 if (me.types.indexOf('bond') !== -1) {
218 menu_items.push({
219 text: Proxmox.Utils.render_network_iface_type('bond'),
220 handler: function() {
05a977a2 221 let win = Ext.create('Proxmox.node.NetworkEdit', {
7c0e4c25
DC
222 nodename: me.nodename,
223 iftype: 'bond',
25f37cbf
TL
224 iface_default: find_next_iface_id('bond'),
225 onlineHelp: 'sysadmin_network_configuration',
7c0e4c25
DC
226 });
227 win.on('destroy', reload);
228 win.show();
01031528 229 },
7c0e4c25
DC
230 });
231 }
232
8aefd47c
AD
233 if (me.types.indexOf('vlan') !== -1) {
234 menu_items.push({
235 text: Proxmox.Utils.render_network_iface_type('vlan'),
236 handler: function() {
05a977a2 237 let win = Ext.create('Proxmox.node.NetworkEdit', {
8aefd47c
AD
238 nodename: me.nodename,
239 iftype: 'vlan',
705f92a1 240 iface_default: find_next_iface_id('vlan'),
25f37cbf 241 onlineHelp: 'sysadmin_network_configuration',
8aefd47c
AD
242 });
243 win.on('destroy', reload);
244 win.show();
01031528 245 },
8aefd47c
AD
246 });
247 }
248
7c0e4c25
DC
249 if (me.types.indexOf('ovs') !== -1) {
250 if (menu_items.length > 0) {
251 menu_items.push({ xtype: 'menuseparator' });
252 }
253
254 menu_items.push(
255 {
256 text: Proxmox.Utils.render_network_iface_type('OVSBridge'),
257 handler: function() {
05a977a2 258 let win = Ext.create('Proxmox.node.NetworkEdit', {
7c0e4c25
DC
259 nodename: me.nodename,
260 iftype: 'OVSBridge',
01031528 261 iface_default: find_next_iface_id('vmbr'),
7c0e4c25
DC
262 });
263 win.on('destroy', reload);
264 win.show();
01031528 265 },
7c0e4c25
DC
266 },
267 {
268 text: Proxmox.Utils.render_network_iface_type('OVSBond'),
269 handler: function() {
05a977a2 270 let win = Ext.create('Proxmox.node.NetworkEdit', {
7c0e4c25
DC
271 nodename: me.nodename,
272 iftype: 'OVSBond',
01031528 273 iface_default: find_next_iface_id('bond'),
7c0e4c25
DC
274 });
275 win.on('destroy', reload);
276 win.show();
01031528 277 },
7c0e4c25
DC
278 },
279 {
280 text: Proxmox.Utils.render_network_iface_type('OVSIntPort'),
281 handler: function() {
05a977a2 282 let win = Ext.create('Proxmox.node.NetworkEdit', {
7c0e4c25 283 nodename: me.nodename,
01031528 284 iftype: 'OVSIntPort',
7c0e4c25
DC
285 });
286 win.on('destroy', reload);
287 win.show();
01031528
TL
288 },
289 },
7c0e4c25
DC
290 );
291 }
292
05a977a2 293 let renderer_generator = function(fieldname) {
d0c2b878 294 return function(val, metaData, rec) {
05a977a2 295 let tmp = [];
d0c2b878
DC
296 if (rec.data[fieldname]) {
297 tmp.push(rec.data[fieldname]);
298 }
299 if (rec.data[fieldname + '6']) {
300 tmp.push(rec.data[fieldname + '6']);
301 }
302 return tmp.join('<br>') || '';
303 };
304 };
305
a58001dd
DM
306 Ext.apply(me, {
307 layout: 'border',
308 tbar: [
309 {
310 text: gettext('Create'),
7c0e4c25 311 menu: {
a58001dd 312 plain: true,
01031528
TL
313 items: menu_items,
314 },
1cf31d6b 315 }, '-',
a58001dd
DM
316 {
317 text: gettext('Revert'),
03e93db5 318 itemId: 'revert',
a58001dd
DM
319 handler: function() {
320 Proxmox.Utils.API2Request({
321 url: baseUrl,
322 method: 'DELETE',
323 waitMsgTarget: me,
324 callback: function() {
325 reload();
326 },
327 failure: function(response, opts) {
328 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
01031528 329 },
a58001dd 330 });
01031528 331 },
a58001dd
DM
332 },
333 edit_btn,
21cd6c09 334 del_btn,
1cf31d6b 335 '-',
01031528 336 apply_btn,
a58001dd
DM
337 ],
338 items: [
339 {
340 xtype: 'gridpanel',
341 stateful: true,
342 stateId: 'grid-node-network',
343 store: store,
344 region: 'center',
345 border: false,
346 columns: [
347 {
348 header: gettext('Name'),
a58001dd 349 sortable: true,
01031528 350 dataIndex: 'iface',
a58001dd
DM
351 },
352 {
353 header: gettext('Type'),
a58001dd 354 sortable: true,
869439b1 355 width: 120,
a58001dd 356 renderer: Proxmox.Utils.render_network_iface_type,
01031528 357 dataIndex: 'type',
a58001dd
DM
358 },
359 {
360 xtype: 'booleancolumn',
361 header: gettext('Active'),
362 width: 80,
363 sortable: true,
364 dataIndex: 'active',
9b575917
WL
365 trueText: Proxmox.Utils.yesText,
366 falseText: Proxmox.Utils.noText,
367 undefinedText: Proxmox.Utils.noText,
a58001dd
DM
368 },
369 {
370 xtype: 'booleancolumn',
371 header: gettext('Autostart'),
372 width: 80,
373 sortable: true,
374 dataIndex: 'autostart',
9b575917
WL
375 trueText: Proxmox.Utils.yesText,
376 falseText: Proxmox.Utils.noText,
01031528 377 undefinedText: Proxmox.Utils.noText,
a58001dd 378 },
8947a4fc
WL
379 {
380 xtype: 'booleancolumn',
381 header: gettext('VLAN aware'),
382 width: 80,
383 sortable: true,
384 dataIndex: 'bridge_vlan_aware',
385 trueText: Proxmox.Utils.yesText,
386 falseText: Proxmox.Utils.noText,
01031528 387 undefinedText: Proxmox.Utils.noText,
8947a4fc 388 },
a58001dd
DM
389 {
390 header: gettext('Ports/Slaves'),
391 dataIndex: 'type',
01031528 392 renderer: render_ports,
a58001dd 393 },
211bdf93
DC
394 {
395 header: gettext('Bond Mode'),
396 dataIndex: 'bond_mode',
397 renderer: Proxmox.Utils.render_bond_mode,
398 },
399 {
400 header: gettext('Hash Policy'),
401 hidden: true,
402 dataIndex: 'bond_xmit_hash_policy',
403 },
a58001dd
DM
404 {
405 header: gettext('IP address'),
406 sortable: true,
869439b1 407 width: 120,
4211996a 408 hidden: true,
a58001dd 409 dataIndex: 'address',
d0c2b878 410 renderer: renderer_generator('address'),
a58001dd
DM
411 },
412 {
413 header: gettext('Subnet mask'),
869439b1 414 width: 120,
a58001dd 415 sortable: true,
4211996a 416 hidden: true,
d0c2b878
DC
417 dataIndex: 'netmask',
418 renderer: renderer_generator('netmask'),
419 },
420 {
421 header: gettext('CIDR'),
f4d366dc 422 width: 150,
d0c2b878
DC
423 sortable: true,
424 dataIndex: 'cidr',
425 renderer: renderer_generator('cidr'),
a58001dd
DM
426 },
427 {
428 header: gettext('Gateway'),
f4d366dc 429 width: 150,
a58001dd
DM
430 sortable: true,
431 dataIndex: 'gateway',
d0c2b878 432 renderer: renderer_generator('gateway'),
a58001dd 433 },
3d886f94
AL
434 {
435 header: gettext('VLAN ID'),
436 hidden: true,
437 sortable: true,
438 dataIndex: 'vlan-id',
439 },
440 {
441 header: gettext('VLAN raw device'),
442 hidden: true,
443 sortable: true,
444 dataIndex: 'vlan-raw-device',
445 },
a58001dd
DM
446 {
447 header: gettext('Comment'),
448 dataIndex: 'comments',
869439b1 449 flex: 1,
01031528
TL
450 renderer: Ext.String.htmlEncode,
451 },
a58001dd
DM
452 ],
453 listeners: {
454 selectionchange: set_button_status,
01031528
TL
455 itemdblclick: run_editor,
456 },
a58001dd
DM
457 },
458 {
459 border: false,
460 region: 'south',
461 autoScroll: true,
89f57452 462 hidden: true,
a58001dd
DM
463 itemId: 'changes',
464 tbar: [
465 gettext('Pending changes') + ' (' +
01031528 466 gettext("Either reboot or use 'Apply Configuration' (needs ifupdown2) to activate") + ')',
a58001dd
DM
467 ],
468 split: true,
469 bodyPadding: 5,
470 flex: 0.6,
01031528
TL
471 html: gettext("No changes"),
472 },
a58001dd 473 ],
a58001dd
DM
474 });
475
476 me.callParent();
1a68e95d 477 reload();
01031528 478 },
a58001dd 479});