]> git.proxmox.com Git - proxmox-widget-toolkit.git/blame - src/node/NetworkView.js
node network view: code style modernization
[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
99f3e147 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
13220ad1
TL
98 Ext.create('Proxmox.node.NetworkEdit', {
99 autoShow: true,
a58001dd
DM
100 nodename: me.nodename,
101 iface: rec.data.iface,
01031528 102 iftype: rec.data.type,
13220ad1
TL
103 listeners: {
104 destroy: () => reload(),
105 },
a58001dd 106 });
a58001dd
DM
107 };
108
05a977a2 109 let edit_btn = new Ext.Button({
a58001dd
DM
110 text: gettext('Edit'),
111 disabled: true,
01031528 112 handler: run_editor,
a58001dd
DM
113 });
114
bb5511d5 115 let sm = Ext.create('Ext.selection.RowModel', {});
a58001dd 116
bb5511d5
TL
117 let del_btn = new Proxmox.button.StdRemoveButton({
118 selModel: sm,
119 getUrl: ({ data }) => `${baseUrl}/${data.iface}`,
120 callback: () => reload(),
a58001dd
DM
121 });
122
05a977a2 123 let apply_btn = Ext.create('Proxmox.button.Button', {
21cd6c09
DC
124 text: gettext('Apply Configuration'),
125 itemId: 'apply',
126 disabled: true,
2877ddea 127 confirmMsg: 'Do you want to apply pending network changes?',
21cd6c09
DC
128 hidden: !me.showApplyBtn,
129 handler: function() {
130 Proxmox.Utils.API2Request({
131 url: baseUrl,
132 method: 'PUT',
133 waitMsgTarget: me,
13220ad1
TL
134 success: function({ result }, opts) {
135 Ext.create('Proxmox.window.TaskProgress', {
136 autoShow: true,
21cd6c09 137 taskDone: reload,
13220ad1 138 upid: result.data,
21cd6c09 139 });
01031528 140 },
13220ad1 141 failure: response => Ext.Msg.alert(gettext('Error'), response.htmlStatus),
21cd6c09 142 });
01031528 143 },
21cd6c09
DC
144 });
145
05a977a2 146 let set_button_status = function() {
05a977a2 147 let rec = sm.getSelection()[0];
a58001dd
DM
148
149 edit_btn.setDisabled(!rec);
150 del_btn.setDisabled(!rec);
151 };
152
05a977a2
TL
153 let find_next_iface_id = function(prefix) {
154 let next;
a58001dd
DM
155 for (next = 0; next <= 9999; next++) {
156 if (!store.getById(prefix + next.toString())) {
157 break;
158 }
159 }
160 return prefix + next.toString();
161 };
162
05a977a2 163 let menu_items = [];
7c0e4c25
DC
164
165 if (me.types.indexOf('bridge') !== -1) {
166 menu_items.push({
167 text: Proxmox.Utils.render_network_iface_type('bridge'),
168 handler: function() {
05a977a2 169 let win = Ext.create('Proxmox.node.NetworkEdit', {
7c0e4c25
DC
170 nodename: me.nodename,
171 iftype: 'bridge',
25f37cbf
TL
172 iface_default: find_next_iface_id('vmbr'),
173 onlineHelp: 'sysadmin_network_configuration',
7c0e4c25
DC
174 });
175 win.on('destroy', reload);
176 win.show();
01031528 177 },
7c0e4c25
DC
178 });
179 }
180
181 if (me.types.indexOf('bond') !== -1) {
182 menu_items.push({
183 text: Proxmox.Utils.render_network_iface_type('bond'),
184 handler: function() {
05a977a2 185 let win = Ext.create('Proxmox.node.NetworkEdit', {
7c0e4c25
DC
186 nodename: me.nodename,
187 iftype: 'bond',
25f37cbf
TL
188 iface_default: find_next_iface_id('bond'),
189 onlineHelp: 'sysadmin_network_configuration',
7c0e4c25
DC
190 });
191 win.on('destroy', reload);
192 win.show();
01031528 193 },
7c0e4c25
DC
194 });
195 }
196
8aefd47c
AD
197 if (me.types.indexOf('vlan') !== -1) {
198 menu_items.push({
199 text: Proxmox.Utils.render_network_iface_type('vlan'),
200 handler: function() {
05a977a2 201 let win = Ext.create('Proxmox.node.NetworkEdit', {
8aefd47c
AD
202 nodename: me.nodename,
203 iftype: 'vlan',
705f92a1 204 iface_default: find_next_iface_id('vlan'),
25f37cbf 205 onlineHelp: 'sysadmin_network_configuration',
8aefd47c
AD
206 });
207 win.on('destroy', reload);
208 win.show();
01031528 209 },
8aefd47c
AD
210 });
211 }
212
7c0e4c25
DC
213 if (me.types.indexOf('ovs') !== -1) {
214 if (menu_items.length > 0) {
215 menu_items.push({ xtype: 'menuseparator' });
216 }
217
218 menu_items.push(
219 {
220 text: Proxmox.Utils.render_network_iface_type('OVSBridge'),
221 handler: function() {
05a977a2 222 let win = Ext.create('Proxmox.node.NetworkEdit', {
7c0e4c25
DC
223 nodename: me.nodename,
224 iftype: 'OVSBridge',
01031528 225 iface_default: find_next_iface_id('vmbr'),
7c0e4c25
DC
226 });
227 win.on('destroy', reload);
228 win.show();
01031528 229 },
7c0e4c25
DC
230 },
231 {
232 text: Proxmox.Utils.render_network_iface_type('OVSBond'),
233 handler: function() {
05a977a2 234 let win = Ext.create('Proxmox.node.NetworkEdit', {
7c0e4c25
DC
235 nodename: me.nodename,
236 iftype: 'OVSBond',
01031528 237 iface_default: find_next_iface_id('bond'),
7c0e4c25
DC
238 });
239 win.on('destroy', reload);
240 win.show();
01031528 241 },
7c0e4c25
DC
242 },
243 {
244 text: Proxmox.Utils.render_network_iface_type('OVSIntPort'),
245 handler: function() {
05a977a2 246 let win = Ext.create('Proxmox.node.NetworkEdit', {
7c0e4c25 247 nodename: me.nodename,
01031528 248 iftype: 'OVSIntPort',
7c0e4c25
DC
249 });
250 win.on('destroy', reload);
251 win.show();
01031528
TL
252 },
253 },
7c0e4c25
DC
254 );
255 }
256
05a977a2 257 let renderer_generator = function(fieldname) {
d0c2b878 258 return function(val, metaData, rec) {
05a977a2 259 let tmp = [];
d0c2b878
DC
260 if (rec.data[fieldname]) {
261 tmp.push(rec.data[fieldname]);
262 }
263 if (rec.data[fieldname + '6']) {
264 tmp.push(rec.data[fieldname + '6']);
265 }
266 return tmp.join('<br>') || '';
267 };
268 };
269
a58001dd
DM
270 Ext.apply(me, {
271 layout: 'border',
272 tbar: [
273 {
274 text: gettext('Create'),
7c0e4c25 275 menu: {
a58001dd 276 plain: true,
01031528
TL
277 items: menu_items,
278 },
1cf31d6b 279 }, '-',
a58001dd
DM
280 {
281 text: gettext('Revert'),
03e93db5 282 itemId: 'revert',
a58001dd
DM
283 handler: function() {
284 Proxmox.Utils.API2Request({
285 url: baseUrl,
286 method: 'DELETE',
287 waitMsgTarget: me,
288 callback: function() {
289 reload();
290 },
ba4ab766 291 failure: response => Ext.Msg.alert(gettext('Error'), response.htmlStatus),
a58001dd 292 });
01031528 293 },
a58001dd
DM
294 },
295 edit_btn,
21cd6c09 296 del_btn,
1cf31d6b 297 '-',
01031528 298 apply_btn,
a58001dd
DM
299 ],
300 items: [
301 {
302 xtype: 'gridpanel',
303 stateful: true,
304 stateId: 'grid-node-network',
305 store: store,
bb5511d5 306 selModel: sm,
a58001dd
DM
307 region: 'center',
308 border: false,
309 columns: [
310 {
311 header: gettext('Name'),
a58001dd 312 sortable: true,
01031528 313 dataIndex: 'iface',
a58001dd
DM
314 },
315 {
316 header: gettext('Type'),
a58001dd 317 sortable: true,
869439b1 318 width: 120,
a58001dd 319 renderer: Proxmox.Utils.render_network_iface_type,
01031528 320 dataIndex: 'type',
a58001dd
DM
321 },
322 {
323 xtype: 'booleancolumn',
324 header: gettext('Active'),
325 width: 80,
326 sortable: true,
327 dataIndex: 'active',
9b575917
WL
328 trueText: Proxmox.Utils.yesText,
329 falseText: Proxmox.Utils.noText,
330 undefinedText: Proxmox.Utils.noText,
a58001dd
DM
331 },
332 {
333 xtype: 'booleancolumn',
334 header: gettext('Autostart'),
335 width: 80,
336 sortable: true,
337 dataIndex: 'autostart',
9b575917
WL
338 trueText: Proxmox.Utils.yesText,
339 falseText: Proxmox.Utils.noText,
01031528 340 undefinedText: Proxmox.Utils.noText,
a58001dd 341 },
8947a4fc
WL
342 {
343 xtype: 'booleancolumn',
344 header: gettext('VLAN aware'),
345 width: 80,
346 sortable: true,
347 dataIndex: 'bridge_vlan_aware',
348 trueText: Proxmox.Utils.yesText,
349 falseText: Proxmox.Utils.noText,
01031528 350 undefinedText: Proxmox.Utils.noText,
8947a4fc 351 },
a58001dd
DM
352 {
353 header: gettext('Ports/Slaves'),
354 dataIndex: 'type',
99f3e147
TL
355 renderer: (value, metaData, { data }) => {
356 if (value === 'bridge') {
357 return data.bridge_ports;
358 } else if (value === 'bond') {
359 return data.slaves;
360 } else if (value === 'OVSBridge') {
361 return data.ovs_ports;
362 } else if (value === 'OVSBond') {
363 return data.ovs_bonds;
364 }
365 return '';
366 },
a58001dd 367 },
211bdf93
DC
368 {
369 header: gettext('Bond Mode'),
370 dataIndex: 'bond_mode',
371 renderer: Proxmox.Utils.render_bond_mode,
372 },
373 {
374 header: gettext('Hash Policy'),
375 hidden: true,
376 dataIndex: 'bond_xmit_hash_policy',
377 },
a58001dd
DM
378 {
379 header: gettext('IP address'),
380 sortable: true,
869439b1 381 width: 120,
4211996a 382 hidden: true,
a58001dd 383 dataIndex: 'address',
d0c2b878 384 renderer: renderer_generator('address'),
a58001dd
DM
385 },
386 {
387 header: gettext('Subnet mask'),
869439b1 388 width: 120,
a58001dd 389 sortable: true,
4211996a 390 hidden: true,
d0c2b878
DC
391 dataIndex: 'netmask',
392 renderer: renderer_generator('netmask'),
393 },
394 {
395 header: gettext('CIDR'),
f4d366dc 396 width: 150,
d0c2b878
DC
397 sortable: true,
398 dataIndex: 'cidr',
399 renderer: renderer_generator('cidr'),
a58001dd
DM
400 },
401 {
402 header: gettext('Gateway'),
f4d366dc 403 width: 150,
a58001dd
DM
404 sortable: true,
405 dataIndex: 'gateway',
d0c2b878 406 renderer: renderer_generator('gateway'),
a58001dd 407 },
3d886f94
AL
408 {
409 header: gettext('VLAN ID'),
410 hidden: true,
411 sortable: true,
412 dataIndex: 'vlan-id',
413 },
414 {
415 header: gettext('VLAN raw device'),
416 hidden: true,
417 sortable: true,
418 dataIndex: 'vlan-raw-device',
419 },
d1f37e22 420 {
8daf5b09 421 header: 'MTU',
d1f37e22
OB
422 hidden: true,
423 sortable: true,
424 dataIndex: 'mtu',
425 },
a58001dd
DM
426 {
427 header: gettext('Comment'),
428 dataIndex: 'comments',
869439b1 429 flex: 1,
01031528
TL
430 renderer: Ext.String.htmlEncode,
431 },
a58001dd
DM
432 ],
433 listeners: {
434 selectionchange: set_button_status,
01031528
TL
435 itemdblclick: run_editor,
436 },
a58001dd
DM
437 },
438 {
439 border: false,
440 region: 'south',
441 autoScroll: true,
89f57452 442 hidden: true,
a58001dd
DM
443 itemId: 'changes',
444 tbar: [
445 gettext('Pending changes') + ' (' +
01031528 446 gettext("Either reboot or use 'Apply Configuration' (needs ifupdown2) to activate") + ')',
a58001dd
DM
447 ],
448 split: true,
449 bodyPadding: 5,
450 flex: 0.6,
01031528
TL
451 html: gettext("No changes"),
452 },
a58001dd 453 ],
a58001dd
DM
454 });
455
456 me.callParent();
1a68e95d 457 reload();
01031528 458 },
a58001dd 459});