luci-app-dawn: Bug fixes for JavaScript implementation

Some bug fixes and a small improvements that were discovered after the
initial implementation of the JavaScript version of luci-app-dawn:

* Correctly show multiple APs per client in the hearing map
* Display correct name of all APs in the hearing map
* Show if client is connected to the network in the hearing map. This
  replaces the column for Stations Connected, which is not a property
  of a client but of an AP, and is available still in the network overview.
* Display both hostname and MAC address for clients/APs
* Convert spaces to tabs in dawn-common.js for consistency

Signed-off-by: Daniel Vijge <danielvijge@gmail.com>
This commit is contained in:
Daniel Vijge 2023-11-05 21:17:33 +01:00 committed by Nick Hainke
parent b23b00e478
commit e8029b0828
2 changed files with 68 additions and 46 deletions

View file

@ -5,65 +5,70 @@
let callDawnGetNetwork, callDawnGetHearingMap, callHostHints; let callDawnGetNetwork, callDawnGetHearingMap, callHostHints;
callDawnGetNetwork = rpc.declare({ callDawnGetNetwork = rpc.declare({
object: 'dawn', object: 'dawn',
method: 'get_network', method: 'get_network',
expect: { } expect: { }
}); });
callDawnGetHearingMap = rpc.declare({ callDawnGetHearingMap = rpc.declare({
object: 'dawn', object: 'dawn',
method: 'get_hearing_map', method: 'get_hearing_map',
expect: { } expect: { }
}); });
callHostHints = rpc.declare({ callHostHints = rpc.declare({
object: 'luci-rpc', object: 'luci-rpc',
method: 'getHostHints', method: 'getHostHints',
expect: { } expect: { }
}); });
function getAvailableText(available) { function getAvailableText(available) {
return ( available ? _('Available') : _('Not available') ); return ( available ? _('Available') : _('Not available') );
}
function getYesText(yes) {
return ( yes ? _('Yes') : _('No') );
} }
function getChannelFromFrequency(freq) { function getChannelFromFrequency(freq) {
if (freq <= 2400) { if (freq <= 2400) {
return 0; return 0;
} }
else if (freq == 2484) { else if (freq == 2484) {
return 14; return 14;
} }
else if (freq < 2484) { else if (freq < 2484) {
return (freq - 2407) / 5; return (freq - 2407) / 5;
} }
else if (freq >= 4910 && freq <= 4980) { else if (freq >= 4910 && freq <= 4980) {
return (freq - 4000) / 5; return (freq - 4000) / 5;
} }
else if (freq <= 45000) { else if (freq <= 45000) {
return (freq - 5000) / 5; return (freq - 5000) / 5;
} }
else if (freq >= 58320 && freq <= 64800) { else if (freq >= 58320 && freq <= 64800) {
return (freq - 56160) / 2160; return (freq - 56160) / 2160;
} }
else { else {
return 0; return 0;
} }
} }
function getFormattedNumber(num, decimals, divider = 1) { function getFormattedNumber(num, decimals, divider = 1) {
return (num/divider).toFixed(decimals); return (num/divider).toFixed(decimals);
} }
function getHostnameFromMAC(hosthints, mac) { function getHostnameFromMAC(hosthints, mac) {
return ( hosthints[mac] && hosthints[mac].name ? hosthints[mac].name : mac); return ( hosthints[mac] && hosthints[mac].name ? hosthints[mac].name + ' (' + mac + ')' : mac);
} }
return L.Class.extend({ return L.Class.extend({
callDawnGetNetwork: callDawnGetNetwork, callDawnGetNetwork: callDawnGetNetwork,
callDawnGetHearingMap: callDawnGetHearingMap, callDawnGetHearingMap: callDawnGetHearingMap,
callHostHints: callHostHints, callHostHints: callHostHints,
getAvailableText: getAvailableText, getAvailableText: getAvailableText,
getChannelFromFrequency: getChannelFromFrequency, getYesText: getYesText,
getFormattedNumber: getFormattedNumber, getChannelFromFrequency: getChannelFromFrequency,
getHostnameFromMAC: getHostnameFromMAC getFormattedNumber: getFormattedNumber,
getHostnameFromMAC: getHostnameFromMAC
}); });

