2 title: L.tr('Interface Overview'),
8 object: 'luci2.network',
11 expect: { '': { code: -1 } }
14 setDown: L.rpc.declare({
15 object: 'luci2.network',
18 expect: { '': { code: -1 } }
21 renderDeviceIcon: function(dev, up)
23 var icon = dev ? dev.icon(up) : L.globals.resource + '/icons/ethernet_disabled.png';
24 var desc = dev ? '%s (%s)'.format(dev.description(), dev.name()) : L.tr('Network interface not present');
31 renderNetworkBadge: function(network, div)
33 var dest = div || $('#network-badge-%s'.format(network.name()));
34 var device = network.getDevice(); //network.device || { type: 'Network device', device: '?' };
35 var subdevs = network.getSubdevices();
40 .addClass('ifacebox-head')
41 .text(network.name());
44 h.css('background-color', network.zone.color).attr('title', L.trc('Interface status', 'Part of zone "%s"').format(network.zone.name));
46 h.css('background-color', '#cccccc').attr('title', L.trc('Interface status', 'Not part of any zone'));
52 dest.children('div.ifacebox-body').remove();
56 .addClass('ifacebox-body');
58 b.append(this.renderDeviceIcon(device, network.isUp()));
64 for (var i = 0; i < subdevs.length; i++)
65 b.append(this.renderDeviceIcon(subdevs[i], subdevs[i].isUp()));
70 b.append($('<br />')).append($('<small />').text(device ? device.name() : '?'));
72 return dest.append(b);
75 renderNetworkStatus: function(network, div)
81 rv += '<strong>%s</strong>: %t<br />'.format(
88 rv += '<strong>%s</strong>: %s<br />'.format(
90 L.tr('Interface is down')
94 var v4 = network.getIPv4Addrs();
96 rv += '<strong>%s</strong>: %s<br />'.format(
97 L.trc('Interface status', 'IPv4'),
101 var v6 = network.getIPv6Addrs();
103 rv += '<strong>%s</strong>: %s<br />'.format(
104 L.trc('Interface status', 'IPv6'),
108 return (div || $('#network-status-%s'.format(network.name())))
113 renderNetworkChart: function(network, div)
115 var dest = (div || $('#network-chart-%s'.format(network.name())));
119 dest.append($('<div />')
120 .addClass('traffic-chart')
121 .append($('<span />')
122 .attr('id', 'network-chart-tx-%s'.format(network.name()))
124 .append($('<label />')));
126 dest.append($('<div />')
127 .addClass('traffic-chart')
128 .append($('<span />')
129 .attr('id', 'network-chart-rx-%s'.format(network.name()))
131 .append($('<label />')));
133 dest.append($('<small />')
134 .addClass('traffic-stats')
135 .text(L.tr('Loading statistics…')));
140 refreshNetworkStatus: function()
145 while (self.pendingRestart.length)
146 deferreds.push(self.setUp(self.pendingRestart.shift()));
148 while (self.pendingShutdown.length)
149 deferreds.push(self.setDown(self.pendingShutdown.shift()));
151 return $.when.apply($, deferreds).then(function() {
152 $('button').prop('disabled', false);
154 L.network.refreshDeviceStatus(),
155 L.network.refreshInterfaceStatus()
158 var networks = L.network.getInterfaces();
160 for (var i = 0; i < networks.length; i++)
162 self.renderNetworkBadge(networks[i]);
163 self.renderNetworkStatus(networks[i]);
167 var networks = L.network.getInterfaces();
169 for (var i = 0; i < networks.length; i++)
171 var network = networks[i];
172 var history = network.getTrafficHistory();
173 var stats = network.getStatistics();
175 var tx = $('#network-chart-tx-%s'.format(network.name()));
176 var rx = $('#network-chart-rx-%s'.format(network.name()));
178 var tx_rate = history.tx_bytes[history.tx_bytes.length - 1];
179 var rx_rate = history.rx_bytes[history.rx_bytes.length - 1];
181 max = Math.max(Math.max.apply(Math, history.rx_bytes),
182 Math.max.apply(Math, history.tx_bytes),
185 for (var j = 0; j < history.rx_bytes.length; j++)
186 history.rx_bytes[j] = -Math.abs(history.rx_bytes[j]);
188 tx.text(history.tx_bytes.join(','));
189 rx.text(history.rx_bytes.join(','));
191 tx.next().attr('title', '%.2mB/s'.format(tx_rate));
192 rx.next().attr('title', '%.2mB/s'.format(rx_rate));
194 tx.nextAll('label').html('↑ %.2mB/s'.format(tx_rate));
195 rx.nextAll('label').html('↓ %.2mB/s'.format(rx_rate));
197 tx.parent().nextAll('small.traffic-stats').html(
198 '<strong>%s</strong>: %.2mB (%d Pkts.)<br />'.format(
199 L.trc('Interface status', 'TX'),
200 stats.tx_bytes, stats.tx_packets) +
201 '<strong>%s</strong>: %.2mB (%d Pkts.)<br />'.format(
202 L.trc('Interface status', 'RX'),
203 stats.rx_bytes, stats.rx_packets));
206 for (var i = 0; i < networks.length; i++)
208 var network = networks[i];
210 var tx = $('#network-chart-tx-%s'.format(network.name()));
211 var rx = $('#network-chart-rx-%s'.format(network.name()));
213 tx.peity('line', { width: 200, min: 0, max: max });
214 rx.peity('line', { width: 200, min: -max, max: 0 });
221 renderContents: function(networks)
225 var list = new L.ui.table({
227 caption: L.tr('Network'),
229 format: function(v) {
230 var div = $('<div />')
231 .attr('id', 'network-badge-%s'.format(v.name()))
232 .addClass('ifacebox');
234 return self.renderNetworkBadge(v, div);
237 caption: L.tr('Traffic'),
239 format: function(v) {
240 var div = $('<div />').attr('id', 'network-chart-%s'.format(v.name()));
241 return self.renderNetworkChart(v, div);
244 caption: L.tr('Status'),
245 format: function(v) {
246 var div = $('<small />').attr('id', 'network-status-%s'.format(v.name()));
247 return self.renderNetworkStatus(v, div);
250 caption: L.tr('Actions'),
251 format: function(v, n) {
253 .addClass('btn-group btn-group-sm')
254 .append(L.ui.button(L.tr('Restart'), 'default', L.tr('Enable or restart interface'))
255 .click({ self: self, network: v }, self.handleIfup))
256 .append(L.ui.button(L.tr('Shutdown'), 'default', L.tr('Shut down interface'))
257 .click({ self: self, network: v }, self.handleIfdown))
258 .append(L.ui.button(L.tr('Edit'), 'primary', L.tr('Edit interface'))
259 .click({ self: self, network: v }, self.handleEdit))
260 .append(L.ui.button(L.tr('Delete'), 'danger', L.tr('Delete interface'))
261 .click({ self: self, network: v }, self.handleRemove));
266 for (var i = 0; i < networks.length; i++)
267 list.row([ networks[i], networks[i], networks[i], networks[i] ]);
269 self.repeat(self.refreshNetworkStatus, 5000);
272 .append(list.render());
275 renderInterfaceForm: function(network)
277 var m = new L.cbi.Map('network', {
279 caption: 'Interface config',
280 description: 'I can config interface!!!!'
285 var s4 = m.section(L.cbi.TypedSection, 'route', {
286 caption: L.tr('Static IPv4 Routes'),
290 add_caption: L.tr('Add new route'),
291 remove_caption: L.tr('Remove route')
294 var ifc = s4.option(L.cbi.ListValue, 'interface', {
295 caption: L.tr('Interface')
300 s4.option(L.cbi.InputValue, 'target', {
301 caption: L.tr('Target'),
305 s4.option(L.cbi.InputValue, 'netmask', {
306 caption: L.tr('IPv4-Netmask'),
308 placeholder: '255.255.255.255',
312 s4.option(L.cbi.InputValue, 'gateway', {
313 caption: L.tr('IPv4-Gateway'),
318 s4.option(L.cbi.InputValue, 'metric', {
319 caption: L.tr('Metric'),
320 datatype: 'range(0,255)',
325 s4.option(L.cbi.InputValue, 'mtu', {
326 caption: L.tr('MTU'),
327 datatype: 'range(64,9000)',
335 handleIfup: function(ev) {
336 this.disabled = true;
338 ev.data.self.pendingRestart.push(ev.data.network['interface']);
341 handleIfdown: function(ev) {
342 this.disabled = true;
344 ev.data.self.pendingShutdown.push(ev.data.network['interface']);
347 handleEdit: function(ev) {
348 var self = ev.data.self;
349 var network = ev.data.network;
351 return network.createForm(L.cbi.Modal).show();
354 execute: function() {
357 return L.network.load().then(function() {
358 self.renderContents(L.network.getInterfaces());