1 Ext
.define('proxmox-networks', {
2 extend
: 'Ext.data.Model',
25 Ext
.define('Proxmox.node.NetworkView', {
26 extend
: 'Ext.panel.Panel',
28 alias
: ['widget.proxmoxNodeNetworkView'],
30 // defines what types of network devices we want to create
31 // order is always the same
32 types
: ['bridge', 'bond', 'vlan', 'ovs'],
36 initComponent: function() {
40 throw "no node name specified";
43 let baseUrl
= `/nodes/${me.nodename}/network`;
45 let store
= Ext
.create('Ext.data.Store', {
46 model
: 'proxmox-networks',
49 url
: '/api2/json' + baseUrl
,
59 let reload = function() {
60 let changeitem
= me
.down('#changes');
61 let apply_btn
= me
.down('#apply');
62 let revert_btn
= me
.down('#revert');
63 Proxmox
.Utils
.API2Request({
65 failure: function(response
, opts
) {
67 Proxmox
.Utils
.setErrorMask(me
, response
.htmlStatus
);
68 changeitem
.update('');
69 changeitem
.setHidden(true);
71 success: function(response
, opts
) {
72 let result
= Ext
.decode(response
.responseText
);
73 store
.loadData(result
.data
);
74 let changes
= result
.changes
;
75 if (changes
=== undefined || changes
=== '') {
76 changes
= gettext("No changes");
77 changeitem
.setHidden(true);
78 apply_btn
.setDisabled(true);
79 revert_btn
.setDisabled(true);
81 changeitem
.update("<pre>" + Ext
.htmlEncode(changes
) + "</pre>");
82 changeitem
.setHidden(false);
83 apply_btn
.setDisabled(false);
84 revert_btn
.setDisabled(false);
90 let run_editor = function() {
91 let grid
= me
.down('gridpanel');
92 let sm
= grid
.getSelectionModel();
93 let rec
= sm
.getSelection()[0];
98 Ext
.create('Proxmox.node.NetworkEdit', {
100 nodename
: me
.nodename
,
101 iface
: rec
.data
.iface
,
102 iftype
: rec
.data
.type
,
104 destroy
: () => reload(),
109 let edit_btn
= new Ext
.Button({
110 text
: gettext('Edit'),
115 let sm
= Ext
.create('Ext.selection.RowModel', {});
117 let del_btn
= new Proxmox
.button
.StdRemoveButton({
119 getUrl
: ({ data
}) => `${baseUrl}/${data.iface}`,
120 callback
: () => reload(),
123 let apply_btn
= Ext
.create('Proxmox.button.Button', {
124 text
: gettext('Apply Configuration'),
127 confirmMsg
: 'Do you want to apply pending network changes?',
128 hidden
: !me
.showApplyBtn
,
129 handler: function() {
130 Proxmox
.Utils
.API2Request({
134 success: function({ result
}, opts
) {
135 Ext
.create('Proxmox.window.TaskProgress', {
141 failure
: response
=> Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
),
146 let set_button_status = function() {
147 let rec
= sm
.getSelection()[0];
149 edit_btn
.setDisabled(!rec
);
150 del_btn
.setDisabled(!rec
);
153 let findNextFreeInterfaceId = function(prefix
) {
154 for (let next
= 0; next
<= 9999; next
++) {
155 let id
= `${prefix}${next.toString()}`;
156 if (!store
.getById(id
)) {
160 Ext
.Msg
.alert('Error', `No free ID for ${prefix} found!`);
165 let addEditWindowToMenu
= (iType
, iDefault
) => {
167 text
: Proxmox
.Utils
.render_network_iface_type(iType
),
168 handler
: () => Ext
.create('Proxmox.node.NetworkEdit', {
170 nodename
: me
.nodename
,
172 iface_default
: findNextFreeInterfaceId(iDefault
?? iType
),
173 onlineHelp
: 'sysadmin_network_configuration',
175 destroy
: () => reload(),
181 if (me
.types
.indexOf('bridge') !== -1) {
182 addEditWindowToMenu('bridge', 'vmbr');
185 if (me
.types
.indexOf('bond') !== -1) {
186 addEditWindowToMenu('bond');
189 if (me
.types
.indexOf('vlan') !== -1) {
190 addEditWindowToMenu('vlan');
193 if (me
.types
.indexOf('ovs') !== -1) {
194 if (menu_items
.length
> 0) {
195 menu_items
.push({ xtype
: 'menuseparator' });
198 addEditWindowToMenu('OVSBridge', 'vmbr');
199 addEditWindowToMenu('OVSBond', 'bond');
202 text
: Proxmox
.Utils
.render_network_iface_type('OVSIntPort'),
203 handler
: () => Ext
.create('Proxmox.node.NetworkEdit', {
205 nodename
: me
.nodename
,
206 iftype
: 'OVSIntPort',
208 destroy
: () => reload(),
214 let renderer_generator = function(fieldname
) {
215 return function(val
, metaData
, rec
) {
217 if (rec
.data
[fieldname
]) {
218 tmp
.push(rec
.data
[fieldname
]);
220 if (rec
.data
[fieldname
+ '6']) {
221 tmp
.push(rec
.data
[fieldname
+ '6']);
223 return tmp
.join('<br>') || '';
231 text
: gettext('Create'),
238 text
: gettext('Revert'),
240 handler: function() {
241 Proxmox
.Utils
.API2Request({
245 callback: function() {
248 failure
: response
=> Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
),
261 stateId
: 'grid-node-network',
268 header
: gettext('Name'),
273 header
: gettext('Type'),
276 renderer
: Proxmox
.Utils
.render_network_iface_type
,
280 xtype
: 'booleancolumn',
281 header
: gettext('Active'),
285 trueText
: Proxmox
.Utils
.yesText
,
286 falseText
: Proxmox
.Utils
.noText
,
287 undefinedText
: Proxmox
.Utils
.noText
,
290 xtype
: 'booleancolumn',
291 header
: gettext('Autostart'),
294 dataIndex
: 'autostart',
295 trueText
: Proxmox
.Utils
.yesText
,
296 falseText
: Proxmox
.Utils
.noText
,
297 undefinedText
: Proxmox
.Utils
.noText
,
300 xtype
: 'booleancolumn',
301 header
: gettext('VLAN aware'),
304 dataIndex
: 'bridge_vlan_aware',
305 trueText
: Proxmox
.Utils
.yesText
,
306 falseText
: Proxmox
.Utils
.noText
,
307 undefinedText
: Proxmox
.Utils
.noText
,
310 header
: gettext('Ports/Slaves'),
312 renderer
: (value
, metaData
, { data
}) => {
313 if (value
=== 'bridge') {
314 return data
.bridge_ports
;
315 } else if (value
=== 'bond') {
317 } else if (value
=== 'OVSBridge') {
318 return data
.ovs_ports
;
319 } else if (value
=== 'OVSBond') {
320 return data
.ovs_bonds
;
326 header
: gettext('Bond Mode'),
327 dataIndex
: 'bond_mode',
328 renderer
: Proxmox
.Utils
.render_bond_mode
,
331 header
: gettext('Hash Policy'),
333 dataIndex
: 'bond_xmit_hash_policy',
336 header
: gettext('IP address'),
340 dataIndex
: 'address',
341 renderer
: renderer_generator('address'),
344 header
: gettext('Subnet mask'),
348 dataIndex
: 'netmask',
349 renderer
: renderer_generator('netmask'),
352 header
: gettext('CIDR'),
356 renderer
: renderer_generator('cidr'),
359 header
: gettext('Gateway'),
362 dataIndex
: 'gateway',
363 renderer
: renderer_generator('gateway'),
366 header
: gettext('VLAN ID'),
369 dataIndex
: 'vlan-id',
372 header
: gettext('VLAN raw device'),
375 dataIndex
: 'vlan-raw-device',
384 header
: gettext('Comment'),
385 dataIndex
: 'comments',
387 renderer
: Ext
.String
.htmlEncode
,
391 selectionchange
: set_button_status
,
392 itemdblclick
: run_editor
,
402 gettext('Pending changes') + ' (' +
403 gettext("Either reboot or use 'Apply Configuration' (needs ifupdown2) to activate") + ')',
408 html
: gettext("No changes"),