luci-mod-admin-full: rework network and wifi status displays
authorJo-Philipp Wich <jo@mein.io>
Wed, 30 May 2018 12:50:14 +0000 (14:50 +0200)
committerJo-Philipp Wich <jo@mein.io>
Wed, 30 May 2018 12:59:24 +0000 (14:59 +0200)
Use a more compact flex layout instead of the tabular display.
Also rename "WAN status" to "Upstream" to avoid future confusion about
wan interfaces vs. defaultroute interfaces.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-mod-admin-full/luasrc/view/admin_status/index.htm

index d22445b01819a8d967a78050c0fed2c18c687524..73e5516bf5ba63df4e914f219811a06c3fb4e361 100644 (file)
@@ -6,6 +6,7 @@
 
 <%
        local fs = require "nixio.fs"
+       local ipc = require "luci.ip"
        local util = require "luci.util"
        local stat = require "luci.tools.status"
        local ver = require "luci.version"
@@ -58,6 +59,8 @@
                }
 
                if wan then
+                       local dev = wan:get_interface()
+                       local link = dev and ipc.link(dev:name())
                        rv.wan = {
                                ipaddr  = wan:ipaddr(),
                                gwaddr  = wan:gwaddr(),
                                expires = wan:expires(),
                                uptime  = wan:uptime(),
                                proto   = wan:proto(),
+                               i18n    = wan:get_i18n(),
                                ifname  = wan:ifname(),
-                               link    = wan:adminlink()
+                               link    = wan:adminlink(),
+                               mac     = dev and dev:mac(),
+                               type    = dev and dev:type(),
+                               name    = dev and dev:get_i18n(),
+                               ether   = link and link.type == 1
                        }
                end
 
                if wan6 then
+                       local dev = wan6:get_interface()
+                       local link = dev and ipc.link(dev:name())
                        rv.wan6 = {
                                ip6addr   = wan6:ip6addr(),
                                gw6addr   = wan6:gw6addr(),
                                ip6prefix = wan6:ip6prefix(),
                                uptime    = wan6:uptime(),
                                proto     = wan6:proto(),
+                               i18n      = wan6:get_i18n(),
                                ifname    = wan6:ifname(),
-                               link      = wan6:adminlink()
+                               link      = wan6:adminlink(),
+                               mac       = dev and dev:mac(),
+                               type      = dev and dev:type(),
+                               name      = dev and dev:get_i18n(),
+                               ether     = link and link.type == 1
                        }
                end
 
                });
        }
 
