diff options
Diffstat (limited to 'modules/luci-mod-status/htdocs/luci-static/resources')
20 files changed, 993 insertions, 321 deletions
diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/bandwidth.svg b/modules/luci-mod-status/htdocs/luci-static/resources/svg/bandwidth.svg index 5a121b85c6..5a121b85c6 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/bandwidth.svg +++ b/modules/luci-mod-status/htdocs/luci-static/resources/svg/bandwidth.svg diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/svg/channel_analysis.svg b/modules/luci-mod-status/htdocs/luci-static/resources/svg/channel_analysis.svg new file mode 100644 index 0000000000..8f01075d0b --- /dev/null +++ b/modules/luci-mod-status/htdocs/luci-static/resources/svg/channel_analysis.svg @@ -0,0 +1,19 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> + +<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg"> + <polyline id="rx" points="" style="fill:blue;fill-opacity:0.4;stroke:blue;stroke-width:1" /> + <polyline id="tx" points="" style="fill:green;fill-opacity:0.4;stroke:green;stroke-width:1" /> + + <line x1="0" y1="25%" x2="100%" y2="25%" style="stroke:black;stroke-width:0.1" /> + <text id="label_75" x="10" y="24%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000">-25 dbm</text> + + <line x1="0" y1="50%" x2="100%" y2="50%" style="stroke:black;stroke-width:0.1" /> + <text id="label_50" x="10" y="49%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000">-50 dbm</text> + + <line x1="0" y1="75%" x2="100%" y2="75%" style="stroke:black;stroke-width:0.1" /> + <text id="label_25" x="10" y="74%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000">-75 dbm</text> + + <line x1="0" y1="90%" x2="100%" y2="90%" style="stroke:black;stroke-width:0.1" /> + <text id="label_10" x="10" y="89%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000">-90 dbm</text> +</svg> diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/connections.svg b/modules/luci-mod-status/htdocs/luci-static/resources/svg/connections.svg index 5794e79426..5794e79426 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/connections.svg +++ b/modules/luci-mod-status/htdocs/luci-static/resources/svg/connections.svg diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/load.svg b/modules/luci-mod-status/htdocs/luci-static/resources/svg/load.svg index 716d37617f..716d37617f 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/load.svg +++ b/modules/luci-mod-status/htdocs/luci-static/resources/svg/load.svg diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/wifirate.svg b/modules/luci-mod-status/htdocs/luci-static/resources/svg/wifirate.svg index e75ea614c9..e75ea614c9 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/wifirate.svg +++ b/modules/luci-mod-status/htdocs/luci-static/resources/svg/wifirate.svg diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/wireless.svg b/modules/luci-mod-status/htdocs/luci-static/resources/svg/wireless.svg index 00cc2a12f1..00cc2a12f1 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/wireless.svg +++ b/modules/luci-mod-status/htdocs/luci-static/resources/svg/wireless.svg diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/bandwidth.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/bandwidth.js index edb934ed93..cb7cf8c23d 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/bandwidth.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/bandwidth.js @@ -27,7 +27,7 @@ function rate(n, br) { return view.extend({ load: function() { return Promise.all([ - this.loadSVG(L.resource('bandwidth.svg')), + this.loadSVG(L.resource('svg/bandwidth.svg')), network.getDevices() ]); }, @@ -260,26 +260,26 @@ return view.extend({ E('div', { 'class': 'right' }, E('small', { 'id': 'scale' }, '-')), E('br'), - E('div', { 'class': 'table', 'style': 'width:100%;table-layout:fixed' }, [ - E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid blue' }, [ _('Inbound:') ])), - E('div', { 'class': 'td', 'id': 'rx_bw_cur' }, rate(0, true)), + E('table', { 'class': 'table', 'style': 'width:100%;table-layout:fixed' }, [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid blue' }, [ _('Inbound:') ])), + E('td', { 'class': 'td', 'id': 'rx_bw_cur' }, rate(0, true)), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), - E('div', { 'class': 'td', 'id': 'rx_bw_avg' }, rate(0, true)), + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), + E('td', { 'class': 'td', 'id': 'rx_bw_avg' }, rate(0, true)), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), - E('div', { 'class': 'td', 'id': 'rx_bw_peak' }, rate(0, true)) + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), + E('td', { 'class': 'td', 'id': 'rx_bw_peak' }, rate(0, true)) ]), - E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid green' }, [ _('Outbound:') ])), - E('div', { 'class': 'td', 'id': 'tx_bw_cur' }, rate(0, true)), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid green' }, [ _('Outbound:') ])), + E('td', { 'class': 'td', 'id': 'tx_bw_cur' }, rate(0, true)), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), - E('div', { 'class': 'td', 'id': 'tx_bw_avg' }, rate(0, true)), + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), + E('td', { 'class': 'td', 'id': 'tx_bw_avg' }, rate(0, true)), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), - E('div', { 'class': 'td', 'id': 'tx_bw_peak' }, rate(0, true)) + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), + E('td', { 'class': 'td', 'id': 'tx_bw_peak' }, rate(0, true)) ]) ]) ])); diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/channel_analysis.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/channel_analysis.js new file mode 100644 index 0000000000..4b321a4f33 --- /dev/null +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/channel_analysis.js @@ -0,0 +1,419 @@ +'use strict'; +'require view'; +'require poll'; +'require request'; +'require network'; +'require ui'; +'require rpc'; +'require tools.prng as random'; + +return view.extend({ + callFrequencyList : rpc.declare({ + object: 'iwinfo', + method: 'freqlist', + params: [ 'device' ], + expect: { results: [] } + }), + + callInfo : rpc.declare({ + object: 'iwinfo', + method: 'info', + params: [ 'device' ], + expect: { } + }), + + render_signal_badge: function(signalPercent, signalValue) { + var icon, title, value; + + if (signalPercent < 0) + icon = L.resource('icons/signal-none.png'); + else if (signalPercent == 0) + icon = L.resource('icons/signal-0.png'); + else if (signalPercent < 25) + icon = L.resource('icons/signal-0-25.png'); + else if (signalPercent < 50) + icon = L.resource('icons/signal-25-50.png'); + else if (signalPercent < 75) + icon = L.resource('icons/signal-50-75.png'); + else + icon = L.resource('icons/signal-75-100.png'); + + value = '%d\xa0%s'.format(signalValue, _('dBm')); + title = '%s: %d %s'.format(_('Signal'), signalValue, _('dBm')); + + return E('div', { + 'class': 'ifacebadge', + 'title': title, + 'data-signal': signalValue + }, [ + E('img', { 'src': icon }), + value + ]); + }, + + add_wifi_to_graph: function(chan_analysis, res, scanCache, channels, channel_width) { + var offset_tbl = chan_analysis.offset_tbl, + height = chan_analysis.graph.offsetHeight - 2, + step = chan_analysis.col_width, + height_diff = (height-(height-(res.signal*-4))); + + if (scanCache[res.bssid].color == null) + scanCache[res.bssid].color = random.derive_color(res.bssid); + + if (scanCache[res.bssid].graph == null) + scanCache[res.bssid].graph = []; + + channels.forEach(function(channel) { + var chan_offset = offset_tbl[channel], + points = [ + (chan_offset-(step*channel_width))+','+height, + (chan_offset-(step*(channel_width-1)))+','+height_diff, + (chan_offset+(step*(channel_width-1)))+','+height_diff, + (chan_offset+(step*(channel_width)))+','+height + ]; + + if (scanCache[res.bssid].graph[i] == null) { + var group = document.createElementNS('http://www.w3.org/2000/svg', 'g'), + line = document.createElementNS('http://www.w3.org/2000/svg', 'polyline'), + text = document.createElementNS('http://www.w3.org/2000/svg', 'text'), + color = scanCache[res.bssid].color; + + line.setAttribute('style', 'fill:'+color+'4f'+';stroke:'+color+';stroke-width:0.5'); + text.setAttribute('style', 'fill:'+color+';font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000'); + text.appendChild(document.createTextNode(res.ssid || res.bssid)); + + group.appendChild(line) + group.appendChild(text) + + chan_analysis.graph.firstElementChild.appendChild(group); + scanCache[res.bssid].graph[i] = { group : group, line : line, text : text }; + } + + scanCache[res.bssid].graph[i].text.setAttribute('x', chan_offset-step); + scanCache[res.bssid].graph[i].text.setAttribute('y', height_diff - 2); + scanCache[res.bssid].graph[i].line.setAttribute('points', points); + scanCache[res.bssid].graph[i].group.style.zIndex = res.signal*-1; + scanCache[res.bssid].graph[i].group.style.opacity = res.stale ? '0.5' : null; + }) + }, + + create_channel_graph: function(chan_analysis, freq_tbl, freq) { + var is5GHz = freq == '5GHz', + columns = is5GHz ? freq_tbl.length * 4 : freq_tbl.length + 3, + chan_graph = chan_analysis.graph, + G = chan_graph.firstElementChild, + step = (chan_graph.offsetWidth - 2) / columns, + curr_offset = step; + + function createGraphHLine(graph, pos) { + var elem = document.createElementNS('http://www.w3.org/2000/svg', 'line'); + elem.setAttribute('x1', pos); + elem.setAttribute('y1', 0); + elem.setAttribute('x2', pos); + elem.setAttribute('y2', '100%'); + elem.setAttribute('style', 'stroke:black;stroke-width:0.1'); + graph.appendChild(elem); + } + + function createGraphText(graph, pos, text) { + var elem = document.createElementNS('http://www.w3.org/2000/svg', 'text'); + elem.setAttribute('y', 15); + elem.setAttribute('style', 'fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000'); + elem.setAttribute('x', pos + 5); + elem.appendChild(document.createTextNode(text)); + graph.appendChild(elem); + } + + chan_analysis.col_width = step; + + createGraphHLine(G,curr_offset); + for (var i=0; i< freq_tbl.length;i++) { + var channel = freq_tbl[i] + chan_analysis.offset_tbl[channel] = curr_offset+step; + + createGraphHLine(G,curr_offset+step); + createGraphText(G,curr_offset+step, channel); + curr_offset += step; + + if (is5GHz && freq_tbl[i+1]) { + var next_channel = freq_tbl[i+1]; + /* Check if we are transitioning to another 5Ghz band range */ + if ((next_channel - channel) == 4) { + for (var j=1; j < 4; j++) { + chan_analysis.offset_tbl[channel+j] = curr_offset+step; + createGraphHLine(G,curr_offset+step); + curr_offset += step; + } + } else { + chan_analysis.offset_tbl[channel+1] = curr_offset+step; + createGraphHLine(G,curr_offset+step); + curr_offset += step; + + chan_analysis.offset_tbl[next_channel-2] = curr_offset+step; + createGraphHLine(G,curr_offset+step); + curr_offset += step; + + chan_analysis.offset_tbl[next_channel-1] = curr_offset+step; + createGraphHLine(G,curr_offset+step); + curr_offset += step; + } + } + } + createGraphHLine(G,curr_offset+step); + + chan_analysis.tab.addEventListener('cbi-tab-active', L.bind(function(ev) { + this.active_tab = ev.detail.tab; + }, this)); + }, + + handleScanRefresh: function() { + if (!this.active_tab) + return; + + var radioDev = this.radios[this.active_tab].dev, + table = this.radios[this.active_tab].table, + chan_analysis = this.radios[this.active_tab].graph, + scanCache = this.radios[this.active_tab].scanCache; + + return Promise.all([ + radioDev.getScanList(), + this.callInfo(radioDev.getName()) + ]).then(L.bind(function(data) { + var results = data[0], + local_wifi = data[1]; + + var rows = []; + + for (var i = 0; i < results.length; i++) { + if (scanCache[results[i].bssid] == null) + scanCache[results[i].bssid] = {}; + + scanCache[results[i].bssid].data = results[i]; + } + + if (scanCache[local_wifi.bssid] == null) + scanCache[local_wifi.bssid] = {}; + + scanCache[local_wifi.bssid].data = local_wifi; + + if (chan_analysis.offset_tbl[local_wifi.channel] != null && local_wifi.center_chan1) { + var center_channels = [local_wifi.center_chan1], + chan_width_text = local_wifi.htmode.replace(/(V)*HT/,''), + chan_width = parseInt(chan_width_text)/10; + + if (local_wifi.center_chan2) { + center_channels.push(local_wifi.center_chan2); + chan_width = 8; + } + + local_wifi.signal = -10; + local_wifi.ssid = 'Local Interface'; + + this.add_wifi_to_graph(chan_analysis, local_wifi, scanCache, center_channels, chan_width); + rows.push([ + this.render_signal_badge(q, local_wifi.signal), + [ + E('span', { 'style': 'color:'+scanCache[local_wifi.bssid].color }, '⬤ '), + local_wifi.ssid + ], + '%d'.format(local_wifi.channel), + '%h MHz'.format(chan_width_text), + '%h'.format(local_wifi.mode), + '%h'.format(local_wifi.bssid) + ]); + } + + for (var k in scanCache) + if (scanCache[k].stale) + results.push(scanCache[k].data); + + results.sort(function(a, b) { + var diff = (b.quality - a.quality) || (a.channel - b.channel); + + if (diff) + return diff; + + if (a.ssid < b.ssid) + return -1; + else if (a.ssid > b.ssid) + return 1; + + if (a.bssid < b.bssid) + return -1; + else if (a.bssid > b.bssid) + return 1; + }); + + for (var i = 0; i < results.length; i++) { + var res = results[i], + qv = res.quality || 0, + qm = res.quality_max || 0, + q = (qv > 0 && qm > 0) ? Math.floor((100 / qm) * qv) : 0, + s = res.stale ? 'opacity:0.5' : '', + center_channels = [res.channel], + chan_width = 2; + + /* Skip WiFi not supported by the current band */ + if (chan_analysis.offset_tbl[res.channel] == null) + continue; + + res.channel_width = "20 MHz"; + if (res.ht_operation != null) + if (res.ht_operation.channel_width == 2040) { /* 40 MHz Channel Enabled */ + if (res.ht_operation.secondary_channel_offset == "below") { + res.channel_width = "40 MHz"; + chan_width = 4; /* 40 MHz Channel Used */ + center_channels[0] -= 2; + } else if (res.ht_operation.secondary_channel_offset == "above") { + res.channel_width = "40 MHz"; + chan_width = 4; /* 40 MHz Channel Used */ + center_channels[0] += 2; + } else { + res.channel_width = "20 MHz (40 MHz Intolerant)"; + } + } + + if (res.vht_operation != null) { + center_channels[0] = res.vht_operation.center_freq_1; + if (res.vht_operation.channel_width == 80) { + chan_width = 8; + res.channel_width = "80 MHz"; + } else if (res.vht_operation.channel_width == 8080) { + res.channel_width = "80+80 MHz"; + chan_width = 8; + center_channels.push(res.vht_operation.center_freq_2); + } else if (res.vht_operation.channel_width == 160) { + res.channel_width = "160 MHz"; + chan_width = 16; + } + } + + this.add_wifi_to_graph(chan_analysis, res, scanCache, center_channels, chan_width); + + rows.push([ + E('span', { 'style': s }, this.render_signal_badge(q, res.signal)), + E('span', { 'style': s }, [ + E('span', { 'style': 'color:'+scanCache[results[i].bssid].color }, '⬤ '), + (res.ssid != null) ? '%h'.format(res.ssid) : E('em', _('hidden')) + ]), + E('span', { 'style': s }, '%d'.format(res.channel)), + E('span', { 'style': s }, '%h'.format(res.channel_width)), + E('span', { 'style': s }, '%h'.format(res.mode)), + E('span', { 'style': s }, '%h'.format(res.bssid)) + ]); + + res.stale = true; + } + + cbi_update_table(table, rows); + }, this)) + }, + + radios : {}, + + loadSVG : function(src) { + return request.get(src).then(function(response) { + if (!response.ok) + throw new Error(response.statusText); + + return E('div', { + 'id': 'channel_graph', + 'style': 'width:100%;height:400px;border:1px solid #000;background:#fff' + }, E(response.text())); + }); + }, + + load: function() { + return Promise.all([ + this.loadSVG(L.resource('svg/channel_analysis.svg')), + network.getWifiDevices().then(L.bind(function(data) { + var tasks = [], ret = []; + + for (var i = 0; i < data.length; i++) { + ret[data[i].getName()] = { dev : data[i] }; + + tasks.push(this.callFrequencyList(data[i].getName()) + .then(L.bind(function(radio, data) { + ret[radio.getName()].freq = data; + }, this, data[i]))); + } + + return Promise.all(tasks).then(function() { return ret; }) + }, this)) + ]); + }, + + render: function(data) { + var svg = data[0], + wifiDevs = data[1]; + + var v = E('div', {}, E('div')); + + for (var ifname in wifiDevs) { + var freq_tbl = { + ['2.4GHz'] : [], + ['5GHz'] : [], + }; + + /* Split FrequencyList in Bands */ + wifiDevs[ifname].freq.forEach(function(freq) { + if (freq.mhz >= 5000) { + freq_tbl['5GHz'].push(freq.channel); + } else { + freq_tbl['2.4GHz'].push(freq.channel); + } + }); + + for (var freq in freq_tbl) { + if (freq_tbl[freq].length == 0) + continue; + + var csvg = svg.cloneNode(true), + table = E('div', { 'class': 'table' }, [ + E('div', { 'class': 'tr table-titles' }, [ + E('div', { 'class': 'th col-2 middle center' }, _('Signal')), + E('div', { 'class': 'th col-4 middle left' }, _('SSID')), + E('div', { 'class': 'th col-2 middle center hide-xs' }, _('Channel')), + E('div', { 'class': 'th col-3 middle left' }, _('Channel Width')), + E('div', { 'class': 'th col-2 middle left hide-xs' }, _('Mode')), + E('div', { 'class': 'th col-3 middle left hide-xs' }, _('BSSID')) + ]) + ]), + tab = E('div', { 'data-tab': ifname+freq, 'data-tab-title': ifname+' ('+freq+')' }, + [E('br'),csvg,E('br'),table,E('br')]), + graph_data = { + graph: csvg, + offset_tbl: {}, + col_width: 0, + tab: tab, + }; + + this.radios[ifname+freq] = { + dev: wifiDevs[ifname].dev, + graph: graph_data, + table: table, + scanCache: {} + }; + + cbi_update_table(table, [], E('em', { class: 'spinning' }, _('Starting wireless scan...'))); + + v.firstElementChild.appendChild(tab) + + requestAnimationFrame(L.bind(this.create_channel_graph, this, graph_data, freq_tbl[freq], freq)); + } + } + + ui.tabs.initTabGroup(v.firstElementChild.childNodes); + + this.pollFn = L.bind(this.handleScanRefresh, this); + + poll.add(this.pollFn); + poll.start(); + + return v; + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}); diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/connections.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/connections.js index 4c1b097f2b..a87fe53fed 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/connections.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/connections.js @@ -36,7 +36,7 @@ Math.log2 = Math.log2 || function(x) { return Math.log(x) * Math.LOG2E; }; return view.extend({ load: function() { return Promise.all([ - this.loadSVG(L.resource('connections.svg')) + this.loadSVG(L.resource('svg/connections.svg')) ]); }, @@ -133,8 +133,8 @@ return view.extend({ rows.push([ c.layer3.toUpperCase(), c.layer4.toUpperCase(), - c.hasOwnProperty('sport') ? (src + ':' + c.sport) : src, - c.hasOwnProperty('dport') ? (dst + ':' + c.dport) : dst, + '%h'.format(c.hasOwnProperty('sport') ? (src + ':' + c.sport) : src), + '%h'.format(c.hasOwnProperty('dport') ? (dst + ':' + c.dport) : dst), '%1024.2mB (%d %s)'.format(c.bytes, c.packets, _('Pkts.')) ]); } @@ -321,36 +321,36 @@ return view.extend({ E('div', { 'class': 'right' }, E('small', { 'id': 'scale' }, '-')), E('br'), - E('div', { 'class': 'table', 'style': 'width:100%;table-layout:fixed' }, [ - E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid blue' }, [ _('UDP:') ])), - E('div', { 'class': 'td', 'id': 'lb_udp_cur' }, [ '0' ]), + E('table', { 'class': 'table', 'style': 'width:100%;table-layout:fixed' }, [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid blue' }, [ _('UDP:') ])), + E('td', { 'class': 'td', 'id': 'lb_udp_cur' }, [ '0' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), - E('div', { 'class': 'td', 'id': 'lb_udp_avg' }, [ '0' ]), + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), + E('td', { 'class': 'td', 'id': 'lb_udp_avg' }, [ '0' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), - E('div', { 'class': 'td', 'id': 'lb_udp_peak' }, [ '0' ]) + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), + E('td', { 'class': 'td', 'id': 'lb_udp_peak' }, [ '0' ]) ]), - E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid green' }, [ _('TCP:') ])), - E('div', { 'class': 'td', 'id': 'lb_tcp_cur' }, [ '0' ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid green' }, [ _('TCP:') ])), + E('td', { 'class': 'td', 'id': 'lb_tcp_cur' }, [ '0' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), - E('div', { 'class': 'td', 'id': 'lb_tcp_avg' }, [ '0' ]), + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), + E('td', { 'class': 'td', 'id': 'lb_tcp_avg' }, [ '0' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), - E('div', { 'class': 'td', 'id': 'lb_tcp_peak' }, [ '0' ]) + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), + E('td', { 'class': 'td', 'id': 'lb_tcp_peak' }, [ '0' ]) ]), - E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid red' }, [ _('Other:') ])), - E('div', { 'class': 'td', 'id': 'lb_otr_cur' }, [ '0' ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid red' }, [ _('Other:') ])), + E('td', { 'class': 'td', 'id': 'lb_otr_cur' }, [ '0' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), - E('div', { 'class': 'td', 'id': 'lb_otr_avg' }, [ '0' ]), + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), + E('td', { 'class': 'td', 'id': 'lb_otr_avg' }, [ '0' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), - E('div', { 'class': 'td', 'id': 'lb_otr_peak' }, [ '0' ]) + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), + E('td', { 'class': 'td', 'id': 'lb_otr_peak' }, [ '0' ]) ]) ]), @@ -376,16 +376,16 @@ return view.extend({ E('br'), E('div', { 'class': 'cbi-section-node' }, [ - E('div', { 'class': 'table', 'id': 'connections' }, [ - E('div', { 'class': 'tr table-titles' }, [ - E('div', { 'class': 'th col-2 hide-xs' }, [ _('Network') ]), - E('div', { 'class': 'th col-2' }, [ _('Protocol') ]), - E('div', { 'class': 'th col-7' }, [ _('Source') ]), - E('div', { 'class': 'th col-7' }, [ _('Destination') ]), - E('div', { 'class': 'th col-4' }, [ _('Transfer') ]) + E('table', { 'class': 'table', 'id': 'connections' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th col-2 hide-xs' }, [ _('Network') ]), + E('th', { 'class': 'th col-2' }, [ _('Protocol') ]), + E('th', { 'class': 'th col-7' }, [ _('Source') ]), + E('th', { 'class': 'th col-7' }, [ _('Destination') ]), + E('th', { 'class': 'th col-4' }, [ _('Transfer') ]) ]), - E('div', { 'class': 'tr placeholder' }, [ - E('div', { 'class': 'td' }, [ + E('tr', { 'class': 'tr placeholder' }, [ + E('td', { 'class': 'td' }, [ E('em', {}, [ _('Collecting data...') ]) ]) ]) diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/10_system.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/10_system.js index 942b2dd567..ea8f2bb239 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/10_system.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/10_system.js @@ -65,12 +65,12 @@ return baseclass.extend({ ) : null ]; - var table = E('div', { 'class': 'table' }); + var table = E('table', { 'class': 'table' }); for (var i = 0; i < fields.length; i += 2) { - table.appendChild(E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td left', 'width': '33%' }, [ fields[i] ]), - E('div', { 'class': 'td left' }, [ (fields[i + 1] != null) ? fields[i + 1] : '?' ]) + table.appendChild(E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left', 'width': '33%' }, [ fields[i] ]), + E('td', { 'class': 'td left' }, [ (fields[i + 1] != null) ? fields[i + 1] : '?' ]) ])); } diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js index ceb13b56fa..3e89578002 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js @@ -43,12 +43,12 @@ return baseclass.extend({ if (swap.total > 0) fields.push(_('Swap free'), swap.free, swap.total); - var table = E('div', { 'class': 'table' }); + var table = E('table', { 'class': 'table' }); for (var i = 0; i < fields.length; i += 3) { - table.appendChild(E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td left', 'width': '33%' }, [ fields[i] ]), - E('div', { 'class': 'td left' }, [ + table.appendChild(E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left', 'width': '33%' }, [ fields[i] ]), + E('td', { 'class': 'td left' }, [ (fields[i + 1] != null) ? progressbar(fields[i + 1], fields[i + 2], true) : '?' ]) ])); diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/30_network.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/30_network.js index d528408236..3359ca82cc 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/30_network.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/30_network.js @@ -81,12 +81,12 @@ return baseclass.extend({ _('Active Connections'), ct_max ? ct_count : null ]; - var ctstatus = E('div', { 'class': 'table' }); + var ctstatus = E('table', { 'class': 'table' }); for (var i = 0; i < fields.length; i += 2) { - ctstatus.appendChild(E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td left', 'width': '33%' }, [ fields[i] ]), - E('div', { 'class': 'td left' }, [ + ctstatus.appendChild(E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left', 'width': '33%' }, [ fields[i] ]), + E('td', { 'class': 'td left' }, [ (fields[i + 1] != null) ? progressbar(fields[i + 1], ct_max) : '?' ]) ])); diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/40_dhcp.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/40_dhcp.js index 603c0d93aa..e06b555e83 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/40_dhcp.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/40_dhcp.js @@ -1,7 +1,9 @@ 'use strict'; 'require baseclass'; 'require rpc'; +'require uci'; 'require network'; +'require validation'; var callLuciDHCPLeases = rpc.declare({ object: 'luci-rpc', @@ -12,29 +14,85 @@ var callLuciDHCPLeases = rpc.declare({ return baseclass.extend({ title: '', + isMACStatic: {}, + isDUIDStatic: {}, + load: function() { return Promise.all([ callLuciDHCPLeases(), - network.getHostHints() + network.getHostHints(), + uci.load('dhcp') ]); }, + handleCreateStaticLease: function(lease, ev) { + ev.currentTarget.classList.add('spinning'); + ev.currentTarget.disabled = true; + ev.currentTarget.blur(); + + var cfg = uci.add('dhcp', 'host'); + uci.set('dhcp', cfg, 'name', lease.hostname || '-'); + uci.set('dhcp', cfg, 'ip', lease.ipaddr); + uci.set('dhcp', cfg, 'mac', lease.macaddr.toUpperCase()); + + return uci.save() + .then(L.bind(L.ui.changes.init, L.ui.changes)) + .then(L.bind(L.ui.changes.displayChanges, L.ui.changes)); + }, + + handleCreateStaticLease6: function(lease, ev) { + ev.currentTarget.classList.add('spinning'); + ev.currentTarget.disabled = true; + ev.currentTarget.blur(); + + var cfg = uci.add('dhcp', 'host'), + ip6arr = lease.ip6addrs[0] ? validation.parseIPv6(lease.ip6addrs[0]) : null; + + uci.set('dhcp', cfg, 'name', lease.hostname || '-'); + uci.set('dhcp', cfg, 'duid', lease.duid.toUpperCase()); + uci.set('dhcp', cfg, 'mac', lease.macaddr); + if (ip6arr) + uci.set('dhcp', cfg, 'hostid', (ip6arr[6] * 0xFFFF + ip6arr[7]).toString(16)); + + return uci.save() + .then(L.bind(L.ui.changes.init, L.ui.changes)) + .then(L.bind(L.ui.changes.displayChanges, L.ui.changes)); + }, + renderLeases: function(data) { var leases = Array.isArray(data[0].dhcp_leases) ? data[0].dhcp_leases : [], leases6 = Array.isArray(data[0].dhcp6_leases) ? data[0].dhcp6_leases : [], - machints = data[1].getMACHints(false); - - var table = E('div', { 'class': 'table lases' }, [ - E('div', { 'class': 'tr table-titles' }, [ - E('div', { 'class': 'th' }, _('Hostname')), - E('div', { 'class': 'th' }, _('IPv4-Address')), - E('div', { 'class': 'th' }, _('MAC-Address')), - E('div', { 'class': 'th' }, _('Lease time remaining')) + machints = data[1].getMACHints(false), + hosts = uci.sections('dhcp', 'host'); + + for (var i = 0; i < hosts.length; i++) { + var host = hosts[i]; + + if (host.mac) { + var macs = L.toArray(host.mac); + for (var j = 0; j < macs.length; j++) { + var mac = macs[j].toUpperCase(); + this.isMACStatic[mac] = true; + } + } + if (host.duid) { + var duid = host.duid.toUpperCase(); + this.isDUIDStatic[duid] = true; + } + }; + + var table = E('table', { 'class': 'table lases' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('Hostname')), + E('th', { 'class': 'th' }, _('IPv4-Address')), + E('th', { 'class': 'th' }, _('MAC-Address')), + E('th', { 'class': 'th' }, _('Lease time remaining')), + E('th', { 'class': 'th cbi-section-actions' }, _('Static Lease')) ]) ]); - cbi_update_table(table, leases.map(function(lease) { - var exp; + cbi_update_table(table, leases.map(L.bind(function(lease) { + var exp, rows; if (lease.expires === false) exp = E('em', _('unlimited')); @@ -43,25 +101,37 @@ return baseclass.extend({ else exp = '%t'.format(lease.expires); - return [ + rows = [ lease.hostname || '-', lease.ipaddr, lease.macaddr, exp ]; - }), E('em', _('There are no active leases'))); - - var table6 = E('div', { 'class': 'table leases6' }, [ - E('div', { 'class': 'tr table-titles' }, [ - E('div', { 'class': 'th' }, _('Host')), - E('div', { 'class': 'th' }, _('IPv6-Address')), - E('div', { 'class': 'th' }, _('DUID')), - E('div', { 'class': 'th' }, _('Lease time remaining')) + + if (lease.macaddr != null) { + var mac = lease.macaddr.toUpperCase(); + rows.push(E('button', { + 'class': 'cbi-button cbi-button-apply', + 'click': L.bind(this.handleCreateStaticLease, this, lease), + 'disabled': this.isMACStatic[mac] + }, [ _('Set Static') ])); + } + + return rows; + }, this)), E('em', _('There are no active leases'))); + + var table6 = E('table', { 'class': 'table leases6' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('Host')), + E('th', { 'class': 'th' }, _('IPv6-Address')), + E('th', { 'class': 'th' }, _('DUID')), + E('th', { 'class': 'th' }, _('Lease time remaining')), + E('th', { 'class': 'th cbi-section-actions' }, _('Static Lease')) ]) ]); - cbi_update_table(table6, leases6.map(function(lease) { - var exp; + cbi_update_table(table6, leases6.map(L.bind(function(lease) { + var exp, rows; if (lease.expires === false) exp = E('em', _('unlimited')); @@ -80,13 +150,24 @@ return baseclass.extend({ else if (hint) host = hint[1]; - return [ + rows = [ host || '-', lease.ip6addrs ? lease.ip6addrs.join(' ') : lease.ip6addr, lease.duid, exp ]; - }), E('em', _('There are no active leases'))); + + if (lease.duid != null) { + var duid = lease.duid.toUpperCase(); + rows.push(E('button', { + 'class': 'cbi-button cbi-button-apply', + 'click': L.bind(this.handleCreateStaticLease6, this, lease), + 'disabled': this.isDUIDStatic[duid] + }, [ _('Set Static') ])); + } + + return rows; + }, this)), E('em', _('There are no active leases'))); return E([ E('h3', _('Active DHCP Leases')), diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/50_dsl.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/50_dsl.js index cafd554f9a..714086f0d7 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/50_dsl.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/50_dsl.js @@ -2,40 +2,39 @@ 'require baseclass'; 'require rpc'; -var callLuciDSLStatus = rpc.declare({ - object: 'luci-rpc', - method: 'getDSLStatus', +var callDSLMetrics = rpc.declare({ + object: 'dsl', + method: 'metrics', expect: { '': {} } }); function renderbox(dsl) { return E('div', { class: 'ifacebox' }, [ - E('div', { class: 'ifacebox-head center ' + ((dsl.line_state === 'UP') ? 'active' : '') }, + E('div', { class: 'ifacebox-head center ' + (dsl.up ? 'active' : '') }, E('strong', _('DSL Status'))), E('div', { class: 'ifacebox-body left' }, [ L.itemlist(E('span'), [ - _('Line State'), '%s [0x%x]'.format(dsl.line_state, dsl.line_state_detail), - _('Line Mode'), dsl.line_mode_s || '-', - _('Line Uptime'), dsl.line_uptime_s || '-', - _('Annex'), dsl.annex_s || '-', - _('Profile'), dsl.profile_s || '-', - _('Data Rate'), '%s/s / %s/s'.format(dsl.data_rate_down_s, dsl.data_rate_up_s), - _('Max. Attainable Data Rate (ATTNDR)'), '%s/s / %s/s'.format(dsl.max_data_rate_down_s, dsl.max_data_rate_up_s), - _('Latency'), '%s / %s'.format(dsl.latency_num_down, dsl.latency_num_up), - _('Line Attenuation (LATN)'), '%.1f dB / %.1f dB'.format(dsl.line_attenuation_down, dsl.line_attenuation_up), - _('Signal Attenuation (SATN)'), '%.1f dB / %.1f dB'.format(dsl.signal_attenuation_down, dsl.signal_attenuation_up), - _('Noise Margin (SNR)'), '%.1f dB / %.1f dB'.format(dsl.noise_margin_down, dsl.noise_margin_up), - _('Aggregate Transmit Power (ACTATP)'), '%.1f dB / %.1f dB'.format(dsl.actatp_down, dsl.actatp_up), - _('Forward Error Correction Seconds (FECS)'), '%d / %d'.format(dsl.errors_fecs_near, dsl.errors_fecs_far), - _('Errored seconds (ES)'), '%d / %d'.format(dsl.errors_es_near, dsl.errors_es_far), - _('Severely Errored Seconds (SES)'), '%d / %d'.format(dsl.errors_ses_near, dsl.errors_ses_far), - _('Loss of Signal Seconds (LOSS)'), '%d / %d'.format(dsl.errors_loss_near, dsl.errors_loss_far), - _('Unavailable Seconds (UAS)'), '%d / %d'.format(dsl.errors_uas_near, dsl.errors_uas_far), - _('Header Error Code Errors (HEC)'), '%d / %d'.format(dsl.errors_hec_near, dsl.errors_hec_far), - _('Non Pre-emptive CRC errors (CRC_P)'), '%d / %d'.format(dsl.errors_crc_p_near, dsl.errors_crc_p_far), - _('Pre-emptive CRC errors (CRCP_P)'), '%d / %d'.format(dsl.errors_crcp_p_near, dsl.errors_crcp_p_far), - _('ATU-C System Vendor ID'), dsl.atuc_vendor_id, - _('Power Management Mode'), dsl.power_mode_s + _('Line State'), dsl.state || '-', + _('Line Mode'), dsl.mode || '-', + _('Line Uptime'), '%t'.format(dsl.uptime), + _('Annex'), dsl.annex || '-', + _('Data Rate'), '%1000.3mb/s / %1000.3mb/s'.format(dsl.downstream.data_rate, dsl.upstream.data_rate), + _('Max. Attainable Data Rate (ATTNDR)'), '%1000.3mb/s / %1000.3mb/s'.format(dsl.downstream.attndr, dsl.upstream.attndr), + _('Latency'), '%.2f ms / %.2f ms'.format(dsl.downstream.interleave_delay / 1000, dsl.upstream.interleave_delay / 1000), + _('Line Attenuation (LATN)'), '%.1f dB / %.1f dB'.format(dsl.downstream.latn, dsl.upstream.latn), + _('Signal Attenuation (SATN)'), '%.1f dB / %.1f dB'.format(dsl.downstream.satn, dsl.upstream.satn), + _('Noise Margin (SNR)'), '%.1f dB / %.1f dB'.format(dsl.downstream.snr, dsl.upstream.snr), + _('Aggregate Transmit Power (ACTATP)'), '%.1f dB / %.1f dB'.format(dsl.downstream.actatp, dsl.upstream.actatp), + _('Forward Error Correction Seconds (FECS)'), '%d / %d'.format(dsl.errors.near.fecs, dsl.errors.far.fecs), + _('Errored seconds (ES)'), '%d / %d'.format(dsl.errors.near.es, dsl.errors.far.es), + _('Severely Errored Seconds (SES)'), '%d / %d'.format(dsl.errors.near.ses, dsl.errors.far.ses), + _('Loss of Signal Seconds (LOSS)'), '%d / %d'.format(dsl.errors.near.loss, dsl.errors.far.loss), + _('Unavailable Seconds (UAS)'), '%d / %d'.format(dsl.errors.near.uas, dsl.errors.far.uas), + _('Header Error Code Errors (HEC)'), '%d / %d'.format(dsl.errors.near.hec, dsl.errors.far.hec), + _('Non Pre-emptive CRC errors (CRC_P)'), '%d / %d'.format(dsl.errors.near.crc_p, dsl.errors.far.crc_p), + _('Pre-emptive CRC errors (CRCP_P)'), '%d / %d'.format(dsl.errors.near.crcp_p, dsl.errors.far.crcp_p), + _('ATU-C System Vendor ID'), dsl.atu_c.vendor || dsl.atu_c.vendor_id, + _('Power Management Mode'), dsl.power_state ]) ]) ]); @@ -45,11 +44,11 @@ return baseclass.extend({ title: _('DSL'), load: function() { - return L.resolveDefault(callLuciDSLStatus(), {}); + return L.resolveDefault(callDSLMetrics(), {}); }, render: function(dsl) { - if (!dsl.line_state) + if (!dsl.state) return null; return E('div', { 'id': 'dsl_status_table', 'class': 'network-status-table' }, renderbox(dsl)); diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/60_wifi.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/60_wifi.js index deb6f8609f..18172aae94 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/60_wifi.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/60_wifi.js @@ -2,120 +2,210 @@ 'require baseclass'; 'require dom'; 'require network'; +'require uci'; +'require fs'; 'require rpc'; -var callSessionAccess = rpc.declare({ - object: 'session', - method: 'access', - params: [ 'scope', 'object', 'function' ], - expect: { 'access': false } -}); +return baseclass.extend({ + title: _('Wireless'), -function renderbox(radio, networks) { - var chan = null, - freq = null, - rate = null, - badges = []; - - for (var i = 0; i < networks.length; i++) { - var net = networks[i], - is_assoc = (net.getBSSID() != '00:00:00:00:00:00' && net.getChannel() && !net.isDisabled()), - quality = net.getSignalPercent(); - - var icon; - if (net.isDisabled()) - icon = L.resource('icons/signal-none.png'); - else if (quality <= 0) - icon = L.resource('icons/signal-0.png'); - else if (quality < 25) - icon = L.resource('icons/signal-0-25.png'); - else if (quality < 50) - icon = L.resource('icons/signal-25-50.png'); - else if (quality < 75) - icon = L.resource('icons/signal-50-75.png'); - else - icon = L.resource('icons/signal-75-100.png'); - - var badge = renderBadge( - icon, - '%s: %d dBm / %s: %d%%'.format(_('Signal'), net.getSignal(), _('Quality'), quality), - _('SSID'), net.getActiveSSID() || '?', - _('Mode'), net.getActiveMode(), - _('BSSID'), is_assoc ? (net.getActiveBSSID() || '-') : null, - _('Encryption'), is_assoc ? net.getActiveEncryption() : null, - _('Associations'), is_assoc ? (net.assoclist.length || '-') : null, - null, is_assoc ? null : E('em', net.isDisabled() ? _('Wireless is disabled') : _('Wireless is not associated'))); - - badges.push(badge); - - chan = (chan != null) ? chan : net.getChannel(); - freq = (freq != null) ? freq : net.getFrequency(); - rate = (rate != null) ? rate : net.getBitRate(); - } + WPSTranslateTbl: { + Disabled: _('Disabled'), + Active: _('Active'), + 'Timed-out': _('Timed-out'), + Overlap: _('Overlap'), + Unknown: _('Unknown') + }, - return E('div', { class: 'ifacebox' }, [ - E('div', { class: 'ifacebox-head center ' + (radio.isUp() ? 'active' : '') }, - E('strong', radio.getName())), - E('div', { class: 'ifacebox-body left' }, [ - L.itemlist(E('span'), [ - _('Type'), radio.getI18n().replace(/^Generic | Wireless Controller .+$/g, ''), - _('Channel'), chan ? '%d (%.3f %s)'.format(chan, freq, _('GHz')) : '-', - _('Bitrate'), rate ? '%d %s'.format(rate, _('Mbit/s')) : '-' - ]), - E('div', {}, badges) - ]) - ]); -} - -function wifirate(rt) { - var s = '%.1f\xa0%s, %d\xa0%s'.format(rt.rate / 1000, _('Mbit/s'), rt.mhz, _('MHz')), - ht = rt.ht, vht = rt.vht, - mhz = rt.mhz, nss = rt.nss, - mcs = rt.mcs, sgi = rt.short_gi; - - if (ht || vht) { - if (vht) s += ', VHT-MCS\xa0%d'.format(mcs); - if (nss) s += ', VHT-NSS\xa0%d'.format(nss); - if (ht) s += ', MCS\xa0%s'.format(mcs); - if (sgi) s += ', ' + _('Short GI').replace(/ /g, '\xa0'); - } + callSessionAccess: rpc.declare({ + object: 'session', + method: 'access', + params: [ 'scope', 'object', 'function' ], + expect: { 'access': false } + }), + + wifirate: function(rt) { + var s = '%.1f\xa0%s, %d\xa0%s'.format(rt.rate / 1000, _('Mbit/s'), rt.mhz, _('MHz')), + ht = rt.ht, vht = rt.vht, + mhz = rt.mhz, nss = rt.nss, + mcs = rt.mcs, sgi = rt.short_gi; + + if (ht || vht) { + if (vht) s += ', VHT-MCS\xa0%d'.format(mcs); + if (nss) s += ', VHT-NSS\xa0%d'.format(nss); + if (ht) s += ', MCS\xa0%s'.format(mcs); + if (sgi) s += ', ' + _('Short GI').replace(/ /g, '\xa0'); + } - return s; -} + return s; + }, -return baseclass.extend({ - title: _('Wireless'), + handleDelClient: function(wifinet, mac, ev, cmd) { + var exec = cmd || 'disconnect'; - handleDelClient: function(wifinet, mac, ev) { dom.parent(ev.currentTarget, '.tr').style.opacity = 0.5; ev.currentTarget.classList.add('spinning'); ev.currentTarget.disabled = true; ev.currentTarget.blur(); + if (exec == 'addlist') { + var macs = [ mac ] + + for (var mac in this.iface_maclist) { + macs.push(mac) + } + + uci.set('wireless', wifinet.sid, 'maclist', macs); + + return uci.save() + .then(L.bind(L.ui.changes.init, L.ui.changes)) + .then(L.bind(L.ui.changes.displayChanges, L.ui.changes)); + } + wifinet.disconnectClient(mac, true, 5, 60000); }, + handleGetWPSStatus: function(wifinet) { + return rpc.declare({ + object: 'hostapd.%s'.format(wifinet), + method: 'wps_status', + })() + }, + + handleCallWPS: function(wifinet, ev) { + ev.currentTarget.classList.add('spinning'); + ev.currentTarget.disabled = true; + ev.currentTarget.blur(); + + return rpc.declare({ + object: 'hostapd.%s'.format(wifinet), + method: 'wps_start', + })(); + }, + + handleCancelWPS: function(wifinet, ev) { + ev.currentTarget.classList.add('spinning'); + ev.currentTarget.disabled = true; + ev.currentTarget.blur(); + + return rpc.declare({ + object: 'hostapd.%s'.format(wifinet), + method: 'wps_cancel', + })(); + }, + + renderbox: function(radio, networks) { + var chan = null, + freq = null, + rate = null, + badges = []; + + for (var i = 0; i < networks.length; i++) { + var net = networks[i], + is_assoc = (net.getBSSID() != '00:00:00:00:00:00' && net.getChannel() && !net.isDisabled()), + quality = net.getSignalPercent(); + + var icon; + if (net.isDisabled()) + icon = L.resource('icons/signal-none.png'); + else if (quality <= 0) + icon = L.resource('icons/signal-0.png'); + else if (quality < 25) + icon = L.resource('icons/signal-0-25.png'); + else if (quality < 50) + icon = L.resource('icons/signal-25-50.png'); + else if (quality < 75) + icon = L.resource('icons/signal-50-75.png'); + else + icon = L.resource('icons/signal-75-100.png'); + + var WPS_button = null; + + if (this.isWPSEnabled[net.sid]) { + if (net.wps_status == 'Active') { + WPS_button = E('button', { + 'class' : 'cbi-button cbi-button-remove', + 'click': L.bind(this.handleCancelWPS, this, net.getIfname()), + }, [ _('Stop WPS') ]) + } else { + WPS_button = E('button', { + 'class' : 'cbi-button cbi-button-apply', + 'click': L.bind(this.handleCallWPS, this, net.getIfname()), + }, [ _('Start WPS') ]) + } + } + + var badge = renderBadge( + icon, + '%s: %d dBm / %s: %d%%'.format(_('Signal'), net.getSignal(), _('Quality'), quality), + _('SSID'), net.getActiveSSID() || '?', + _('Mode'), net.getActiveMode(), + _('BSSID'), is_assoc ? (net.getActiveBSSID() || '-') : null, + _('Encryption'), is_assoc ? net.getActiveEncryption() : null, + _('Associations'), is_assoc ? (net.assoclist.length || '-') : null, + null, is_assoc ? null : E('em', net.isDisabled() ? _('Wireless is disabled') : _('Wireless is not associated')), + _('WPS status'), this.WPSTranslateTbl[net.wps_status], + '', WPS_button + ); + + badges.push(badge); + + chan = (chan != null) ? chan : net.getChannel(); + freq = (freq != null) ? freq : net.getFrequency(); + rate = (rate != null) ? rate : net.getBitRate(); + } + + return E('div', { class: 'ifacebox' }, [ + E('div', { class: 'ifacebox-head center ' + (radio.isUp() ? 'active' : '') }, + E('strong', radio.getName())), + E('div', { class: 'ifacebox-body left' }, [ + L.itemlist(E('span'), [ + _('Type'), radio.getI18n().replace(/^Generic | Wireless Controller .+$/g, ''), + _('Channel'), chan ? '%d (%.3f %s)'.format(chan, freq, _('GHz')) : '-', + _('Bitrate'), rate ? '%d %s'.format(rate, _('Mbit/s')) : '-', + ]), + E('div', {}, badges) + ]) + ]); + }, + + isWPSEnabled: {}, + load: function() { return Promise.all([ network.getWifiDevices(), network.getWifiNetworks(), network.getHostHints(), - callSessionAccess('access-group', 'luci-mod-status-index-wifi', 'read'), - callSessionAccess('access-group', 'luci-mod-status-index-wifi', 'write') - ]).then(function(radios_networks_hints) { - var tasks = []; - - for (var i = 0; i < radios_networks_hints[1].length; i++) - tasks.push(L.resolveDefault(radios_networks_hints[1][i].getAssocList(), []).then(L.bind(function(net, list) { + this.callSessionAccess('access-group', 'luci-mod-status-index-wifi', 'read'), + this.callSessionAccess('access-group', 'luci-mod-status-index-wifi', 'write'), + uci.load('wireless') + ]).then(L.bind(function(data) { + var tasks = [], + radios_networks_hints = data[1], + hasWPS = L.hasSystemFeature('hostapd', 'wps'); + + for (var i = 0; i < radios_networks_hints.length; i++) { + tasks.push(L.resolveDefault(radios_networks_hints[i].getAssocList(), []).then(L.bind(function(net, list) { net.assoclist = list.sort(function(a, b) { return a.mac > b.mac }); - }, this, radios_networks_hints[1][i]))); + }, this, radios_networks_hints[i]))); + + if (hasWPS && uci.get('wireless', radios_networks_hints[i].sid, 'wps_pushbutton') == '1') { + this.isWPSEnabled[radios_networks_hints[i].sid] = true; + tasks.push(L.resolveDefault(this.handleGetWPSStatus(radios_networks_hints[i].getIfname()), null) + .then(L.bind(function(net, data) { + net.wps_status = data ? data.pbc_status : _('No Data'); + }, this, radios_networks_hints[i]))); + } + } return Promise.all(tasks).then(function() { - return radios_networks_hints; + return data; }); - }); + }, this)); }, + isDeviceAdded: {}, + render: function(data) { var seen = {}, radios = data[0], @@ -127,25 +217,36 @@ return baseclass.extend({ var table = E('div', { 'class': 'network-status-table' }); for (var i = 0; i < radios.sort(function(a, b) { a.getName() > b.getName() }).length; i++) - table.appendChild(renderbox(radios[i], + table.appendChild(this.renderbox(radios[i], networks.filter(function(net) { return net.getWifiDeviceName() == radios[i].getName() }))); if (!table.lastElementChild) return null; - var assoclist = E('div', { 'class': 'table assoclist' }, [ - E('div', { 'class': 'tr table-titles' }, [ - E('div', { 'class': 'th nowrap' }, _('Network')), - E('div', { 'class': 'th hide-xs' }, _('MAC-Address')), - E('div', { 'class': 'th' }, _('Host')), - E('div', { 'class': 'th' }, '%s / %s'.format(_('Signal'), _('Noise'))), - E('div', { 'class': 'th' }, '%s / %s'.format(_('RX Rate'), _('TX Rate'))) + var assoclist = E('table', { 'class': 'table assoclist' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th nowrap' }, _('Network')), + E('th', { 'class': 'th hide-xs' }, _('MAC-Address')), + E('th', { 'class': 'th' }, _('Host')), + E('th', { 'class': 'th' }, '%s / %s'.format(_('Signal'), _('Noise'))), + E('th', { 'class': 'th' }, '%s / %s'.format(_('RX Rate'), _('TX Rate'))) ]) ]); var rows = []; for (var i = 0; i < networks.length; i++) { + var macfilter = uci.get('wireless', networks[i].sid, 'macfilter'); + + if (macfilter != null && macfilter != 'disable') { + this.isDeviceAdded = {}; + var macs = L.toArray(uci.get('wireless', networks[i].sid, 'maclist')); + for (var j = 0; j < macs.length; j++) { + var mac = macs[j].toUpperCase(); + this.isDeviceAdded[mac] = true; + } + } + for (var k = 0; k < networks[i].assoclist.length; k++) { var bss = networks[i].assoclist[k], name = hosthints.getHostnameByMACAddr(bss.mac), @@ -215,20 +316,36 @@ return baseclass.extend({ ]) ]), E('span', {}, [ - E('span', wifirate(bss.rx)), + E('span', this.wifirate(bss.rx)), E('br'), - E('span', wifirate(bss.tx)) + E('span', this.wifirate(bss.tx)) ]) ]; if (networks[i].isClientDisconnectSupported() && hasWritePermission) { if (assoclist.firstElementChild.childNodes.length < 6) - assoclist.firstElementChild.appendChild(E('div', { 'class': 'th cbi-section-actions' })); - - row.push(E('button', { - 'class': 'cbi-button cbi-button-remove', - 'click': L.bind(this.handleDelClient, this, networks[i], bss.mac) - }, [ _('Disconnect') ])); + assoclist.firstElementChild.appendChild(E('th', { 'class': 'th cbi-section-actions' })); + + if (macfilter != null && macfilter != 'disable' && !this.isDeviceAdded[bss.mac]) { + row.push(new L.ui.ComboButton('button', { + 'addlist': macfilter == 'allow' ? _('Add to Whitelist') : _('Add to Blacklist'), + 'disconnect': _('Disconnect') + }, { + 'click': L.bind(this.handleDelClient, this, networks[i], bss.mac), + 'sort': [ 'disconnect', 'addlist' ], + 'classes': { + 'addlist': 'btn cbi-button cbi-button-remove', + 'disconnect': 'btn cbi-button cbi-button-remove' + } + }).render() + ) + } + else { + row.push(E('button', { + 'class': 'cbi-button cbi-button-remove', + 'click': L.bind(this.handleDelClient, this, networks[i], bss.mac) + }, [ _('Disconnect') ])); + } } else { row.push('-'); diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/iptables.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/iptables.js index 84d2b10556..951c31218d 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/iptables.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/iptables.js @@ -4,7 +4,8 @@ 'require fs'; 'require ui'; -var table_names = [ 'Filter', 'NAT', 'Mangle', 'Raw' ]; +var table_names = [ 'Filter', 'NAT', 'Mangle', 'Raw' ], + raw_style = 'font-family:monospace;font-size:smaller;text-align:right'; return view.extend({ load: function() { @@ -58,18 +59,18 @@ return view.extend({ if (!cdiv) { cdiv = E('div', { 'data-chain': chain }, [ E('h4', { 'id': 'rule_%s-%s_%s'.format(is_ipv6 ? 'ipv6' : 'ipv4', table.toLowerCase(), chain) }, title), - E('div', { 'class': 'table' }, [ - E('div', { 'class': 'tr table-titles' }, [ - E('div', { 'class': 'th center' }, _('Pkts.')), - E('div', { 'class': 'th center' }, _('Traffic')), - E('div', { 'class': 'th' }, _('Target')), - E('div', { 'class': 'th' }, _('Prot.')), - E('div', { 'class': 'th' }, _('In')), - E('div', { 'class': 'th' }, _('Out')), - E('div', { 'class': 'th' }, _('Source')), - E('div', { 'class': 'th' }, _('Destination')), - E('div', { 'class': 'th' }, _('Options')), - E('div', { 'class': 'th' }, _('Comment')) + E('table', { 'class': 'table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('Pkts.')), + E('th', { 'class': 'th' }, _('Traffic')), + E('th', { 'class': 'th' }, _('Target')), + E('th', { 'class': 'th' }, _('Prot.')), + E('th', { 'class': 'th' }, _('In')), + E('th', { 'class': 'th' }, _('Out')), + E('th', { 'class': 'th' }, _('Source')), + E('th', { 'class': 'th' }, _('Destination')), + E('th', { 'class': 'th' }, _('Options')), + E('th', { 'class': 'th' }, _('Comment')) ]) ]) ]); @@ -105,6 +106,7 @@ return view.extend({ var chain_refs = {}; var re = /([^\n]*)\n/g; var m, m2; + var raw = document.querySelector('[data-raw-counters="true"]'); while ((m = re.exec(s)) != null) { if (m[1].match(/^Chain (.+) \(policy (\w+) (\d+) packets, (\d+) bytes\)$/)) { @@ -152,12 +154,22 @@ return view.extend({ }) || '-'; current_rules.push([ - '%.2m'.format(pkts).nobr(), - '%.2mB'.format(bytes).nobr(), + E('div', { + 'class': 'nowrap', + 'style': raw ? raw_style : null, + 'data-format': '%.2m', + 'data-value': pkts + }, (raw ? '%d' : '%.2m').format(pkts)), + E('div', { + 'class': 'nowrap', + 'style': raw ? raw_style : null, + 'data-format': '%.2mB', + 'data-value': bytes + }, (raw ? '%d' : '%.2mB').format(bytes)), target ? '<span class="target">%s</span>'.format(target) : '-', proto, - (indev !== '*') ? '<span class="ifacebadge">%s</span>'.format(indev) : '*', - (outdev !== '*') ? '<span class="ifacebadge">%s</span>'.format(outdev) : '*', + (indev !== '*') ? '<span class="ifacebadge nowrap">%s</span>'.format(indev) : '*', + (outdev !== '*') ? '<span class="ifacebadge nowrap">%s</span>'.format(outdev) : '*', srcnet, dstnet, options, @@ -256,6 +268,23 @@ return view.extend({ } }, + handleRawCounters: function(ev) { + var btn = ev.currentTarget, + raw = (btn.getAttribute('data-raw-counters') === 'false'); + + btn.setAttribute('data-raw-counters', raw); + btn.firstChild.data = raw ? _('Human-readable counters') : _('Show raw counters'); + btn.blur(); + + document.querySelectorAll('[data-value]') + .forEach(function(div) { + var fmt = raw ? '%d' : div.getAttribute('data-format'); + + div.style = raw ? raw_style : ''; + div.innerText = fmt.format(div.getAttribute('data-value')); + }); + }, + handleHideEmpty: function(ev) { var btn = ev.currentTarget, hide = (btn.getAttribute('data-hide-empty') === 'false'); @@ -304,6 +333,12 @@ return view.extend({ ' ', E('button', { 'class': 'cbi-button', + 'data-raw-counters': false, + 'click': ui.createHandlerFn(this, 'handleRawCounters') + }, [ _('Show raw counters') ]), + ' ', + E('button', { + 'class': 'cbi-button', 'click': ui.createHandlerFn(this, 'handleCounterReset', has_ip6tables) }, [ _('Reset Counters') ]), ' ', @@ -313,7 +348,7 @@ return view.extend({ }, [ _('Restart Firewall') ]) ]), E('div', {}, [ - E('div', { 'data-tab': 'iptables', 'data-tab-title': has_ip6tables ? _('IPv4 Firewall') : null }, [ + E('div', { 'data-tab': 'iptables', 'data-tab-title': has_ip6tables ? _('IPv4 Firewall') : null, 'data-tab-active': has_ip6tables ? null : true }, [ E('p', {}, E('em', { 'class': 'spinning' }, [ _('Collecting data...') ])) ]), has_ip6tables ? E('div', { 'data-tab': 'ip6tables', 'data-tab-title': _('IPv6 Firewall') }, [ diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/load.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/load.js index 3b302dc509..2766f5d1b5 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/load.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/load.js @@ -19,7 +19,7 @@ Math.log2 = Math.log2 || function(x) { return Math.log(x) * Math.LOG2E; }; return view.extend({ load: function() { return Promise.all([ - this.loadSVG(L.resource('load.svg')) + this.loadSVG(L.resource('svg/load.svg')) ]); }, @@ -226,36 +226,36 @@ return view.extend({ E('div', { 'class': 'right' }, E('small', { 'id': 'scale' }, '-')), E('br'), - E('div', { 'class': 'table', 'style': 'width:100%;table-layout:fixed' }, [ - E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid #f00' }, [ _('1 Minute Load:') ])), - E('div', { 'class': 'td', 'id': 'lb_load01_cur' }, [ '0.00' ]), + E('table', { 'class': 'table', 'style': 'width:100%;table-layout:fixed' }, [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid #f00' }, [ _('1 Minute Load:') ])), + E('td', { 'class': 'td', 'id': 'lb_load01_cur' }, [ '0.00' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), - E('div', { 'class': 'td', 'id': 'lb_load01_avg' }, [ '0.00' ]), + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), + E('td', { 'class': 'td', 'id': 'lb_load01_avg' }, [ '0.00' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), - E('div', { 'class': 'td', 'id': 'lb_load01_peak' }, [ '0.00' ]) + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), + E('td', { 'class': 'td', 'id': 'lb_load01_peak' }, [ '0.00' ]) ]), - E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid #f60' }, [ _('5 Minute Load:') ])), - E('div', { 'class': 'td', 'id': 'lb_load05_cur' }, [ '0.00' ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid #f60' }, [ _('5 Minute Load:') ])), + E('td', { 'class': 'td', 'id': 'lb_load05_cur' }, [ '0.00' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), - E('div', { 'class': 'td', 'id': 'lb_load05_avg' }, [ '0.00' ]), + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), + E('td', { 'class': 'td', 'id': 'lb_load05_avg' }, [ '0.00' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), - E('div', { 'class': 'td', 'id': 'lb_load05_peak' }, [ '0.00' ]) + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), + E('td', { 'class': 'td', 'id': 'lb_load05_peak' }, [ '0.00' ]) ]), - E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid #fa0' }, [ _('15 Minute Load:') ])), - E('div', { 'class': 'td', 'id': 'lb_load15_cur' }, [ '0.00' ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid #fa0' }, [ _('15 Minute Load:') ])), + E('td', { 'class': 'td', 'id': 'lb_load15_cur' }, [ '0.00' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), - E('div', { 'class': 'td', 'id': 'lb_load15_avg' }, [ '0.00' ]), + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), + E('td', { 'class': 'td', 'id': 'lb_load15_avg' }, [ '0.00' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), - E('div', { 'class': 'td', 'id': 'lb_load15_peak' }, [ '0.00' ]) + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), + E('td', { 'class': 'td', 'id': 'lb_load15_peak' }, [ '0.00' ]) ]) ]) ]); diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/processes.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/processes.js index 8a77306e57..e7d094a7f9 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/processes.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/processes.js @@ -64,14 +64,14 @@ return view.extend({ E('h2', _('Processes')), E('div', { 'class': 'cbi-map-descr' }, _('This list gives an overview over currently running system processes and their status.')), - E('div', { 'class': 'table' }, [ - E('div', { 'class': 'tr table-titles' }, [ - E('div', { 'class': 'th' }, _('PID')), - E('div', { 'class': 'th' }, _('Owner')), - E('div', { 'class': 'th' }, _('Command')), - E('div', { 'class': 'th' }, _('CPU usage (%)')), - E('div', { 'class': 'th' }, _('Memory usage (%)')), - E('div', { 'class': 'th center nowrap cbi-section-actions' }) + E('table', { 'class': 'table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('PID')), + E('th', { 'class': 'th' }, _('Owner')), + E('th', { 'class': 'th' }, _('Command')), + E('th', { 'class': 'th' }, _('CPU usage (%)')), + E('th', { 'class': 'th' }, _('Memory usage (%)')), + E('th', { 'class': 'th center nowrap cbi-section-actions' }) ]) ]) ]); diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/routes.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/routes.js index 5da5d403b1..ac512bb849 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/routes.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/routes.js @@ -135,7 +135,8 @@ return view.extend({ dest, (v6 ? flags.from : flags.via) || '-', String(flags.metric || 0), - flags.table || 'main' + flags.table || 'main', + flags.proto, ]); } @@ -149,39 +150,41 @@ return view.extend({ ip6neigh = data[3].stdout || '', ip6route = data[4].stdout || ''; - var neigh4tbl = E('div', { 'class': 'table' }, [ - E('div', { 'class': 'tr table-titles' }, [ - E('div', { 'class': 'th' }, [ _('IPv4-Address') ]), - E('div', { 'class': 'th' }, [ _('MAC-Address') ]), - E('div', { 'class': 'th' }, [ _('Interface') ]) + var neigh4tbl = E('table', { 'class': 'table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, [ _('IPv4-Address') ]), + E('th', { 'class': 'th' }, [ _('MAC-Address') ]), + E('th', { 'class': 'th' }, [ _('Interface') ]) ]) ]); - var route4tbl = E('div', { 'class': 'table' }, [ - E('div', { 'class': 'tr table-titles' }, [ - E('div', { 'class': 'th' }, [ _('Network') ]), - E('div', { 'class': 'th' }, [ _('Target') ]), - E('div', { 'class': 'th' }, [ _('IPv4-Gateway') ]), - E('div', { 'class': 'th' }, [ _('Metric') ]), - E('div', { 'class': 'th' }, [ _('Table') ]) + var route4tbl = E('table', { 'class': 'table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, [ _('Network') ]), + E('th', { 'class': 'th' }, [ _('Target') ]), + E('th', { 'class': 'th' }, [ _('IPv4-Gateway') ]), + E('th', { 'class': 'th' }, [ _('Metric') ]), + E('th', { 'class': 'th' }, [ _('Table') ]), + E('th', { 'class': 'th' }, [ _('Protocol') ]), ]) ]); - var neigh6tbl = E('div', { 'class': 'table' }, [ - E('div', { 'class': 'tr table-titles' }, [ - E('div', { 'class': 'th' }, [ _('IPv6-Address') ]), - E('div', { 'class': 'th' }, [ _('MAC-Address') ]), - E('div', { 'class': 'th' }, [ _('Interface') ]) + var neigh6tbl = E('table', { 'class': 'table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, [ _('IPv6-Address') ]), + E('th', { 'class': 'th' }, [ _('MAC-Address') ]), + E('th', { 'class': 'th' }, [ _('Interface') ]) ]) ]); - var route6tbl = E('div', { 'class': 'table' }, [ - E('div', { 'class': 'tr table-titles' }, [ - E('div', { 'class': 'th' }, [ _('Network') ]), - E('div', { 'class': 'th' }, [ _('Target') ]), - E('div', { 'class': 'th' }, [ _('Source') ]), - E('div', { 'class': 'th' }, [ _('Metric') ]), - E('div', { 'class': 'th' }, [ _('Table') ]) + var route6tbl = E('table', { 'class': 'table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, [ _('Network') ]), + E('th', { 'class': 'th' }, [ _('Target') ]), + E('th', { 'class': 'th' }, [ _('Source') ]), + E('th', { 'class': 'th' }, [ _('Metric') ]), + E('th', { 'class': 'th' }, [ _('Table') ]), + E('th', { 'class': 'th' }, [ _('Protocol') ]), ]) ]); @@ -212,4 +215,3 @@ return view.extend({ handleSave: null, handleReset: null }); - diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/wireless.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/wireless.js index 171899262a..0fdd3d56e7 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/wireless.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/wireless.js @@ -21,8 +21,8 @@ Math.log2 = Math.log2 || function(x) { return Math.log(x) * Math.LOG2E; }; return view.extend({ load: function() { return Promise.all([ - this.loadSVG(L.resource('wireless.svg')), - this.loadSVG(L.resource('wifirate.svg')), + this.loadSVG(L.resource('svg/wireless.svg')), + this.loadSVG(L.resource('svg/wifirate.svg')), network.getWifiDevices().then(function(radios) { var tasks = [], all_networks = []; @@ -255,26 +255,26 @@ return view.extend({ E('div', { 'class': 'right' }, E('small', { 'id': 'scale' }, '-')), E('br'), - E('div', { 'class': 'table', 'style': 'width:100%;table-layout:fixed' }, [ - E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid blue' }, [ _('Signal:') ])), - E('div', { 'class': 'td', 'id': 'rssi_bw_cur' }, [ '0 ' + _('dBm') ]), + E('table', { 'class': 'table', 'style': 'width:100%;table-layout:fixed' }, [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid blue' }, [ _('Signal:') ])), + E('td', { 'class': 'td', 'id': 'rssi_bw_cur' }, [ '0 ' + _('dBm') ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), - E('div', { 'class': 'td', 'id': 'rssi_bw_avg' }, [ '0 ' + _('dBm') ]), + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), + E('td', { 'class': 'td', 'id': 'rssi_bw_avg' }, [ '0 ' + _('dBm') ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), - E('div', { 'class': 'td', 'id': 'rssi_bw_peak' }, [ '0 ' + _('dBm') ]) + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), + E('td', { 'class': 'td', 'id': 'rssi_bw_peak' }, [ '0 ' + _('dBm') ]) ]), - E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid red' }, [ _('Noise:') ])), - E('div', { 'class': 'td', 'id': 'noise_bw_cur' }, [ '0 ' + _('dBm') ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid red' }, [ _('Noise:') ])), + E('td', { 'class': 'td', 'id': 'noise_bw_cur' }, [ '0 ' + _('dBm') ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), - E('div', { 'class': 'td', 'id': 'noise_bw_avg' }, [ '0 ' + _('dBm') ]), + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), + E('td', { 'class': 'td', 'id': 'noise_bw_avg' }, [ '0 ' + _('dBm') ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), - E('div', { 'class': 'td', 'id': 'noise_bw_peak' }, [ '0 ' + _('dBm') ]) + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), + E('td', { 'class': 'td', 'id': 'noise_bw_peak' }, [ '0 ' + _('dBm') ]) ]) ]), E('br'), @@ -283,16 +283,16 @@ return view.extend({ E('div', { 'class': 'right' }, E('small', { 'id': 'scale2' }, '-')), E('br'), - E('div', { 'class': 'table', 'style': 'width:100%;table-layout:fixed' }, [ - E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid green' }, [ _('Phy Rate:') ])), - E('div', { 'class': 'td', 'id': 'rate_bw_cur' }, [ '0 MBit/s' ]), + E('table', { 'class': 'table', 'style': 'width:100%;table-layout:fixed' }, [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td right top' }, E('strong', { 'style': 'border-bottom:2px solid green' }, [ _('Phy Rate:') ])), + E('td', { 'class': 'td', 'id': 'rate_bw_cur' }, [ '0 Mbit/s' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), - E('div', { 'class': 'td', 'id': 'rate_bw_avg' }, [ '0 MBit/s' ]), + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Average:') ])), + E('td', { 'class': 'td', 'id': 'rate_bw_avg' }, [ '0 Mbit/s' ]), - E('div', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), - E('div', { 'class': 'td', 'id': 'rate_bw_peak' }, [ '0 MBit/s' ]) + E('td', { 'class': 'td right top' }, E('strong', {}, [ _('Peak:') ])), + E('td', { 'class': 'td', 'id': 'rate_bw_peak' }, [ '0 Mbit/s' ]) ]) ]) ])); @@ -318,9 +318,9 @@ return view.extend({ this.updateGraph(ifname, csvg2, [ { line: 'rate', multiply: 0.001 } ], function(svg, info) { var G = svg.firstElementChild, tab = svg.parentNode; - G.getElementById('label_25').firstChild.data = '%.2f %s'.format(info.label_25, _('MBit/s')); - G.getElementById('label_50').firstChild.data = '%.2f %s'.format(info.label_50, _('MBit/s')); - G.getElementById('label_75').firstChild.data = '%.2f %s'.format(info.label_75, _('MBit/s')); + G.getElementById('label_25').firstChild.data = '%.2f %s'.format(info.label_25, _('Mbit/s')); + G.getElementById('label_50').firstChild.data = '%.2f %s'.format(info.label_50, _('Mbit/s')); + G.getElementById('label_75').firstChild.data = '%.2f %s'.format(info.label_75, _('Mbit/s')); tab.querySelector('#scale2').firstChild.data = _('(%d minute window, %d second interval)').format(info.timeframe, info.interval); |