diff options
Diffstat (limited to 'applications/luci-app-dawn/htdocs')
3 files changed, 240 insertions, 0 deletions
diff --git a/applications/luci-app-dawn/htdocs/luci-static/resources/dawn/dawn-common.js b/applications/luci-app-dawn/htdocs/luci-static/resources/dawn/dawn-common.js new file mode 100644 index 0000000000..5d002d9b7f --- /dev/null +++ b/applications/luci-app-dawn/htdocs/luci-static/resources/dawn/dawn-common.js @@ -0,0 +1,69 @@ +'use strict'; +'require baseclass'; +'require rpc'; + +let callDawnGetNetwork, callDawnGetHearingMap, callHostHints; + +callDawnGetNetwork = rpc.declare({ + object: 'dawn', + method: 'get_network', + expect: { } +}); + +callDawnGetHearingMap = rpc.declare({ + object: 'dawn', + method: 'get_hearing_map', + expect: { } +}); + +callHostHints = rpc.declare({ + object: 'luci-rpc', + method: 'getHostHints', + expect: { } +}); + +function getAvailableText(available) { + return ( available ? _('Available') : _('Not available') ); +} + +function getChannelFromFrequency(freq) { + if (freq <= 2400) { + return 0; + } + else if (freq == 2484) { + return 14; + } + else if (freq < 2484) { + return (freq - 2407) / 5; + } + else if (freq >= 4910 && freq <= 4980) { + return (freq - 4000) / 5; + } + else if (freq <= 45000) { + return (freq - 5000) / 5; + } + else if (freq >= 58320 && freq <= 64800) { + return (freq - 56160) / 2160; + } + else { + return 0; + } +} + +function getFormattedNumber(num, decimals, divider = 1) { + return (num/divider).toFixed(decimals); +} + +function getHostnameFromMAC(hosthints, mac) { + return ( hosthints[mac] && hosthints[mac].name ? hosthints[mac].name : mac); +} + +return L.Class.extend({ + callDawnGetNetwork: callDawnGetNetwork, + callDawnGetHearingMap: callDawnGetHearingMap, + callHostHints: callHostHints, + getAvailableText: getAvailableText, + getChannelFromFrequency: getChannelFromFrequency, + getFormattedNumber: getFormattedNumber, + getHostnameFromMAC: getHostnameFromMAC +}); diff --git a/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/hearing_map.js b/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/hearing_map.js new file mode 100644 index 0000000000..ea2aa67998 --- /dev/null +++ b/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/hearing_map.js @@ -0,0 +1,78 @@ +'use strict'; +'require uci'; +'require view'; +'require dawn.dawn-common as dawn'; + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + + load: function() { + return Promise.all([ + dawn.callDawnGetHearingMap(), + dawn.callHostHints() + ]); + }, + + render: function(data) { + + const dawnHearingMapData = data[0]; + const hostHintsData = data[1]; + + const body = E([ + E('h2', _('Hearing Map')) + ]); + + for (let network in dawnHearingMapData) { + + body.appendChild( + E('h3', 'SSID: ' + network) + ); + + let hearing_map_table = E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('Client')), + E('th', { 'class': 'th' }, _('Access Point')), + E('th', { 'class': 'th' }, _('Frequency')), + E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('High Throughput') }, [ _('HT') ])), + E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('Very High Throughput') }, [ _('VHT') ])), + E('th', { 'class': 'th' }, _('Signal')), + 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' }, _('Channel Utilization')), + E('th', { 'class': 'th' }, _('Stations Connected')), + E('th', { 'class': 'th' }, _('Score')) + ]) + ]); + + let clients = Object.entries(dawnHearingMapData[network]).map(function(client) { + + return Object.entries(client[1]).map(function(ap) { + + if (ap[1].freq != 0) { + return [ + dawn.getHostnameFromMAC(hostHintsData, client[0]), + dawn.getHostnameFromMAC(hostHintsData, ap[0]), + 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].vht_capabilities && ap[1].vht_support), + ap[1].signal, + ap[1].rcpi, + ap[1].rsni, + dawn.getFormattedNumber(ap[1].channel_utilization, 2, 2.55) + '%', + ap[1].num_sta, + ap[1].score + ] + } + }).flat() + + }); + + cbi_update_table(hearing_map_table, clients, E('em', _('No clients connected.'))); + + body.appendChild(hearing_map_table); + } + return body; + } +}); diff --git a/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/network_overview.js b/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/network_overview.js new file mode 100644 index 0000000000..71133991ab --- /dev/null +++ b/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/network_overview.js @@ -0,0 +1,93 @@ +'use strict'; +'require uci'; +'require view'; +'require dawn.dawn-common as dawn'; + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + + load: function() { + return Promise.all([ + dawn.callDawnGetNetwork(), + dawn.callHostHints() + ]); + }, + + render: function(data) { + + const dawnNetworkData = data[0]; + const hostHintsData = data[1]; + + const body = E([ + E('h2', _('Network Overview')) + ]); + + let client_table = {}; + + for (let network in dawnNetworkData) { + + body.appendChild( + E('h3', 'SSID: ' + network) + ); + + let ap_table = E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th left cbi-section-actions' }, _('Access Point')), + E('th', { 'class': 'th left cbi-section-actions' }, _('Interface')), + E('th', { 'class': 'th left cbi-section-actions' }, _('MAC')), + E('th', { 'class': 'th left cbi-section-actions' }, _('Utilization')), + E('th', { 'class': 'th left cbi-section-actions' }, _('Frequency')), + E('th', { 'class': 'th left cbi-section-actions' }, _('Stations Connected')), + E('th', { 'class': 'th left cbi-section-actions' }, E('span', { 'data-tooltip': _('High Throughput') }, [ _('HT') ])), + E('th', { 'class': 'th left cbi-section-actions' }, E('span', { 'data-tooltip': _('Very High Throughput') }, [ _('VHT') ])), + E('th', { 'class': 'th center cbi-section-actions' }, _('Clients')), + ]) + ]); + + let aps = Object.entries(dawnNetworkData[network]).map(function(ap) { + client_table[ap[0]] = E('table', { 'class': 'table cbi-section-table', 'style': 'display: table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('Client')), + E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('High Throughput') }, [ _('HT') ])), + E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('Very High Throughput') }, [ _('VHT') ])), + E('th', { 'class': 'th' }, _('Signal')) + ]) + ]); + + let clients = []; + let clientData = Object.entries(ap[1]); + for (let i = 0; i < clientData.length; i++) { + if (typeof clientData[i][1] === 'object') { + clients.push([ + dawn.getHostnameFromMAC(hostHintsData ,clientData[i][0]), + dawn.getAvailableText(clientData[i][1].ht), + dawn.getAvailableText(clientData[i][1].vht), + clientData[i][1].signal + ]); + } + } + + cbi_update_table(client_table[ap[0]], clients, E('em', _('No clients connected.'))); + + return [ + ap[1].hostname, + ap[1].iface, + ap[0], + dawn.getFormattedNumber(ap[1].channel_utilization, 2, 2.55) + '%', + dawn.getFormattedNumber(ap[1].freq, 3, 1000) + ' GHz (' + _('Channel') + ': ' + dawn.getChannelFromFrequency(ap[1].freq) + ')', + ap[1].num_sta, + dawn.getAvailableText(ap[1].ht_support), + dawn.getAvailableText(ap[1].vht_support), + ap[1].num_sta > 0 ? client_table[ap[0]] : E('em', { 'style': 'display: inline' }, _('No clients connected.')) + ] + }); + + cbi_update_table(ap_table, aps, E('em', _('No access points available.'))); + + body.appendChild(ap_table); + } + return body; + } +}); |