7 var callSessionAccess
= rpc
.declare({
10 params
: [ 'scope', 'object', 'function' ],
11 expect
: { 'access': false }
14 function renderbox(radio
, networks
) {
20 for (var i
= 0; i
< networks
.length
; i
++) {
21 var net
= networks
[i
],
22 is_assoc
= (net
.getBSSID() != '00:00:00:00:00:00' && net
.getChannel() && !net
.isDisabled()),
23 quality
= net
.getSignalPercent();
27 icon
= L
.resource('icons/signal-none.png');
28 else if (quality
<= 0)
29 icon
= L
.resource('icons/signal-0.png');
30 else if (quality
< 25)
31 icon
= L
.resource('icons/signal-0-25.png');
32 else if (quality
< 50)
33 icon
= L
.resource('icons/signal-25-50.png');
34 else if (quality
< 75)
35 icon
= L
.resource('icons/signal-50-75.png');
37 icon
= L
.resource('icons/signal-75-100.png');
39 var badge
= renderBadge(
41 '%s: %d dBm / %s: %d%%'.format(_('Signal'), net
.getSignal(), _('Quality'), quality
),
42 _('SSID'), net
.getActiveSSID() || '?',
43 _('Mode'), net
.getActiveMode(),
44 _('BSSID'), is_assoc
? (net
.getActiveBSSID() || '-') : null,
45 _('Encryption'), is_assoc
? net
.getActiveEncryption() : null,
46 _('Associations'), is_assoc
? (net
.assoclist
.length
|| '-') : null,
47 null, is_assoc
? null : E('em', net
.isDisabled() ? _('Wireless is disabled') : _('Wireless is not associated')));
51 chan
= (chan
!= null) ? chan
: net
.getChannel();
52 freq
= (freq
!= null) ? freq
: net
.getFrequency();
53 rate
= (rate
!= null) ? rate
: net
.getBitRate();
56 return E('div', { class: 'ifacebox' }, [
57 E('div', { class: 'ifacebox-head center ' + (radio
.isUp() ? 'active' : '') },
58 E('strong', radio
.getName())),
59 E('div', { class: 'ifacebox-body left' }, [
60 L
.itemlist(E('span'), [
61 _('Type'), radio
.getI18n().replace(/^Generic | Wireless Controller .+$/g, ''),
62 _('Channel'), chan
? '%d (%.3f %s)'.format(chan
, freq
, _('GHz')) : '-',
63 _('Bitrate'), rate
? '%d %s'.format(rate
, _('Mbit/s')) : '-'
70 function wifirate(rt
) {
71 var s
= '%.1f\xa0%s, %d\xa0%s'.format(rt
.rate
/ 1000, _('Mbit/s'), rt
.mhz
, _('MHz')),
72 ht
= rt
.ht
, vht
= rt
.vht
,
73 mhz
= rt
.mhz
, nss
= rt
.nss
,
74 mcs
= rt
.mcs
, sgi
= rt
.short_gi
;
77 if (vht
) s
+= ', VHT-MCS\xa0%d'.format(mcs
);
78 if (nss
) s
+= ', VHT-NSS\xa0%d'.format(nss
);
79 if (ht
) s
+= ', MCS\xa0%s'.format(mcs
);
80 if (sgi
) s
+= ', ' + _('Short GI').replace(/ /g
, '\xa0');
86 return baseclass
.extend({
89 handleDelClient: function(wifinet
, mac
, ev
) {
90 dom
.parent(ev
.currentTarget
, '.tr').style
.opacity
= 0.5;
91 ev
.currentTarget
.classList
.add('spinning');
92 ev
.currentTarget
.disabled
= true;
93 ev
.currentTarget
.blur();
95 wifinet
.disconnectClient(mac
, true, 5, 60000);
100 network
.getWifiDevices(),
101 network
.getWifiNetworks(),
102 network
.getHostHints(),
103 callSessionAccess('access-group', 'luci-mod-status-index-wifi', 'read'),
104 callSessionAccess('access-group', 'luci-mod-status-index-wifi', 'write')
105 ]).then(function(radios_networks_hints
) {
108 for (var i
= 0; i
< radios_networks_hints
[1].length
; i
++)
109 tasks
.push(L
.resolveDefault(radios_networks_hints
[1][i
].getAssocList(), []).then(L
.bind(function(net
, list
) {
110 net
.assoclist
= list
.sort(function(a
, b
) { return a
.mac
> b
.mac
});
111 }, this, radios_networks_hints
[1][i
])));
113 return Promise
.all(tasks
).then(function() {
114 return radios_networks_hints
;
119 render: function(data
) {
124 hasReadPermission
= data
[3],
125 hasWritePermission
= data
[4];
127 var table
= E('div', { 'class': 'network-status-table' });
129 for (var i
= 0; i
< radios
.sort(function(a
, b
) { a
.getName() > b
.getName() }).length
; i
++)
130 table
.appendChild(renderbox(radios
[i
],
131 networks
.filter(function(net
) { return net
.getWifiDeviceName() == radios
[i
].getName() })));
133 if (!table
.lastElementChild
)
136 var assoclist
= E('div', { 'class': 'table assoclist' }, [
137 E('div', { 'class': 'tr table-titles' }, [
138 E('div', { 'class': 'th nowrap' }, _('Network')),
139 E('div', { 'class': 'th hide-xs' }, _('MAC-Address')),
140 E('div', { 'class': 'th' }, _('Host')),
141 E('div', { 'class': 'th' }, '%s / %s'.format(_('Signal'), _('Noise'))),
142 E('div', { 'class': 'th' }, '%s / %s'.format(_('RX Rate'), _('TX Rate')))
148 for (var i
= 0; i
< networks
.length
; i
++) {
149 for (var k
= 0; k
< networks
[i
].assoclist
.length
; k
++) {
150 var bss
= networks
[i
].assoclist
[k
],
151 name
= hosthints
.getHostnameByMACAddr(bss
.mac
),
152 ipv4
= hosthints
.getIPAddrByMACAddr(bss
.mac
),
153 ipv6
= hosthints
.getIP6AddrByMACAddr(bss
.mac
);
156 var q
= Math
.min((bss
.signal
+ 110) / 70 * 100, 100);
158 icon
= L
.resource('icons/signal-0.png');
160 icon
= L
.resource('icons/signal-0-25.png');
162 icon
= L
.resource('icons/signal-25-50.png');
164 icon
= L
.resource('icons/signal-50-75.png');
166 icon
= L
.resource('icons/signal-75-100.png');
168 var sig_title
, sig_value
;
171 sig_value
= '%d/%d\xa0%s'.format(bss
.signal
, bss
.noise
, _('dBm'));
172 sig_title
= '%s: %d %s / %s: %d %s / %s %d'.format(
173 _('Signal'), bss
.signal
, _('dBm'),
174 _('Noise'), bss
.noise
, _('dBm'),
175 _('SNR'), bss
.signal
- bss
.noise
);
178 sig_value
= '%d\xa0%s'.format(bss
.signal
, _('dBm'));
179 sig_title
= '%s: %d %s'.format(_('Signal'), bss
.signal
, _('dBm'));
184 if (name
&& ipv4
&& ipv6
)
185 hint
= '%s <span class="hide-xs">(%s, %s)</span>'.format(name
, ipv4
, ipv6
);
186 else if (name
&& (ipv4
|| ipv6
))
187 hint
= '%s <span class="hide-xs">(%s)</span>'.format(name
, ipv4
|| ipv6
);
189 hint
= name
|| ipv4
|| ipv6
|| '?';
193 'class': 'ifacebadge',
194 'title': networks
[i
].getI18n(),
195 'data-ifname': networks
[i
].getIfname(),
196 'data-ssid': networks
[i
].getActiveSSID()
198 E('img', { 'src': L
.resource('icons/wifi.png') }),
200 ' ', networks
[i
].getShortName(),
201 E('small', {}, [ ' (', networks
[i
].getIfname(), ')' ])
207 'class': 'ifacebadge',
209 'data-signal': bss
.signal
,
210 'data-noise': bss
.noise
212 E('img', { 'src': icon
}),
218 E('span', wifirate(bss
.rx
)),
220 E('span', wifirate(bss
.tx
))
224 if (networks
[i
].isClientDisconnectSupported() && hasWritePermission
) {
225 if (assoclist
.firstElementChild
.childNodes
.length
< 6)
226 assoclist
.firstElementChild
.appendChild(E('div', { 'class': 'th cbi-section-actions' }));
228 row
.push(E('button', {
229 'class': 'cbi-button cbi-button-remove',
230 'click': L
.bind(this.handleDelClient
, this, networks
[i
], bss
.mac
)
231 }, [ _('Disconnect') ]));
241 cbi_update_table(assoclist
, rows
, E('em', _('No information available')));
245 hasReadPermission
? E('h3', _('Associated Stations')) : E([]),
246 hasReadPermission
? assoclist
: E([])