10 'require tools.widgets as widgets';
12 var Hosts
, Remotehosts
, Remoteinfo
, Localinfo
, Clients
, WifiNetworks
;
16 function SplitWlan(wlan
) {
18 if (typeof wlan
.split('#')[1] !== 'undefined') {
19 wlansplit
=wlan
.split('#');
20 if (typeof dns_cache
[wlansplit
[0]] !== 'undefined') {
21 wlansplit
[0]=dns_cache
[wlansplit
[0]];
24 wlansplit
[0]=_('This AP');
31 function collectHearingClient(client_table_entries
, mac
) {
32 if (typeof Clients
[mac
] !== 'undefined') {
33 for (var wlanc
in Clients
[mac
]) {
36 if (typeof Localinfo
[wlanc
] !== 'undefined') {
37 SSID
= Localinfo
[wlanc
]['ssid'];
38 freq
= Localinfo
[wlanc
]['freq'];
40 if (typeof Remoteinfo
[wlanc
] !== 'undefined') {
41 SSID
= Remoteinfo
[wlanc
]['ssid'];
42 freq
= Remoteinfo
[wlanc
]['freq'];
44 var wlansplit
=SplitWlan(wlanc
);
45 client_table_entries
.push([
46 '<nobr>' + '%h'.format(wlansplit
[0]) + '</nobr>',
47 '<nobr>' + '%h'.format(wlansplit
[1]) + '</nobr>',
50 Clients
[mac
][wlanc
]['connected'] === true ? 'Yes' : 'No',
51 typeof Clients
[mac
][wlanc
]['signal'] !== 'undefined' ? '%h'.format(Clients
[mac
][wlanc
]['signal']) : ''
57 var HearingMap
= form
.DummyValue
.extend({
58 renderWidget: function () {
60 E('h3', _('Hearing map')),
61 E('div', _('Refresh page to get new mac addresses to show up'))
63 for (var mac
in Clients
) {
65 maciphost
= '%h'.format(mac
);
66 var macUp
= mac
.toUpperCase();
67 var macn
= macUp
.replace(/:/g
,'');
68 if (typeof Hosts
[macUp
] !== 'undefined') {
69 if ((String(Hosts
[macUp
]['ipaddrs'][0]).length
> 0) && (typeof Hosts
[macUp
]['ipaddrs'][0] !== 'undefined'))
70 maciphost
+= '\u2003' + Hosts
[macUp
]['ipaddrs'];
71 if ((String(Hosts
[macUp
]['name']).length
> 0) && (typeof Hosts
[macUp
]['name'] !== 'undefined'))
72 maciphost
+= '\u2003%h'.format(Hosts
[macUp
]['name']);
77 var client_table
= E('table', {'class': 'table cbi-section-table','id':'client_table'+macn
}, [
78 E('tr', {'class': 'tr table-titles'}, [
79 E('th', {'class': 'th'}, _('AP','Name or IP address of access point')),
80 E('th', {'class': 'th'}, _('Interface name','interface name in usteer overview')),
81 E('th', {'class': 'th', 'style': 'width:25%'}, _('SSID')),
82 E('th', {'class': 'th', 'style': 'width:15%'}, _('Frequency','BSS operating frequency in usteer overview')),
83 E('th', {'class': 'th', 'style': 'width:15%'}, _('Connected','Connection state in usteer overview')),
84 E('th', {'class': 'th', 'style': 'width:15%'}, _('Signal','Signal strength reported by wireless station in usteer overview'))
87 var client_table_entries
= [];
88 collectHearingClient(client_table_entries
, mac
);
89 cbi_update_table(client_table
, client_table_entries
, E('em', _('No data')));
90 body
.appendChild(client_table
);
92 return E('div', {'class': 'cbi-section cbi-tblsection'}, [body
]);
99 function collectWlanAPInfoEntries(connectioninfo_table_entries
, wlanAPInfos
) {
100 for (var wlan
in wlanAPInfos
) {
101 var wlansplit
=SplitWlan(wlan
);
102 connectioninfo_table_entries
.push([
103 '<nobr>' + '%h'.format(wlansplit
[0]) + '</nobr>',
104 '<nobr>' + '%h'.format(wlansplit
[1]) + '</nobr>',
105 '%h'.format(wlanAPInfos
[wlan
]['bssid']),
106 '%h'.format(wlanAPInfos
[wlan
]['ssid']),
107 '%h'.format(wlanAPInfos
[wlan
]['freq']),
108 '%h'.format(wlanAPInfos
[wlan
]['n_assoc']),
109 '%h'.format(wlanAPInfos
[wlan
]['noise']),
110 '%h'.format(wlanAPInfos
[wlan
]['load']),
111 '%h'.format(wlanAPInfos
[wlan
]['max_assoc']),
112 typeof wlanAPInfos
[wlan
]['roam_events']['source'] !== 'undefined' ? '%h'.format(wlanAPInfos
[wlan
]['roam_events']['source']) : '',
113 typeof wlanAPInfos
[wlan
]['roam_events']['target'] !== 'undefined' ? '%h'.format(wlanAPInfos
[wlan
]['roam_events']['target']) : ''
118 function tootltip(mac
, IP
, hostname
) {
120 body
.appendChild(E('div', '%h'.format(mac
)));
121 if (typeof IP
!== 'undefined') {
122 for (var IPaddr
in IP
['ipaddrs']) body
.appendChild(E('div', '%h'.format(IP
['ipaddrs'][IPaddr
])));
123 for (var IPaddr
in IP
['ip6addrs']) body
.appendChild(E('div', '%h'.format(IP
['ip6addrs'][IPaddr
])));;
125 if (hostname
!== '') {
126 body
.appendChild(E('div', '%h'.format(hostname
)));
131 function collectWlanAPInfos(compactconnectioninfo_table_entries
, wlanAPInfos
) {
132 for (var wlan
in wlanAPInfos
) {
134 for (var mac
in Clients
) {
135 if (typeof Clients
[mac
] !== 'undefined')
136 if (typeof Clients
[mac
][wlan
] !== 'undefined')
137 if (String(Clients
[mac
][wlan
]['connected']).valueOf() === 'true') {
141 var macUp
= mac
.toUpperCase();
142 if (typeof Hosts
[macUp
] !== 'undefined') {
143 if ((typeof Hosts
[macUp
]['ipaddrs'][0] !== 'undefined') && (String(Hosts
[macUp
]['ipaddrs'][0]).length
> 0)) {
144 IP
= Hosts
[macUp
]['ipaddrs'][0];
147 if ((typeof Hosts
[macUp
]['name'] !== 'undefined') && (String(Hosts
[macUp
]['name']).length
> 0)) {
148 hostname
= Hosts
[macUp
]['name'];
149 foundname
= hostname
;
153 E('span', { 'class': 'cbi-tooltip-container' }, [
154 '%h\u2003'.format(foundname
),
155 E('div', { 'class': 'cbi-tooltip' }, tootltip(mac
, Hosts
[macUp
], hostname
))
160 var wlansplit
=SplitWlan(wlan
);
161 compactconnectioninfo_table_entries
.push([
162 '<nobr>' + '%h'.format(wlansplit
[0]) + '</nobr>',
163 '<nobr>' + '%h'.format(wlansplit
[1]) + '</nobr>',
164 '%h'.format(wlanAPInfos
[wlan
]['ssid']),
165 '%h'.format(wlanAPInfos
[wlan
]['freq']),
166 '%h'.format(wlanAPInfos
[wlan
]['load']),
167 '%h'.format(wlanAPInfos
[wlan
]['n_assoc']),
173 var callNetworkRrdnsLookup
= rpc
.declare({
174 object
: 'network.rrdns',
176 params
: [ 'addrs', 'timeout', 'limit' ],
181 function collectRemoteHosts (remotehosttableentries
,Remotehosts
) {
182 const getUndefinedDnsCacheIPs
= (Remotehosts
, dns_cache
) =>
183 Object
.keys(Remotehosts
).filter(IPaddr
=> !dns_cache
.hasOwnProperty(IPaddr
));
185 var ipAddrs
= getUndefinedDnsCacheIPs(Remotehosts
, dns_cache
);
187 L
.resolveDefault(callNetworkRrdnsLookup(ipAddrs
, 1000, 1000), {}).then(function(replies
) {
188 for (var address
of ipAddrs
) {
191 if (replies
[address
]) {
192 dns_cache
[address
] = replies
[address
];
195 dns_cache
[address
]=Hosts
[
196 Object
.keys(Hosts
).find(mac
=>
197 ((typeof Hosts
[mac
]['name'] !== 'undefined') &&
198 ((Object
.keys(Hosts
[mac
]['ip6addrs']).find(IPaddr2
=> (address
=== Hosts
[mac
]['ip6addrs'][IPaddr2
]))) ||
199 (Object
.keys(Hosts
[mac
]['ipaddrs']).find(IPaddr2
=> (address
=== Hosts
[mac
]['ipaddrs'][IPaddr2
])))))
206 for (var IPaddr
in Remotehosts
) {
207 remotehosttableentries
.push([IPaddr
,'%h'.format(dns_cache
[IPaddr
]),'%h'.format(Remotehosts
[IPaddr
]['id'])]);
212 var Clientinfooverview
= form
.DummyValue
.extend({
213 renderWidget: function () {
215 E('h3', _('Remote hosts'))
217 var remotehost_table
= E('table', {'class': 'table cbi-section-table', 'id': 'remotehost_table'}, [
218 E('tr', {'class': 'tr table-titles'}, [
219 E('th', {'class': 'th'}, _('IP address')),
220 E('th', {'class': 'th'}, _('Hostname')),
221 E('th', {'class': 'th'}, _('Identifier'))
224 var remotehosttableentries
= [];
225 collectRemoteHosts(remotehosttableentries
,Remotehosts
);
226 cbi_update_table(remotehost_table
, remotehosttableentries
, E('em', _('No data')));
227 body
.appendChild(remotehost_table
);
229 E('h3', _('Client list'))
231 var connectioninfo_table
= E('table', {'class': 'table cbi-section-table', 'id': 'connectioninfo_table'}, [
232 E('tr', {'class': 'tr table-titles'}, [
233 E('th', {'class': 'th'}, _('AP','Name or IP address of access point')),
234 E('th', {'class': 'th'}, _('Interface name','interface name in usteer overview')),
235 E('th', {'class': 'th'}, _('BSSID')),
236 E('th', {'class': 'th'}, _('SSID')),
237 E('th', {'class': 'th'}, _('Frequency','BSS operating frequency in usteer overview')),
238 E('th', {'class': 'th'}, _('N','Number of associated clients in usteer overview')),
239 E('th', {'class': 'th'}, _('Noise','Channel noise in usteer overview')),
240 E('th', {'class': 'th'}, _('Load','Channel load in usteer overview')),
241 E('th', {'class': 'th'}, _('Max assoc','Max associated clients in usteer overview')),
242 E('th', {'class': 'th'}, _('Roam src','Roam source in usteer overview')),
243 E('th', {'class': 'th'}, _('Roam tgt','Roam target in usteer overview'))
246 var connectioninfo_table_entries
= [];
247 collectWlanAPInfoEntries(connectioninfo_table_entries
, Localinfo
);
248 collectWlanAPInfoEntries(connectioninfo_table_entries
, Remoteinfo
);
250 cbi_update_table(connectioninfo_table
, connectioninfo_table_entries
, E('em', _('No data')));
251 body
.appendChild(connectioninfo_table
);
252 var compactconnectioninfo_table
= E('table', {'class': 'table cbi-section-table','id': 'compactconnectioninfo_table'}, [
253 E('tr', {'class': 'tr table-titles'}, [
254 E('th', {'class': 'th'}, _('AP','Name or IP address of access point')),
255 E('th', {'class': 'th'}, _('Interface name','interface name in usteer overview')),
256 E('th', {'class': 'th'}, _('SSID')),
257 E('th', {'class': 'th'}, _('Frequency', 'BSS operating frequency in usteer overview')),
258 E('th', {'class': 'th'}, _('Load', 'Channel load in usteer overview')),
259 E('th', {'class': 'th'}, _('N', 'Number of associated clients in usteer overview')),
260 E('th', {'class': 'th'}, _('Host', 'host hint in usteer overview'))
263 var compactconnectioninfo_table_entries
= [];
264 collectWlanAPInfos(compactconnectioninfo_table_entries
, Localinfo
);
265 collectWlanAPInfos(compactconnectioninfo_table_entries
, Remoteinfo
);
266 cbi_update_table(compactconnectioninfo_table
, compactconnectioninfo_table_entries
, E('em', _('No data')));
267 body
.appendChild(compactconnectioninfo_table
);
268 return E('div', {'class': 'cbi-section cbi-tblsection'}, [body
]);
272 var Settingstitle
= form
.DummyValue
.extend({
273 renderWidget: function () {
275 E('h3', _('Settings')),
277 _('The first four options below are mandatory.') + ' ' +
278 _('Also be sure to enable rrm reports, 80211kv, etc.') + ' ' +
279 _('See <a %s>documentation</a>').format('href="https://openwrt.org/docs/guide-user/network/wifi/usteer"')
282 return E('div', [body
]);
287 var Settingsfooter
= form
.DummyValue
.extend({
288 renderWidget: function () {
290 E('body', footerdata
),
292 return E('div', {'style': 'width:100%'}, [footerdata
]);
298 callHostHints
: rpc
.declare({
300 method
: 'getHostHints',
303 callGetRemotehosts
: rpc
.declare({
305 method
: 'remote_hosts',
308 callGetRemoteinfo
: rpc
.declare({
310 method
: 'remote_info',
313 callGetLocalinfo
: rpc
.declare({
315 method
: 'local_info',
318 callGetClients
: rpc
.declare({
320 method
: 'get_clients',
326 this.callHostHints().catch (function (){return null;}),
327 this.callGetRemotehosts().catch (function (){return null;}),
328 this.callGetRemoteinfo().catch (function (){return null;}),
329 this.callGetLocalinfo().catch (function (){return null;}),
330 this.callGetClients().catch (function (){return null;}),
331 network
.getWifiNetworks()
335 poll_status: function(nodes
, data
) {
338 Remotehosts
= data
[2];
339 Remoteinfo
= data
[3];
343 var remotehosttableentries
= [];
344 collectRemoteHosts(remotehosttableentries
,Remotehosts
);
345 cbi_update_table(nodes
.querySelector('#remotehost_table'), remotehosttableentries
, E('em', _('No data')));
347 var connectioninfo_table_entries
= [];
348 collectWlanAPInfoEntries(connectioninfo_table_entries
, Localinfo
);
349 collectWlanAPInfoEntries(connectioninfo_table_entries
, Remoteinfo
);
350 cbi_update_table(nodes
.querySelector('#connectioninfo_table'), connectioninfo_table_entries
, E('em', _('No data')));
352 var compactconnectioninfo_table_entries
= [];
353 collectWlanAPInfos(compactconnectioninfo_table_entries
, Localinfo
);
354 collectWlanAPInfos(compactconnectioninfo_table_entries
, Remoteinfo
);
355 cbi_update_table(nodes
.querySelector('#compactconnectioninfo_table'), compactconnectioninfo_table_entries
, E('em', _('No data')));
357 for (var mac
in Clients
) {
358 var macn
= mac
.toUpperCase().replace(/:/g
,'');
359 var client_table_entries
= [];
360 collectHearingClient(client_table_entries
, mac
);
361 cbi_update_table(nodes
.querySelector('#client_table'+macn
), client_table_entries
, E('em', _('No data')));
366 render: function (data
) {
369 if (!('usteer' in data
[0])) {
370 m
= new form
.Map('usteer', _('Usteer'),
371 _('Usteer is not running. Make sure it is installed and running.') +
372 _('To start it running try %s').format('<code>/etc/init.d/usteer start</code>')
377 m
= new form
.Map('usteer', _('Usteer'));
380 Remotehosts
= data
[2];
381 Remoteinfo
= data
[3];
384 WifiNetworks
= data
[6];
386 s
= m
.section(form
.TypedSection
);
388 s
.tab('status', _('Status'));
389 s
.tab('hearingmap', _('Hearing map'));
390 s
.tab('settings', _('Settings'));
392 o
= s
.taboption('status', Clientinfooverview
);
395 o
= s
.taboption('hearingmap', HearingMap
);
398 o
= s
.taboption('settings', Settingstitle
);
401 o
= s
.taboption('settings', widgets
.NetworkSelect
, 'network', _('Network'), _('The network interface for inter-AP communication'));
403 o
= s
.taboption('settings', form
.Flag
, 'syslog', _('Log messages to syslog'));
407 o
= s
.taboption('settings', form
.Flag
, 'ipv6', _('IPv6 mode'), _('Use IPv6 for remote exchange'));
410 o
= s
.taboption('settings', form
.ListValue
, 'debug_level', _('Debug level'));
411 o
.value('0', _('Fatal'));
412 o
.value('1', _('Info'));
413 o
.value('2', _('Verbose'));
414 o
.value('3', _('Some debug'));
415 o
.value('4', _('Network packet info'));
416 o
.value('5', _('All debug messages'));
420 o
= s
.taboption('settings', form
.Value
, 'max_neighbour_reports', _('Max neighbour reports'), _('Maximum number of neighbor reports set for a node'));
423 o
.datatype
= 'uinteger';
425 o
= s
.taboption('settings', form
.Value
, 'sta_block_timeout', _('Sta block timeout'), _('Maximum amount of time (ms) a station may be blocked due to policy decisions'));
427 o
.placeholder
= 30000;
428 o
.datatype
= 'uinteger';
430 o
= s
.taboption('settings', form
.Value
, 'local_sta_timeout', _('Local sta timeout'), _('Maximum amount of time (ms) a local unconnected station is tracked'));
432 o
.placeholder
= 12000;
433 o
.datatype
= 'uinteger';
435 o
= s
.taboption('settings', form
.Value
, 'measurement_report_timeout', _('Measurement report timeout'), _('Maximum amount of time (ms) a measurement report is stored'));
437 o
.placeholder
= 120000;
438 o
.datatype
= 'uinteger';
440 o
= s
.taboption('settings', form
.Value
, 'local_sta_update', _('Local sta update'), _('Local station information update interval (ms)'));
442 o
.placeholder
= 1000;
443 o
.datatype
= 'uinteger';
445 o
= s
.taboption('settings', form
.Value
, 'max_retry_band', _('Max retry band'), _('Maximum number of consecutive times a station may be blocked by policy'));
448 o
.datatype
= 'uinteger';
450 o
= s
.taboption('settings', form
.Value
, 'seen_policy_timeout', _('Seen policy timeout'), _('Maximum idle time of a station entry (ms) to be considered for policy decisions'));
452 o
.placeholder
= 30000;
453 o
.datatype
= 'uinteger';
455 o
= s
.taboption('settings', form
.Value
, 'load_balancing_threshold', _('Load balancing threshold'), _('Minimum number of stations delta between APs before load balancing policy is active'));
458 o
.datatype
= 'uinteger';
460 o
= s
.taboption('settings', form
.Value
, 'band_steering_threshold', _('Band steering threshold'), _('Minimum number of stations delta between bands before band steering policy is active'));
463 o
.datatype
= 'uinteger';
465 o
= s
.taboption('settings', form
.Value
, 'remote_update_interval', _('Remote update interval'), _('Interval (ms) between sending state updates to other APs'));
467 o
.placeholder
= 1000;
468 o
.datatype
= 'uinteger';
470 o
= s
.taboption('settings', form
.Value
, 'remote_node_timeout', _('Remote node timeout'), _('Number of remote update intervals after which a remote-node is deleted'));
473 o
.datatype
= 'uinteger';
475 o
= s
.taboption('settings', form
.Flag
, 'assoc_steering', _('Assoc steering'), _('Allow rejecting assoc requests for steering purposes'));
478 o
= s
.taboption('settings', form
.Flag
, 'probe_steering', _('Probe steering'), _('Allow ignoring probe requests for steering purposes'));
481 o
= s
.taboption('settings', form
.Value
, 'min_connect_snr', _('Min connect SNR'), _('Minimum signal-to-noise ratio or signal level (dBm) to allow connections'));
484 o
.datatype
= 'integer';
486 o
= s
.taboption('settings', form
.Value
, 'min_snr', _('Min SNR'), _('Minimum signal-to-noise ratio or signal level (dBm) to remain connected'));
489 o
.datatype
= 'integer';
491 o
= s
.taboption('settings', form
.Value
, 'min_snr_kick_delay', _('Min SNR kick delay'), _('Timeout after which a station with SNR < min_SNR will be kicked'));
493 o
.placeholder
= 5000;
494 o
.datatype
= 'uinteger';
496 o
= s
.taboption('settings', form
.Value
, 'roam_process_timeout', _('Roam process timeout'), _('Timeout (in ms) after which a association following a disassociation is not seen as a roam'));
498 o
.placeholder
= 5000;
499 o
.datatype
= 'uinteger';
501 o
= s
.taboption('settings', form
.Value
, 'roam_scan_snr', _('Roam scan SNR'), _('Minimum signal-to-noise ratio or signal level (dBm) before attempting to trigger client scans for roam'));
504 o
.datatype
= 'integer';
506 o
= s
.taboption('settings', form
.Value
, 'roam_scan_tries', _('Roam scan tries'), _('Maximum number of client roaming scan trigger attempts'));
509 o
.datatype
= 'uinteger';
511 o
= s
.taboption('settings', form
.Value
, 'roam_scan_timeout', _('Roam scan timeout'),
512 _('Retry scanning when roam_scan_tries is exceeded after this timeout (in ms).') +
513 _(' In case this option is disabled, the client is kicked instead')
517 o
.datatype
= 'uinteger';
519 o
= s
.taboption('settings', form
.Value
, 'roam_scan_interval', _('Roam scan interval'), _('Minimum time (ms) between client roaming scan trigger attempts'));
521 o
.placeholder
= 10000;
522 o
.datatype
= 'uinteger';
524 o
= s
.taboption('settings', form
.Value
, 'roam_trigger_snr', _('Roam trigger SNR'), _('Minimum signal-to-noise ratio or signal level (dBm) before attempting to trigger forced client roaming'));
527 o
.datatype
= 'integer';
529 o
= s
.taboption('settings', form
.Value
, 'roam_trigger_interval', _('Roam trigger interval'), _('Minimum time (ms) between client roaming trigger attempts'));
531 o
.placeholder
= 60000;
532 o
.datatype
= 'uinteger';
534 o
= s
.taboption('settings', form
.Value
, 'roam_kick_delay', _('Roam kick delay'), _('Timeout (in 100ms beacon intervals) for client roam requests'));
537 o
.datatype
= 'uinteger';
539 o
= s
.taboption('settings', form
.Value
, 'signal_diff_threshold', _('Signal diff threshold'), _('Minimum signal strength difference until AP steering policy is active'));
542 o
.datatype
= 'uinteger';
544 o
= s
.taboption('settings', form
.Value
, 'initial_connect_delay', _('Initial connect delay'), _('Initial delay (ms) before responding to probe requests (to allow other APs to see packets as well)'));
547 o
.datatype
= 'uinteger';
549 o
= s
.taboption('settings', form
.Flag
, 'load_kick_enabled', _('Load kick enabled'), _('Enable kicking client on excessive channel load'));
552 o
= s
.taboption('settings', form
.Value
, 'load_kick_threshold', _('Load kick threshold'), _('Minimum channel load (%) before kicking clients'));
555 o
.datatype
= 'uinteger';
557 o
= s
.taboption('settings', form
.Value
, 'load_kick_delay', _('Load kick delay'), _('Minimum amount of time (ms) that channel load is above threshold before starting to kick clients'));
559 o
.placeholder
= 10000;
560 o
.datatype
= 'uinteger';
562 o
= s
.taboption('settings', form
.Value
, 'load_kick_min_clients', _('Load kick min clients'), _('Minimum number of connected clients before kicking based on channel load'));
565 o
.datatype
= 'uinteger';
567 o
= s
.taboption('settings', form
.Value
, 'load_kick_reason_code', _('Load kick reason code'),
568 _('Reason code on client kick based on channel load.') + ' Default: WLAN_REASON_DISASSOC_AP_BUSY)'
572 o
.datatype
= 'uinteger';
574 o
= s
.taboption('settings', form
.Value
, 'band_steering_interval', _('Band steering interval'), _('Attempting to steer clients to a higher frequency-band every n ms. A value of 0 disables band-steering.'));
576 o
.placeholder
= 120000;
577 o
.datatype
= 'uinteger';
579 o
= s
.taboption('settings', form
.Value
, 'band_steering_min_snr', _('Band steering min SNR'), _('Minimal SNR or absolute signal a device has to maintain over band_steering_interval to be steered to a higher frequency band.'));
582 o
.datatype
= 'integer';
584 o
= s
.taboption('settings', form
.Value
, 'link_measurement_interval', _('Link measurement interval'),
585 _('Interval (ms) the device is sent a link-measurement request to help assess the bi-directional link quality.') +
586 _('Setting the interval to 0 disables link-measurements.')
589 o
.placeholder
= 30000;
590 o
.datatype
= 'uinteger';
592 o
= s
.taboption('settings', form
.Value
, 'node_up_script', _('Node up script'), _('Script to run after bringing up a node'));
594 o
.datatype
= 'string';
596 o
= s
.taboption('settings', form
.MultiValue
, 'event_log_types', _('Event log types'), _('Message types to include in log.'));
597 o
.value('probe_req_accept');
598 o
.value('probe_req_deny');
599 o
.value('auth_req_accept');
600 o
.value('auth_req_deny');
601 o
.value('assoc_req_accept');
602 o
.value('assoc_req_deny');
603 o
.value('load_kick_trigger');
604 o
.value('load_kick_reset');
605 o
.value('load_kick_min_clients');
606 o
.value('load_kick_no_client');
607 o
.value('load_kick_client');
608 o
.value('signal_kick');
610 o
.datatype
= 'list(string)';
612 o
= s
.taboption('settings', form
.DynamicList
, 'ssid_list', _('SSID list'), _('List of SSIDs to enable steering on'));
613 WifiNetworks
.forEach(function (wifiNetwork
) {
614 if (wifiNetwork
.getSSID() && (!o
.keylist
|| o
.keylist
.indexOf(wifiNetwork
.getSSID()) === -1)) {
615 o
.value(wifiNetwork
.getSSID())
619 o
.datatype
= 'list(string)';
621 footerdata
= this.super('addFooter', []);
622 o
= s
.taboption('settings', Settingsfooter
);
625 return m
.render().then(L
.bind(function(m
, nodes
) {
626 poll
.add(L
.bind(function() {
629 this.callHostHints().catch (function (){return null;}),
630 this.callGetRemotehosts().catch (function (){return null;}),
631 this.callGetRemoteinfo().catch (function (){return null;}),
632 this.callGetLocalinfo().catch (function (){return null;}),
633 this.callGetClients().catch (function (){return null;})
634 ]).then(L
.bind(this.poll_status
, this, nodes
));
641 addFooter: function () {