Merge pull request #4598 from Ansuel/wifi_chan
luci-mod-status: add new channel analysis page
This commit is contained in:
commit
c49d33f6cb
7 changed files with 461 additions and 18 deletions
|
@ -57,21 +57,7 @@ function getColorForName(forName) {
|
||||||
else if (forName == 'wan')
|
else if (forName == 'wan')
|
||||||
return '#f09090';
|
return '#f09090';
|
||||||
|
|
||||||
random.seed(parseInt(sfh(forName), 16));
|
return random.derive_color(forName);
|
||||||
|
|
||||||
var r = random.get(128),
|
|
||||||
g = random.get(128),
|
|
||||||
min = 0,
|
|
||||||
max = 128;
|
|
||||||
|
|
||||||
if ((r + g) < 128)
|
|
||||||
min = 128 - r - g;
|
|
||||||
else
|
|
||||||
max = 255 - r - g;
|
|
||||||
|
|
||||||
var b = min + Math.floor(random.get() * (max - min));
|
|
||||||
|
|
||||||
return '#%02x%02x%02x'.format(0xff - r, 0xff - g, 0xff - b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -89,5 +89,23 @@ return L.Class.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
return Math.floor(r * (u - l + 1)) + l;
|
return Math.floor(r * (u - l + 1)) + l;
|
||||||
|
},
|
||||||
|
|
||||||
|
derive_color: function(string) {
|
||||||
|
this.seed(parseInt(sfh(string), 16));
|
||||||
|
|
||||||
|
var r = this.get(128),
|
||||||
|
g = this.get(128),
|
||||||
|
min = 0,
|
||||||
|
max = 128;
|
||||||
|
|
||||||
|
if ((r + g) < 128)
|
||||||
|
min = 128 - r - g;
|
||||||
|
else
|
||||||
|
max = 255 - r - g;
|
||||||
|
|
||||||
|
var b = min + Math.floor(this.get() * (max - min));
|
||||||
|
|
||||||
|
return '#%02x%02x%02x'.format(0xff - r, 0xff - g, 0xff - b);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -3597,9 +3597,11 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ {
|
||||||
this.setActiveTabId(panes[selected], selected);
|
this.setActiveTabId(panes[selected], selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
panes[selected].dispatchEvent(new CustomEvent('cbi-tab-active', {
|
requestAnimationFrame(L.bind(function(pane) {
|
||||||
detail: { tab: panes[selected].getAttribute('data-tab') }
|
pane.dispatchEvent(new CustomEvent('cbi-tab-active', {
|
||||||
|
detail: { tab: pane.getAttribute('data-tab') }
|
||||||
}));
|
}));
|
||||||
|
}, this, panes[selected]));
|
||||||
|
|
||||||
this.updateTabs(group);
|
this.updateTabs(group);
|
||||||
},
|
},
|
||||||
|
|
|
@ -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>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,396 @@
|
||||||
|
'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 = [];
|
||||||
|
|
||||||
|
for (var i=0; i < channels.length; i++) {
|
||||||
|
var chan_offset = offset_tbl[channels[i]],
|
||||||
|
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, is5GHz) {
|
||||||
|
var 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].channel
|
||||||
|
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].channel;
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
var center_channels = [local_wifi.center_chan1],
|
||||||
|
chan_width_text = local_wifi.htmode.replace(/(V)*HT/,''),
|
||||||
|
chan_width;
|
||||||
|
|
||||||
|
if (local_wifi.center_chan2) {
|
||||||
|
center_channels.push(local_wifi.center_chan2);
|
||||||
|
chan_width = 8;
|
||||||
|
} else {
|
||||||
|
chan_width = parseInt(chan_width_text)/10;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
res.channel_width = "20 MHz";
|
||||||
|
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 csvg = svg.cloneNode(true),
|
||||||
|
freq_tbl = wifiDevs[ifname].freq,
|
||||||
|
is5GHz = freq_tbl[0].mhz >= 5000,
|
||||||
|
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, 'data-tab-title': ifname+' ('+(is5GHz ? '5GHz' : '2.4GHz')+') ' },
|
||||||
|
[E('br'),csvg,E('br'),table,E('br')]),
|
||||||
|
graph_data = {
|
||||||
|
graph: csvg,
|
||||||
|
offset_tbl: {},
|
||||||
|
col_width: 0,
|
||||||
|
tab: tab,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.radios[ifname] = {
|
||||||
|
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, is5GHz));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
});
|
|
@ -71,6 +71,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"admin/status/channel_analysis": {
|
||||||
|
"title": "Channel Analysis",
|
||||||
|
"order": 7,
|
||||||
|
"action": {
|
||||||
|
"type": "view",
|
||||||
|
"path": "status/channel_analysis"
|
||||||
|
},
|
||||||
|
"depends": {
|
||||||
|
"acl": [ "luci-mod-status-channel_analysis" ],
|
||||||
|
"uci": { "wireless": { "@wifi-device": true } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"admin/status/realtime": {
|
"admin/status/realtime": {
|
||||||
"title": "Realtime Graphs",
|
"title": "Realtime Graphs",
|
||||||
"order": 7,
|
"order": 7,
|
||||||
|
|
|
@ -56,6 +56,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"luci-mod-status-channel_analysis": {
|
||||||
|
"description": "Grant access to the system route status",
|
||||||
|
"read": {
|
||||||
|
"ubus": {
|
||||||
|
"iwinfo": [ "info", "freqlist" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"luci-mod-status-firewall": {
|
"luci-mod-status-firewall": {
|
||||||
"description": "Grant access to firewall status",
|
"description": "Grant access to firewall status",
|
||||||
"read": {
|
"read": {
|
||||||
|
|
Loading…
Reference in a new issue