View file

@ -11,6 +11,7 @@ return view.extend({
load: function() { load: function() {
return Promise.all([ return Promise.all([
dawn.callDawnGetHearingMap(), dawn.callDawnGetHearingMap(),
dawn.callDawnGetNetwork(),
dawn.callHostHints() dawn.callHostHints()
]); ]);
}, },
@ -18,7 +19,23 @@ return view.extend({
render: function(data) { render: function(data) {
const dawnHearingMapData = data[0]; const dawnHearingMapData = data[0];
const hostHintsData = data[1]; const dawnNetworkData = data[1];
const hostHintsData = data[2];
let accessPointsHintsData = {};
let connectedClients = {};
for (let network in dawnNetworkData) {
connectedClients[network] = [];
let aps = Object.entries(dawnNetworkData[network]).map(function(ap) {
accessPointsHintsData[ap[0]] = {name: ap[1].hostname};
let clientData = Object.entries(ap[1]);
for (let i = 0; i < clientData.length; i++) {
if (typeof clientData[i][1] === 'object') {
connectedClients[network].push(clientData[i][0]);
}
}
});
}
const body = E([ const body = E([
E('h2', _('Hearing Map')) E('h2', _('Hearing Map'))
@ -41,7 +58,7 @@ return view.extend({
E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('Received Channel Power Indication') }, [ _('RCPI') ])), E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('Received Channel Power Indication') }, [ _('RCPI') ])),
E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('Received Signal to Noise Indicator') }, [ _('RSNI') ])), E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('Received Signal to Noise Indicator') }, [ _('RSNI') ])),
E('th', { 'class': 'th' }, _('Channel Utilization')), E('th', { 'class': 'th' }, _('Channel Utilization')),
E('th', { 'class': 'th' }, _('Stations Connected')), E('th', { 'class': 'th' }, _('Connected to Network')),
E('th', { 'class': 'th' }, _('Score')) E('th', { 'class': 'th' }, _('Score'))
]) ])
]); ]);
@ -53,7 +70,7 @@ return view.extend({
if (ap[1].freq != 0) { if (ap[1].freq != 0) {
return [ return [
dawn.getHostnameFromMAC(hostHintsData, client[0]), dawn.getHostnameFromMAC(hostHintsData, client[0]),
dawn.getHostnameFromMAC(hostHintsData, ap[0]), dawn.getHostnameFromMAC(accessPointsHintsData, ap[0]),
dawn.getFormattedNumber(ap[1].freq, 3, 1000) + ' GHz (' + _('Channel') + ': ' + dawn.getChannelFromFrequency(ap[1].freq) + ')', dawn.getFormattedNumber(ap[1].freq, 3, 1000) + ' GHz (' + _('Channel') + ': ' + dawn.getChannelFromFrequency(ap[1].freq) + ')',
dawn.getAvailableText(ap[1].ht_capabilities && ap[1].ht_support), dawn.getAvailableText(ap[1].ht_capabilities && ap[1].ht_support),
dawn.getAvailableText(ap[1].vht_capabilities && ap[1].vht_support), dawn.getAvailableText(ap[1].vht_capabilities && ap[1].vht_support),
@ -61,13 +78,13 @@ return view.extend({
ap[1].rcpi, ap[1].rcpi,
ap[1].rsni, ap[1].rsni,
dawn.getFormattedNumber(ap[1].channel_utilization, 2, 2.55) + '%', dawn.getFormattedNumber(ap[1].channel_utilization, 2, 2.55) + '%',
ap[1].num_sta, dawn.getYesText(connectedClients[network].includes(client[0])),
ap[1].score ap[1].score
] ]
} }
}).flat() })
}); }).flat();
cbi_update_table(hearing_map_table, clients, E('em', _('No clients connected.'))); cbi_update_table(hearing_map_table, clients, E('em', _('No clients connected.')));