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