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