summaryrefslogtreecommitdiffhomepage
path: root/applications/luci-app-dawn/htdocs
diff options
context:
space:
mode:
Diffstat (limited to 'applications/luci-app-dawn/htdocs')
-rw-r--r--applications/luci-app-dawn/htdocs/luci-static/resources/dawn/dawn-common.js90
-rw-r--r--applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/hearing_map.js103
-rw-r--r--applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/network_overview.js99
3 files changed, 292 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..9dec2c6ec1
--- /dev/null
+++ b/applications/luci-app-dawn/htdocs/luci-static/resources/dawn/dawn-common.js
@@ -0,0 +1,90 @@
+'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 isDawnRPCAvailable() {
+ return rpc.list("dawn").then(function(signatures) {
+ return 'dawn' in signatures && 'get_network' in signatures.dawn && 'get_hearing_map' in signatures.dawn;
+ });
+}
+
+function getAvailableText(available) {
+ return ( available ? _('Available') : _('Not available') );
+}
+
+function getYesText(yes) {
+ return ( yes ? _('Yes') : _('No') );
+}
+
+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 + ')' : mac );
+}
+
+function getDawnServiceNotRunningErrorMessage() {
+ return E('div', { 'class': 'alert-message fade-in warning' }, [
+ E('h4', _('DAWN service unavailable')),
+ E('p', _('Unable to query the DAWN service via ubus, the service appears to be stopped.')),
+ E('a', { 'href': L.url('admin/system/startup') }, _('Check Startup services'))
+ ]);
+}
+
+return L.Class.extend({
+ callDawnGetNetwork: callDawnGetNetwork,
+ callDawnGetHearingMap: callDawnGetHearingMap,
+ callHostHints: callHostHints,
+ isDawnRPCAvailable: isDawnRPCAvailable,
+ getAvailableText: getAvailableText,
+ getYesText: getYesText,
+ getChannelFromFrequency: getChannelFromFrequency,
+ getFormattedNumber: getFormattedNumber,
+ getHostnameFromMAC: getHostnameFromMAC,
+ getDawnServiceNotRunningErrorMessage: getDawnServiceNotRunningErrorMessage
+});
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..8b93fbfd6d
--- /dev/null
+++ b/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/hearing_map.js
@@ -0,0 +1,103 @@
+'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.isDawnRPCAvailable().then(function(isAvailable) {
+ return ( isAvailable ? dawn.callDawnGetHearingMap() : null )
+ }),
+ dawn.isDawnRPCAvailable().then(function(isAvailable) {
+ return ( isAvailable ? dawn.callDawnGetNetwork() : null )
+ }),
+ dawn.callHostHints()
+ ]);
+ },
+
+ render: function(data) {
+
+ const dawnHearingMapData = data[0];
+ 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]);
+ }
+ }
+ });
+ }
+
+ if (!dawnHearingMapData || !dawnNetworkData) {
+ return dawn.getDawnServiceNotRunningErrorMessage();
+ }
+
+ 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' }, _('Connected to Network')),
+ 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(accessPointsHintsData, 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) + '%',
+ dawn.getYesText(connectedClients[network].includes(client[0])),
+ 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..a605858eca
--- /dev/null
+++ b/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/network_overview.js
@@ -0,0 +1,99 @@
+'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.isDawnRPCAvailable().then(function(isAvailable) {
+ return ( isAvailable ? dawn.callDawnGetNetwork() : null );
+ }),
+ dawn.callHostHints()
+ ]);
+ },
+
+ render: function(data) {
+
+ const dawnNetworkData = data[0];
+ const hostHintsData = data[1];
+
+ if (!dawnNetworkData) {
+ return dawn.getDawnServiceNotRunningErrorMessage();
+ }
+
+ 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;
+ }
+});