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