-       XHR.poll(5, '<%=REQUEST_URI%>', { status: 1 },
-               function(x, info)
-               {
-                       if (!(npoll++ % 5))
-                               updateHosts();
+       function labelList(items, offset) {
+               var rv = [ ];
 
-                       var si = document.getElementById('wan4_i');
-                       var ss = document.getElementById('wan4_s');
-                       var ifc = info.wan;
+               for (var i = offset || 0; i < items.length; i += 2) {
+                       var label = items[i],
+                           value = items[i+1];
 
-                       if (ifc && ifc.ifname && ifc.proto != 'none')
-                       {
-                               var s = String.format(
-                                       '<strong><%:Type%>: </strong>%s<br />' +
-                                       '<strong><%:Address%>: </strong>%s<br />' +
-                                       '<strong><%:Netmask%>: </strong>%s<br />' +
-                                       '<strong><%:Gateway%>: </strong>%s<br />',
-                                               ifc.proto,
-                                               (ifc.ipaddr) ? ifc.ipaddr : '0.0.0.0',
-                                               (ifc.netmask && ifc.netmask != ifc.ipaddr) ? ifc.netmask : '255.255.255.255',
-                                               (ifc.gwaddr) ? ifc.gwaddr : '0.0.0.0'
-                               );
+                       if (value === undefined || value === null)
+                               continue;
 
-                               for (var i = 0; i < ifc.dns.length; i++)
-                               {
-                                       s += String.format(
-                                               '<strong><%:DNS%> %d: </strong>%s<br />',
-                                               i + 1, ifc.dns[i]
-                                       );
-                               }
+                       if (label)
+                               rv.push(E('strong', [label, ': ']));
 
-                               if (ifc.expires > -1)
-                               {
-                                       s += String.format(
-                                               '<strong><%:Expires%>: </strong>%t<br />',
-                                               ifc.expires
-                                       );
-                               }
-
-                               if (ifc.uptime > 0)
-                               {
-                                       s += String.format(
-                                               '<strong><%:Connected%>: </strong>%t<br />',
-                                               ifc.uptime
-                                       );
-                               }
-
-                               ss.innerHTML = String.format('<small>%s</small>', s);
-                               si.innerHTML = String.format(
-                                       '<img src="<%=resource%>/icons/ethernet.png" />' +
-                                       '<br /><small><a href="%s">%s</a></small>',
-                                               ifc.link, ifc.ifname
-                               );
-                       }
-                       else
-                       {
-                               si.innerHTML = '<img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small>';
-                               ss.innerHTML = '<em><%:Not connected%></em>';
-                       }
+                       rv.push(value, E('br'));
+               }
 
-                       <% if has_ipv6 then %>
-                       var si6 = document.getElementById('wan6_i');
-                       var ss6 = document.getElementById('wan6_s');
-                       var ifc6 = info.wan6;
+               return rv;
+       }
 
-                       if (ifc6 && ifc6.ifname && ifc6.proto != 'none')
-                       {
-                               var s = String.format(
-                                       '<strong><%:Type%>: </strong>%s%s<br />',
-                                               ifc6.proto, (ifc6.ip6prefix) ? '-pd' : ''
-                               );
+       function renderBox(title, active, childs) {
+               childs = childs || [];
+               childs.unshift(E('span', labelList(arguments, 3)));
 
-                               if (!ifc6.ip6prefix)
-                               {
-                                       s += String.format(
-                                               '<strong><%:Address%>: </strong>%s<br />',
-                                               (ifc6.ip6addr) ? ifc6.ip6addr : '::'
-                                       );
-                               }
-                               else
-                               {
-                                       s += String.format(
-                                               '<strong><%:Prefix Delegated%>: </strong>%s<br />',
-                                               ifc6.ip6prefix
-                                       );
-                                       if (ifc6.ip6addr)
-                                       {
-                                               s += String.format(
-                                                       '<strong><%:Address%>: </strong>%s<br />',
-                                                       ifc6.ip6addr
-                                               );
-                                       }
-                               }
+               return E('div', { class: 'ifacebox' }, [
+                       E('div', { class: 'ifacebox-head center ' + (active ? 'active' : '') },
+                               E('strong', title)),
+                       E('div', { class: 'ifacebox-body' }, childs)
+               ]);
+       }
 
-                               s += String.format(
-                                       '<strong><%:Gateway%>: </strong>%s<br />',
-                                               (ifc6.gw6addr) ? ifc6.gw6addr : '::'
-                               );
+       function renderBadge(icon, title) {
+               return E('span', { class: 'ifacebadge' }, [
+                       E('img', { src: icon, title: title || '' }),
+                       E('span', labelList(arguments, 2))
+               ]);
+       }
 
-                               for (var i = 0; i < ifc6.dns.length; i++)
-                               {
-                                       s += String.format(
-                                               '<strong><%:DNS%> %d: </strong>%s<br />',
-                                               i + 1, ifc6.dns[i]
-                                       );
-                               }
+       XHR.poll(5, '<%=REQUEST_URI%>', { status: 1 },
+               function(x, info)
+               {
+                       if (!(npoll++ % 5))
+                               updateHosts();
 
-                               if (ifc6.uptime > 0)
-                               {
-                                       s += String.format(
-                                               '<strong><%:Connected%>: </strong>%t<br />',
-                                               ifc6.uptime
-                                       );
-                               }
+                       var us = document.getElementById('upstream_status_table');
+
+                       while (us.lastElementChild)
+                               us.removeChild(us.lastElementChild);
+
+                       var ifc = info.wan || {};
+
+                       us.appendChild(renderBox(
+                               '<%:IPv4 Upstream%>',
+                               (ifc.ifname && ifc.proto != 'none'),
+                               [ renderBadge(
+                                       '<%=resource%>/icons/%s.png'.format((ifc && ifc.type) ? ifc.type : 'ethernet_disabled'), null,
+                                       '<%:Device%>', ifc ? (ifc.name || ifc.ifname || '-') : '-',
+                                       '<%:MAC-Address%>', (ifc && ifc.ether) ? ifc.mac : null) ],
+                               '<%:Protocol%>', ifc.i18n || E('em', '<%:Not connected%>'),
+                               '<%:Address%>', (ifc.ipaddr) ? ifc.ipaddr : '0.0.0.0',
+                               '<%:Netmask%>', (ifc.netmask && ifc.netmask != ifc.ipaddr) ? ifc.netmask : '255.255.255.255',
+                               '<%:Gateway%>', (ifc.gwaddr) ? ifc.gwaddr : '0.0.0.0',
+                               '<%:DNS%> 1', (ifc.dns) ? ifc.dns[0] : null,
+                               '<%:DNS%> 2', (ifc.dns) ? ifc.dns[1] : null,
+                               '<%:DNS%> 3', (ifc.dns) ? ifc.dns[2] : null,
+                               '<%:DNS%> 4', (ifc.dns) ? ifc.dns[3] : null,
+                               '<%:DNS%> 5', (ifc.dns) ? ifc.dns[4] : null,
+                               '<%:Expires%>', (ifc.expires > -1) ? '%t'.format(ifc.expires) : null,
+                               '<%:Connected%>', (ifc.uptime > 0) ? '%t'.format(ifc.uptime) : null));
 
-                               ss6.innerHTML = String.format('<small>%s</small>', s);
-                               si6.innerHTML = String.format(
-                                       '<img src="<%=resource%>/icons/ethernet.png" />' +
-                                       '<br /><small><a href="%s">%s</a></small>',
-                                               ifc6.link, ifc6.ifname
-                               );
-                       }
-                       else
-                       {
-                               si6.innerHTML = '<img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small>';
-                               ss6.innerHTML = '<em><%:Not connected%></em>';
-                       }
+                       <% if has_ipv6 then %>
+                       var ifc6 = info.wan6 || {};
+
+                       us.appendChild(renderBox(
+                               '<%:IPv6 Upstream%>',
+                               (ifc6.ifname && ifc6.proto != 'none'),
+                               [ renderBadge(
+                                       '<%=resource%>/icons/%s.png'.format(ifc6.type || 'ethernet_disabled'), null,
+                                       '<%:Device%>', ifc6 ? (ifc6.name || ifc6.ifname || '-') : '-',
+                                       '<%:MAC-Address%>', (ifc6 && ifc6.ether) ? ifc6.mac : null) ],
+                               '<%:Protocol%>', ifc6.i18n ? (ifc6.i18n + (ifc6.proto === 'dhcp' && ifc6.ip6prefix ? '-PD' : '')) : E('em', '<%:Not connected%>'),
+                               '<%:Prefix Delegated%>', ifc6.ip6prefix,
+                               '<%:Address%>', (ifc6.ip6prefix) ? (ifc6.ip6addr || null) : (ifc6.ipaddr || '::'),
+                               '<%:Gateway%>', (ifc6.gw6addr) ? ifc6.gw6addr : '::',
+                               '<%:DNS%> 1', (ifc6.dns) ? ifc6.dns[0] : null,
+                               '<%:DNS%> 2', (ifc6.dns) ? ifc6.dns[1] : null,
+                               '<%:DNS%> 3', (ifc6.dns) ? ifc6.dns[2] : null,
+                               '<%:DNS%> 4', (ifc6.dns) ? ifc6.dns[3] : null,
+                               '<%:DNS%> 5', (ifc6.dns) ? ifc6.dns[4] : null,
+                               '<%:Connected%>', (ifc6.uptime > 0) ? '%t'.format(ifc6.uptime) : null));
                        <% end %>
 
                        <% if has_dsl then %>
                                                        hint = host.name;
                                        }
 
-                                       ls6.appendChild(E('<div class="tr cbi-section-table-row cbi-rowstyle-%d" style="max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space: nowrap">'.format((i % 2) + 1), [
-                                               E('<div class="td">', hint ? '<div style="max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space: nowrap">%h (%h)</div>'.format(name || '?', hint) : (name || '?')),
-                                               E('<div class="td">', info.leases6[i].ip6addr),
-                                               E('<div class="td">', info.leases6[i].duid),
-                                               E('<div class="td">', timestr)
+                                       ls6.appendChild(E('<div class="tr cbi-section-table-row cbi-rowstyle-%d">'.format((i % 2) + 1), [
+                                               E('<div class="td nowrap">', hint ? '<div>%h (%h)</div>'.format(name || '?', hint) : (name || '?')),
+                                               E('<div class="td nowrap">', info.leases6[i].ip6addr),
+                                               E('<div class="td nowrap">', info.leases6[i].duid),
+                                               E('<div class="td nowrap">', timestr)
                                        ]));
                                }
 
                                for (var didx = 0; didx < info.wifinets.length; didx++)
                                {
                                        var dev = info.wifinets[didx];
-                                       var s = '';
+                                       var net0 = (dev.networks && dev.networks[0]) ? dev.networks[0] : {};
+                                       var vifs = [];
 
                                        for (var nidx = 0; nidx < dev.networks.length; nidx++)
                                        {
                                                var net = dev.networks[nidx];
                                                var is_assoc = (net.bssid != '00:00:00:00:00:00' && net.channel && !net.disabled);
+                                               var num_assoc = 0;
+
+                                               for (var bssid in net.assoclist)
+                                               {
+                                                       var bss = net.assoclist[bssid];
+
+                                                       bss.bssid  = bssid;
+                                                       bss.link   = net.link;
+                                                       bss.name   = net.name;
+                                                       bss.ifname = net.ifname;
+                                                       bss.radio  = dev.name;
+
+                                                       assoclist.push(bss);
+                                                       num_assoc++;
+                                               }
 
                                                var icon;
                                                if (!is_assoc)
                                                else
                                                        icon = "<%=resource%>/icons/signal-75-100.png";
 
-                                               s += String.format(
-                                                       '<div class="table"><div class="tr"><div class="td" style="text-align:center; width:32px; padding:3px">' +
-                                                               '<img src="%s" title="<%:Signal%>: %d dBm / <%:Noise%>: %d dBm" />' +
-                                                               '<br /><small>%d%%</small>' +
-                                                       '</div><div class="td" style="text-align:left; padding:3px"><small>' +
-                                                               '<strong><%:SSID%>:</strong> <a href="%s">%h</a><br />' +
-                                                               '<strong><%:Mode%>:</strong> %s<br />' +
-                                                               '<strong><%:Channel%>:</strong> %d (%.3f <%:GHz%>)<br />' +
-                                                               '<strong><%:Bitrate%>:</strong> %s <%:Mbit/s%><br />',
-                                                               icon, net.signal, net.noise,
-                                                               net.quality,
-                                                               net.link, net.ssid || '?',
-                                                               net.mode,
-                                                               net.channel, net.frequency,
-                                                               net.bitrate || '?'
-                                               );
-
-                                               if (is_assoc)
-                                               {
-                                                       s += String.format(
-                                                               '<strong><%:BSSID%>:</strong> %s<br />' +
-                                                               '<strong><%:Encryption%>:</strong> %s',
-                                                                       net.bssid || '?',
-                                                                       net.encryption
-                                                       );
-                                               }
-                                               else
-                                               {
-                                                       s += '<em><%:Wireless is disabled or not associated%></em>';
-                                               }
-
-                                               s += '</small></div></div></div>';
-
-                                               for (var bssid in net.assoclist)
-                                               {
-                                                       var bss = net.assoclist[bssid];
-
-                                                       bss.bssid  = bssid;
-                                                       bss.link   = net.link;
-                                                       bss.name   = net.name;
-                                                       bss.ifname = net.ifname;
-                                                       bss.radio  = dev.name;
-
-                                                       assoclist.push(bss);
-                                               }
+                                               vifs.push(renderBadge(
+                                                       icon,
+                                                       '<%:Signal%>: %d dBm / <%:Quality%>: %d%%'.format(net.signal, net.quality),
+                                                       '<%:SSID%>', E('a', { href: net.link }, [ net.ssid || '?' ]),
+                                                       '<%:Mode%>', net.mode,
+                                                       '<%:BSSID%>', is_assoc ? (net.bssid || '-') : null,
+                                                       '<%:Encryption%>', is_assoc ? net.encryption : null,
+                                                       '<%:Associations%>', is_assoc ? (num_assoc || '-') : null,
+                                                       null, is_assoc ? null : E('em', '<%:Wireless is disabled or not associated%>')));
                                        }
 
-                                       if (!s)
-                                               s = '<em><%:No information available%></em>';
-
-                                       ws.appendChild(E('<div class="tr">', [
-                                               E('<div class="td left" width="33%" style="vertical-align:top">', dev.name),
-                                               E('<div class="td">', s)
-                                       ]));
+                                       ws.appendChild(renderBox(
+                                               dev.device, dev.up || net0.up,
+                                               [ E('div', vifs) ],
+                                               '<%:Type%>', dev.name.replace(/^Generic | Wireless Controller .+$/g, ''),
+                                               '<%:Channel%>', net0.channel ? '%d (%.3f <%:GHz%>)'.format(net0.channel, net0.frequency) : '-',
+                                               '<%:Bitrate%>', net0.bitrate ? '%d <%:Mbit/s%>'.format(net0.bitrate) : '-'));
                                }
+
+                               if (!ws.lastElementChild)
+                                       ws.appendChild(E('<em><%:No information available%></em>'));
                        }
 
                        var ac = document.getElementById('wifi_assoc_table');
                                                        .format(assoclist[i].link, assoclist[i].name)),
                                                E('<div class="td">',
                                                        assoclist[i].bssid),
-                                               E('<div class="td">',
-                                                       hint ? '<div style="max-width:200px;overflow:hidden;text-overflow:ellipsis">%h (%h)</div>'.format(name || '?', hint) : (name || '?')),
+                                               E('<div class="td nowrap">',
+                                                       hint ? '<div>%h (%h)</div>'.format(name || '?', hint) : (name || '?')),
                                                E('<div class="td"><span class="ifacebadge" title="<%:Signal%>: %d <%:dBm%> / <%:Noise%>: %d <%:dBm%> / <%:SNR%>: %d"><img src="%s" /> %d / %d <%:dBm%></span></div>'
                                                        .format(assoclist[i].signal, assoclist[i].noise, assoclist[i].signal - assoclist[i].noise, icon, assoclist[i].signal, assoclist[i].noise)),
-                                               E('<div class="td">', [
+                                               E('<div class="td nowrap">', [
                                                        E('<span style="white-space:nowrap">', wifirate(assoclist[i], true)),
                                                        E('<br />'),
                                                        E('<span style="white-space:nowrap">', wifirate(assoclist[i], false))
 <fieldset class="cbi-section">
        <legend><%:Network%></legend>
 
+       <div id="upstream_status_table" class="network-status-table">
+               <em><%:Collecting data...%></em>
+       </div>
+
        <div class="table" width="100%">
-               <div class="tr"><div class="td left" width="33%" style="vertical-align:top"><%:IPv4 WAN Status%></div><div class="td">
-                       <div class="table"><div class="tr">
-                               <div class="td" id="wan4_i" style="width:16px; text-align:center; padding:3px"><img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small></div>
-                               <div class="td left" id="wan4_s" style="vertical-align:middle; padding: 3px"><em><%:Collecting data...%></em></div>
-                       </div></div>
-               </div></div>
-               <% if has_ipv6 then %>
-               <div class="tr"><div class="td left" width="33%" style="vertical-align:top"><%:IPv6 WAN Status%></div><div class="td">
-                       <div class="table"><div class="tr">
-                               <div class="td" id="wan6_i" style="width:16px; text-align:center; padding:3px"><img src="<%=resource%>/icons/ethernet_disabled.png" /><br /><small>?</small></div>
-                               <div class="td left" id="wan6_s" style="vertical-align:middle; padding: 3px"><em><%:Collecting data...%></em></div>
-                       </div></div>
-               </div></div>
-               <% end %>
                <div class="tr"><div class="td left" width="33%"><%:Active Connections%></div><div class="td left" id="conns">-</div></div>
        </div>
 </fieldset>
 <fieldset class="cbi-section">
        <legend><%:Wireless%></legend>
 
-       <div class="table" id="wifi_status_table" width="100%">
-               <div class="tr"><div class="td"><em><%:Collecting data...%></em></div></div>
+       <div id="wifi_status_table" class="network-status-table">
+               <em><%:Collecting data...%></em>
        </div>
 </fieldset>