luci2: convert status overview to grid and hlist widgets
[project/luci2/ui.git] / luci2 / htdocs / luci2 / view / status.overview.js
1 L.ui.view.extend({
2 title: L.tr('Status'),
3
4 getConntrackCount: L.rpc.declare({
5 object: 'luci2.network',
6 method: 'conntrack_count',
7 expect: { '': { count: 0, limit: 0 } }
8 }),
9
10 getDHCPLeases: L.rpc.declare({
11 object: 'luci2.network',
12 method: 'dhcp_leases',
13 expect: { leases: [ ] }
14 }),
15
16 getDHCPv6Leases: L.rpc.declare({
17 object: 'luci2.network',
18 method: 'dhcp6_leases',
19 expect: { leases: [ ] }
20 }),
21
22 renderContents: function() {
23 var self = this;
24 return $.when(
25 L.network.refreshStatus().then(function() {
26 var wan = L.network.findWAN();
27 var wan6 = L.network.findWAN6();
28
29 if (!wan && !wan6)
30 {
31 $('#network_status_table').empty();
32 return;
33 }
34
35 var networkTable = new L.ui.grid({
36 caption: L.tr('Network'),
37 columns: [ {
38 width: 2,
39 width_sm: 12,
40 format: '%s'
41 }, {
42 width: 2,
43 width_sm: 3,
44 align: 'right',
45 format: function(v) {
46 var dev = L.network.resolveAlias(v.getDevice());
47 if (dev)
48 return $('<span />')
49 .addClass('badge')
50 .attr('title', dev.description())
51 .append($('<img />').attr('src', dev.icon()))
52 .append(' %s'.format(dev.name()));
53
54 return '';
55 }
56 }, {
57 width: 6,
58 width_sm: 9,
59 format: function(v, n) {
60 return new L.ui.hlist({ items: [
61 L.tr('Type'), v.getProtocol().description,
62 L.tr('Connected'), '%t'.format(v.getUptime()),
63 L.tr('Address'), (n ? v.getIPv6Addrs() : v.getIPv4Addrs()).join(', '),
64 L.tr('Gateway'), v.getIPv4Gateway(),
65 L.tr('DNS'), (n ? v.getIPv6DNS() : v.getIPv4DNS()).join(', ')
66 ] }).render();
67 }
68 } ]
69 });
70
71 if (wan)
72 networkTable.row([ L.tr('IPv4 WAN Status'), wan, wan ]);
73
74 if (wan6)
75 networkTable.row([ L.tr('IPv6 WAN Status'), wan6, wan6 ]);
76
77 networkTable.insertInto('#network_status_table');
78 }),
79 self.getConntrackCount().then(function(count) {
80 var conntrackTable = new L.ui.grid({
81 caption: L.tr('Connection Tracking'),
82 columns: [ {
83 width: 4
84 }, {
85 format: function(v) {
86 return new L.ui.progress({
87 value: v.count,
88 max: v.limit,
89 format: '%d / %d (%d%%)'
90 }).render();
91 }
92 } ]
93 });
94
95 conntrackTable.row([ L.tr('Active Connections'), count ]);
96 conntrackTable.insertInto('#conntrack_status_table');
97 }),
98 L.system.getInfo().then(function(info) {
99 var sysinfoTable = new L.ui.grid({
100 caption: L.tr('System'),
101 columns: [ {
102 width: 4
103 }, {
104 width: 8,
105 nowrap: true
106 } ]
107 });
108
109 sysinfoTable.rows([
110 [ L.tr('Hostname'), info.hostname ],
111 [ L.tr('Model'), info.model ],
112 [ L.tr('Firmware Version'), info.release.description ],
113 [ L.tr('Kernel Version'), info.kernel ],
114 [ L.tr('Local Time'), (new Date(info.localtime * 1000)).toString() ],
115 [ L.tr('Uptime'), '%t'.format(info.uptime) ],
116 [ L.tr('Load Average'),
117 '%.2f %.2f %.2f'.format(
118 info.load[0] / 65535.0,
119 info.load[1] / 65535.0,
120 info.load[2] / 65535.0
121 ) ]
122 ]);
123
124 sysinfoTable.insertInto('#system_status_table');
125
126 var memoryTable = new L.ui.grid({
127 caption: L.tr('Memory'),
128 columns: [ {
129 format: '%s',
130 width: 4
131 }, {
132 format: function(v) {
133 return new L.ui.progress({
134 value: v,
135 max: info.memory.total,
136 format: function(pc) {
137 return ('%d ' + L.tr('kB') + ' / %d ' + L.tr('kB') + ' (%d%%)').format(
138 v / 1024, info.memory.total / 1024, pc
139 );
140 }
141 }).toString();
142 }
143 } ]
144 });
145
146 memoryTable.rows([
147 [ L.tr('Total Available'), info.memory.free + info.memory.buffered ],
148 [ L.tr('Free'), info.memory.free ],
149 [ L.tr('Cached'), info.memory.shared ],
150 [ L.tr('Buffered'), info.memory.buffered ],
151 ]);
152
153 memoryTable.insertInto('#memory_status_table');
154
155 if (info.swap.total > 0)
156 {
157 var swapTable = new L.ui.grid({
158 caption: L.tr('Swap'),
159 columns: [ {
160 format: '%s',
161 width: 4
162 }, {
163 format: function(v) {
164 return new L.ui.progress({
165 value: v,
166 max: info.swap.total,
167 format: function(pc) {
168 return ('%d ' + L.tr('kB') + ' / %d ' + L.tr('kB') + ' (%d%%)').format(
169 v / 1024, info.swap.total / 1024, pc
170 );
171 }
172 }).toString();
173 }
174 } ]
175 });
176
177 swapTable.row([ L.tr('Free'), info.swap.free ]);
178 swapTable.insertInto('#swap_status_table');
179 }
180
181 var diskTable = new L.ui.grid({
182 caption: L.tr('Storage'),
183 columns: [ {
184 format: '%s',
185 width: 4
186 }, {
187 format: function(v) {
188 return new L.ui.progress({
189 value: v[0],
190 max: v[1],
191 format: function(pc) {
192 return ('%d ' + L.tr('kB') + ' / %d ' + L.tr('kB') + ' (%d%%)').format(
193 v[0] / 1024, v[1] / 1024, pc
194 );
195 }
196 }).toString();
197 }
198 } ]
199 });
200
201 diskTable.row([ '' + L.tr('Root Usage') + ' (/)', [ info.root.used, info.root.total ] ]);
202 diskTable.row([ '' + L.tr('Temporary Usage') + ' (/tmp)', [ info.tmp.used, info.tmp.total ] ]);
203 diskTable.insertInto('#disk_status_table');
204 }),
205 L.wireless.getWirelessStatus().then(function(radios) {
206 var phys = [ ];
207 for (var phy in radios)
208 phys.push(phy);
209
210 phys.sort();
211
212 $('#wifi_status_table').empty();
213
214 for (var i = 0; i < phys.length; i++)
215 {
216 var rows = [ ];
217 var radio = radios[phys[i]];
218
219 rows.push([false, {
220 name: radio.hardware
221 ? '%s 802.11%s (%s)'.format(
222 radio.hardware.name, radio.hwmodes.join(''),
223 radio.phy.replace(/^[^0-9]+/, 'radio'))
224 : ('802.11%s ' + L.tr('Radio') + ' (%s)').format(
225 radio.hwmodes.join(''),
226 radio.phy.replace(/^[^0-9]+/, 'radio')),
227 channel: radio.channel,
228 frequency: radio.frequency,
229 txpower: radio.txpower
230 }]);
231
232 for (var j = 0; j < radio.networks.length; j++)
233 {
234 var network = radio.networks[j];
235
236 if (network.bssid && network.bssid != '00:00:00:00:00:00' && radio.channel)
237 rows[0][0] = true;
238
239 rows.push([{
240 signal: network.signal,
241 noise: network.noise,
242 device: network.device
243 }, {
244 ssid: network.ssid,
245 bssid: network.bssid,
246 mode: network.mode,
247 encryption: network.encryption,
248 bitrate: network.bitrate
249 }]);
250 }
251
252 var wifiTable = new L.ui.grid({
253 caption: i ? null : L.tr('Wireless'),
254 columns: [ {
255 width: 2,
256 width_sm: 3,
257 align: 'right',
258 format: function(v, n)
259 {
260 if (typeof(v) != 'boolean')
261 return new L.ui.devicebadge(v).render();
262 else
263 return L.ui.icon('wifi_big' + (v ? '' : '_disabled'));
264 }
265 }, {
266 width: 6,
267 width_sm: 9,
268 format: function(v, n)
269 {
270 if (typeof(rows[n][0]) != 'boolean')
271 {
272 return new L.ui.hlist({ items: [
273 L.tr('Mode'), v.mode,
274 L.tr('Bitrate'), v.bitrate ? ('~ %.1f ' + L.tr('Mbit/s')).format(v.bitrate / 1000) : undefined,
275 L.tr('SSID'), v.ssid,
276 L.tr('BSSID'), v.bssid,
277 L.tr('Encryption'), L.wireless.formatEncryption(v.encryption)
278 ] }).render();
279 }
280 else
281 {
282 return $('<big />')
283 .append($('<strong />')
284 .addClass('nowrap')
285 .append(v.name))
286 .append('<br />')
287 .add(new L.ui.hlist({ items: [
288 L.tr('Channel'), '%d (%.3f %s)'.format(v.channel, v.frequency / 1000, L.tr('GHz')),
289 L.tr('TX Power'), '%d %s'.format(v.txpower, L.tr('dBm'))
290 ] }).render());
291 }
292 }
293 } ]
294 });
295
296 wifiTable.rows(rows);
297 $('#wifi_status_table').append(wifiTable.render());
298 }
299 }),
300 L.wireless.getAssocLists().then(function(assoclist) {
301 var formatRate = function(v)
302 {
303 return '<span class="nowrap">%s</span>'.format(
304 (!isNaN(v.mcs) && v.mcs > 0)
305 ? ('%.1f ' + L.tr('Mbit/s') + ', MCS %d, %d%s').format(v.rate / 1000, v.mcs, v['40mhz'] ? 40 : 20, L.tr('MHz'))
306 : ('%.1f ' + L.tr('Mbit/s')).format(v.rate / 1000));
307 };
308
309 var assocTable = new L.ui.grid({
310 caption: L.tr('Associated Stations'),
311 placeholder: L.tr('No information available'),
312 columns: [ {
313 format: function(v, n) {
314 return new L.ui.devicebadge(assoclist[n]).render();
315 },
316 width: 2,
317 width_sm: 2,
318 align: 'right',
319 key: 'signal'
320 }, {
321 width_sm: 4,
322 caption: L.tr('MAC-Address'),
323 key: 'mac'
324 }, {
325 caption: L.tr('Signal'),
326 format: '%d ' + L.tr('dBm') + '',
327 key: 'signal',
328 width: 1,
329 width_sm: 0
330 }, {
331 caption: L.tr('Noise'),
332 format: '%d ' + L.tr('dBm') + '',
333 key: 'noise',
334 width: 1,
335 width_sm: 0
336 }, {
337 caption: L.tr('RX Rate'),
338 format: formatRate,
339 key: 'rx',
340 width: 3
341 }, {
342 caption: L.tr('TX Rate'),
343 format: formatRate,
344 key: 'tx',
345 width: 3
346 } ]
347 });
348
349 assocTable.rows(assoclist);
350 assocTable.insertInto('#wifi_assoc_table');
351 }),
352 self.getDHCPLeases().then(function(leases) {
353 var leaseTable = new L.ui.grid({
354 caption: L.tr('DHCP Leases'),
355 placeholder: L.tr('There are no active leases.'),
356 columns: [ {
357 caption: L.tr('Hostname'),
358 placeholder: '?',
359 key: 'hostname',
360 nowrap: true,
361 width_sm: 5
362 }, {
363 caption: L.tr('IPv4-Address'),
364 key: 'ipaddr',
365 width_sm: 4,
366 format: '255.255.255.255'
367 }, {
368 caption: L.tr('MAC-Address'),
369 key: 'macaddr',
370 width_sm: 0
371 }, {
372 caption: L.tr('Leasetime remaining'),
373 key: 'expires',
374 width_sm: 3,
375 nowrap: true,
376 format: function(v) {
377 return (v <= 0) ? L.tr('expired') : '%t'.format(v);
378 }
379 } ]
380 });
381
382 leaseTable.rows(leases);
383 leaseTable.insertInto('#lease_status_table');
384 }),
385 self.getDHCPv6Leases().then(function(leases) {
386 if (!leases.length)
387 return;
388
389 var leaseTable = new L.ui.grid({
390 caption: L.tr('DHCPv6 Leases'),
391 columns: [ {
392 caption: L.tr('Hostname'),
393 placeholder: '?',
394 key: 'hostname',
395 width_sm: 0
396 }, {
397 caption: L.tr('IPv6-Address'),
398 key: 'ip6addr',
399 width_sm: 6
400 }, {
401 caption: L.tr('DUID'),
402 key: 'duid',
403 width_sm: 0
404 }, {
405 caption: L.tr('Leasetime remaining'),
406 key: 'expires',
407 width_sm: 6,
408 format: function(v) {
409 return (v <= 0) ? L.tr('expired') : '%t'.format(v);
410 }
411 } ]
412 });
413
414 leaseTable.rows(leases);
415 leaseTable.insertInto('#lease6_status_table');
416 })
417 )
418 },
419
420 execute: function()
421 {
422 var self = this;
423 return L.network.load().then(function() {
424 self.repeat(self.renderContents, 5000);
425 });
426 }
427 });