diff options
Diffstat (limited to 'modules/luci-base/luasrc')
-rw-r--r-- | modules/luci-base/luasrc/controller/admin/index.lua | 122 | ||||
-rw-r--r-- | modules/luci-base/luasrc/controller/admin/uci.lua | 109 | ||||
-rw-r--r-- | modules/luci-base/luasrc/dispatcher.lua | 92 | ||||
-rw-r--r-- | modules/luci-base/luasrc/model/network.lua | 37 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/admin_uci/changelog.htm | 66 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/admin_uci/changes.htm | 45 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/admin_uci/revert.htm | 33 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/cbi/wireless_modefreq.htm | 168 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/empty_node_placeholder.htm | 11 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/lease_status.htm | 95 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/wifi_assoclist.htm | 82 |
11 files changed, 824 insertions, 36 deletions
diff --git a/modules/luci-base/luasrc/controller/admin/index.lua b/modules/luci-base/luasrc/controller/admin/index.lua new file mode 100644 index 0000000000..7e0a207437 --- /dev/null +++ b/modules/luci-base/luasrc/controller/admin/index.lua @@ -0,0 +1,122 @@ +-- Copyright 2008 Steven Barth <steven@midlink.org> +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.admin.index", package.seeall) + +function index() + function toplevel_page(page, preflookup, preftarget) + if preflookup and preftarget then + if lookup(preflookup) then + page.target = preftarget + end + end + + if not page.target then + page.target = firstchild() + end + end + + local uci = require("luci.model.uci").cursor() + + local root = node() + if not root.target then + root.target = alias("admin") + root.index = true + end + + local page = node("admin") + + page.title = _("Administration") + page.order = 10 + page.sysauth = "root" + page.sysauth_authenticator = "htmlauth" + page.ucidata = true + page.index = true + page.target = firstnode() + + -- Empty menu tree to be populated by addons and modules + + page = node("admin", "status") + page.title = _("Status") + page.order = 10 + page.index = true + -- overview is from mod-admin-full + toplevel_page(page, "admin/status/overview", alias("admin", "status", "overview")) + + page = node("admin", "system") + page.title = _("System") + page.order = 20 + page.index = true + -- system/system is from mod-admin-full + toplevel_page(page, "admin/system/system", alias("admin", "system", "system")) + + -- Only used if applications add items + page = node("admin", "services") + page.title = _("Services") + page.order = 40 + page.index = true + toplevel_page(page, false, false) + + -- Even for mod-admin-full network just uses first submenu item as landing + page = node("admin", "network") + page.title = _("Network") + page.order = 50 + page.index = true + toplevel_page(page, false, false) + + if nixio.fs.access("/etc/config/dhcp") then + page = entry({"admin", "dhcplease_status"}, call("lease_status"), nil) + page.leaf = true + end + + local has_wifi = false + + uci:foreach("wireless", "wifi-device", + function(s) + has_wifi = true + return false + end) + + if has_wifi then + page = entry({"admin", "wireless_assoclist"}, call("wifi_assoclist"), nil) + page.leaf = true + end + + -- Logout is last + entry({"admin", "logout"}, call("action_logout"), _("Logout"), 999) +end + +function action_logout() + local dsp = require "luci.dispatcher" + local utl = require "luci.util" + local sid = dsp.context.authsession + + if sid then + utl.ubus("session", "destroy", { ubus_rpc_session = sid }) + + luci.http.header("Set-Cookie", "sysauth=%s; expires=%s; path=%s/" %{ + sid, 'Thu, 01 Jan 1970 01:00:00 GMT', dsp.build_url() + }) + end + + luci.http.redirect(dsp.build_url()) +end + + +function lease_status() + local s = require "luci.tools.status" + + luci.http.prepare_content("application/json") + luci.http.write('[') + luci.http.write_json(s.dhcp_leases()) + luci.http.write(',') + luci.http.write_json(s.dhcp6_leases()) + luci.http.write(']') +end + +function wifi_assoclist() + local s = require "luci.tools.status" + + luci.http.prepare_content("application/json") + luci.http.write_json(s.wifi_assoclist()) +end diff --git a/modules/luci-base/luasrc/controller/admin/uci.lua b/modules/luci-base/luasrc/controller/admin/uci.lua new file mode 100644 index 0000000000..1d955dd982 --- /dev/null +++ b/modules/luci-base/luasrc/controller/admin/uci.lua @@ -0,0 +1,109 @@ +-- Copyright 2008 Steven Barth <steven@midlink.org> +-- Copyright 2010-2015 Jo-Philipp Wich <jow@openwrt.org> +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.admin.uci", package.seeall) + +function index() + local redir = luci.http.formvalue("redir", true) + or table.concat(luci.dispatcher.context.request, "/") + + entry({"admin", "uci"}, nil, _("Configuration")) + entry({"admin", "uci", "changes"}, post_on({ trigger_apply = true }, "action_changes"), _("Changes"), 40).query = {redir=redir} + entry({"admin", "uci", "revert"}, post("action_revert"), _("Revert"), 30).query = {redir=redir} + + local node + local authen = function(checkpass, allowed_users) + return "root", luci.http.formvalue("sid") + end + + node = entry({"admin", "uci", "apply_rollback"}, post("action_apply_rollback"), nil) + node.cors = true + node.sysauth_authenticator = authen + + node = entry({"admin", "uci", "apply_unchecked"}, post("action_apply_unchecked"), nil) + node.cors = true + node.sysauth_authenticator = authen + + node = entry({"admin", "uci", "confirm"}, call("action_confirm"), nil) + node.cors = true + node.sysauth = false +end + + +function action_changes() + local uci = require "luci.model.uci" + local changes = uci:changes() + + luci.template.render("admin_uci/changes", { + changes = next(changes) and changes, + timeout = timeout, + trigger_apply = luci.http.formvalue("trigger_apply") and true or false + }) +end + +function action_revert() + local uci = require "luci.model.uci" + local changes = uci:changes() + + -- Collect files to be reverted + local r, tbl + for r, tbl in pairs(changes) do + uci:revert(r) + end + + luci.template.render("admin_uci/revert", { + changes = next(changes) and changes, + trigger_revert = true + }) +end + + +local function ubus_state_to_http(errstr) + local map = { + ["Invalid command"] = 400, + ["Invalid argument"] = 400, + ["Method not found"] = 404, + ["Entry not found"] = 404, + ["No data"] = 204, + ["Permission denied"] = 403, + ["Timeout"] = 504, + ["Not supported"] = 500, + ["Unknown error"] = 500, + ["Connection failed"] = 503 + } + + local code = map[errstr] or 200 + local msg = errstr or "OK" + + luci.http.status(code, msg) + + if code ~= 204 then + luci.http.prepare_content("text/plain") + luci.http.write(msg) + end +end + +function action_apply_rollback() + local uci = require "luci.model.uci" + local token, errstr = uci:apply(true) + if token then + luci.http.prepare_content("application/json") + luci.http.write_json({ token = token }) + else + ubus_state_to_http(errstr) + end +end + +function action_apply_unchecked() + local uci = require "luci.model.uci" + local _, errstr = uci:apply(false) + ubus_state_to_http(errstr) +end + +function action_confirm() + local uci = require "luci.model.uci" + local token = luci.http.formvalue("token") + local _, errstr = uci:confirm(token) + ubus_state_to_http(errstr) +end diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua index 6cf2712eb4..8b9003d207 100644 --- a/modules/luci-base/luasrc/dispatcher.lua +++ b/modules/luci-base/luasrc/dispatcher.lua @@ -724,32 +724,82 @@ end -- Subdispatchers -- -function _firstchild() - local path = { unpack(context.path) } - local name = table.concat(path, ".") - local node = context.treecache[name] - - local lowest - if node and node.nodes and next(node.nodes) then - local k, v - for k, v in pairs(node.nodes) do - if not lowest or - (v.order or 100) < (node.nodes[lowest].order or 100) - then - lowest = k - end - end - end +function _find_eligible_node(root, prefix, deep, types, descend) + local _, cur_name, cur_node + local childs = { } + + for cur_name, cur_node in pairs(root.nodes) do + childs[#childs+1] = { + node = cur_node, + name = cur_name, + order = cur_node.order or 100 + } + end + + table.sort(childs, function(a, b) + if a.order == b.order then + return a.name < b.name + else + return a.order < b.order + end + end) + + if not root.leaf and deep ~= nil then + local sub_path = { unpack(prefix) } + + if deep == false then + deep = nil + end + + for _, cur_node in ipairs(childs) do + sub_path[#prefix+1] = cur_node.name + + local res_path = _find_eligible_node(cur_node.node, sub_path, + deep, types, true) + + if res_path then + return res_path + end + end + end - assert(lowest ~= nil, - "The requested node contains no childs, unable to redispatch") + if descend and + (not types or + (type(root.target) == "table" and + util.contains(types, root.target.type))) + then + return prefix + end +end + +function _find_node(recurse, types) + local path = { unpack(context.path) } + local name = table.concat(path, ".") + local node = context.treecache[name] + + path = _find_eligible_node(node, path, recurse, types) - path[#path+1] = lowest - dispatch(path) + if path then + dispatch(path) + else + require "luci.template".render("empty_node_placeholder") + end +end + +function _firstchild() + return _find_node(false, nil) end function firstchild() - return { type = "firstchild", target = _firstchild } + return { type = "firstchild", target = _firstchild } +end + +function _firstnode() + return _find_node(true, { "cbi", "form", "template", "arcombine" }) +end + +function firstnode() + return { type = "firstnode", target = _firstnode } end function alias(...) diff --git a/modules/luci-base/luasrc/model/network.lua b/modules/luci-base/luasrc/model/network.lua index cce559aab1..7f7397032f 100644 --- a/modules/luci-base/luasrc/model/network.lua +++ b/modules/luci-base/luasrc/model/network.lua @@ -813,6 +813,7 @@ function del_wifinet(self, net) end function get_status_by_route(self, addr, mask) + local route_statuses = { } local _, object for _, object in ipairs(utl.ubus()) do local net = object:match("^network%.interface%.(.+)") @@ -822,12 +823,14 @@ function get_status_by_route(self, addr, mask) local rt for _, rt in ipairs(s.route) do if not rt.table and rt.target == addr and rt.mask == mask then - return net, s + route_statuses[net] = s end end end end end + + return route_statuses end function get_status_by_address(self, addr) @@ -856,24 +859,28 @@ function get_status_by_address(self, addr) end end -function get_wannet(self) - local net, stat = self:get_status_by_route("0.0.0.0", 0) - return net and network(net, stat.proto) -end +function get_wan_networks(self) + local k, v + local wan_nets = { } + local route_statuses = self:get_status_by_route("0.0.0.0", 0) -function get_wandev(self) - local _, stat = self:get_status_by_route("0.0.0.0", 0) - return stat and interface(stat.l3_device or stat.device) -end + for k, v in pairs(route_statuses) do + wan_nets[#wan_nets+1] = network(k, v.proto) + end -function get_wan6net(self) - local net, stat = self:get_status_by_route("::", 0) - return net and network(net, stat.proto) + return wan_nets end -function get_wan6dev(self) - local _, stat = self:get_status_by_route("::", 0) - return stat and interface(stat.l3_device or stat.device) +function get_wan6_networks(self) + local k, v + local wan6_nets = { } + local route_statuses = self:get_status_by_route("::", 0) + + for k, v in pairs(route_statuses) do + wan6_nets[#wan6_nets+1] = network(k, v.proto) + end + + return wan6_nets end function get_switch_topologies(self) diff --git a/modules/luci-base/luasrc/view/admin_uci/changelog.htm b/modules/luci-base/luasrc/view/admin_uci/changelog.htm new file mode 100644 index 0000000000..8a162c88b6 --- /dev/null +++ b/modules/luci-base/luasrc/view/admin_uci/changelog.htm @@ -0,0 +1,66 @@ +<%# + Copyright 2010 Jo-Philipp Wich <jo@mein.io> + Licensed to the public under the Apache License 2.0. +-%> + +<% export("uci_changelog", function(changes) -%> +<div class="cbi-section"> + <strong><%:Legend:%></strong> + <div class="uci-change-legend"> + <div class="uci-change-legend-label"><ins> </ins> <%:Section added%></div> + <div class="uci-change-legend-label"><del> </del> <%:Section removed%></div> + <div class="uci-change-legend-label"><var><ins> </ins></var> <%:Option changed%></div> + <div class="uci-change-legend-label"><var><del> </del></var> <%:Option removed%></div> + <br style="clear:both" /> + </div> + <br /> + + <div class="uci-change-list"><% + local util = luci.util + local tpl = { + ["add-3"] = "<ins>uci add %0 <strong>%3</strong> # =%2</ins>", + ["set-3"] = "<ins>uci set %0.<strong>%2</strong></ins>=%3", + ["set-4"] = "<var><ins>uci set %0.%2.%3=<strong>%4</strong></ins></var>", + ["remove-2"] = "<del>uci del %0.<strong>%2</strong></del>", + ["remove-3"] = "<var><del>uci del %0.%2.<strong>%3</strong></del></var>", + ["order-3"] = "<var>uci reorder %0.%2=<strong>%3</strong></var>", + ["list-add-4"] = "<var><ins>uci add_list %0.%2.%3=<strong>%4</strong></ins></var>", + ["list-del-4"] = "<var><del>uci del_list %0.%2.%3=<strong>%4</strong></del></var>", + ["rename-3"] = "<var>uci rename %0.%2=<strong>%3</strong></var>", + ["rename-4"] = "<var>uci rename %0.%2.%3=<strong>%4</strong></var>" + } + + local conf, deltas + for conf, deltas in util.kspairs(changes) do + write("<h3># /etc/config/%s</h3>" % conf) + + local _, delta, added + for _, delta in pairs(deltas) do + local t = tpl["%s-%d" %{ delta[1], #delta }] + + write(t:gsub("%%(%d)", function(n) + if n == "0" then + return conf + elseif n == "2" then + if added and delta[2] == added[1] then + return "@%s[-1]" % added[2] + else + return delta[2] + end + elseif n == "4" then + return util.shellquote(delta[4]) + else + return delta[tonumber(n)] + end + end)) + + if delta[1] == "add" then + added = { delta[2], delta[3] } + end + end + + write("<br />") + end + %></div> +</div> +<%- end) %> diff --git a/modules/luci-base/luasrc/view/admin_uci/changes.htm b/modules/luci-base/luasrc/view/admin_uci/changes.htm new file mode 100644 index 0000000000..43bd7c23fb --- /dev/null +++ b/modules/luci-base/luasrc/view/admin_uci/changes.htm @@ -0,0 +1,45 @@ +<%# + Copyright 2008 Steven Barth <steven@midlink.org> + Copyright 2008-2018 Jo-Philipp Wich <jo@mein.io> + Licensed to the public under the Apache License 2.0. +-%> + +<%+header%> + +<%- + local node, redir_url = luci.dispatcher.lookup(luci.http.formvalue("redir")) + export("redirect", redir_url or url("admin/uci/changes")) + + include("admin_uci/changelog") +-%> + +<h2 name="content"><%:Configuration%> / <%:Changes%></h2> + +<% if changes then %> + <%- uci_changelog(changes) -%> +<% else %> + <p><strong><%:There are no pending changes!%></strong></p> +<% end %> + +<div class="alert-message" id="cbi_apply_status" style="display:none"></div> + +<div class="cbi-page-actions"> + <% if redir_url then %> + <form method="get" action="<%=luci.util.pcdata(redir_url)%>"> + <input class="cbi-button cbi-button-link" type="submit" value="<%:Back%>" /> + </form> + <% end %> + + <form method="post" action="<%=url("admin/uci/changes")%>"> + <input type="hidden" name="token" value="<%=token%>" /> + <input type="hidden" name="redir" value="<%=pcdata(luci.http.formvalue("redir"))%>" /> + <input class="cbi-button cbi-button-save" type="submit" name="trigger_apply" value="<%:Save & Apply%>" /> + </form> + <form method="post" action="<%=url("admin/uci/revert")%>"> + <input type="hidden" name="token" value="<%=token%>" /> + <input type="hidden" name="redir" value="<%=pcdata(luci.http.formvalue("redir"))%>" /> + <input class="cbi-button cbi-button-reset" type="submit" value="<%:Revert%>" /> + </form> +</div> + +<%+footer%> diff --git a/modules/luci-base/luasrc/view/admin_uci/revert.htm b/modules/luci-base/luasrc/view/admin_uci/revert.htm new file mode 100644 index 0000000000..d8fd3de01e --- /dev/null +++ b/modules/luci-base/luasrc/view/admin_uci/revert.htm @@ -0,0 +1,33 @@ +<%# + Copyright 2008 Steven Barth <steven@midlink.org> + Copyright 2008-2018 Jo-Philipp Wich <jo@mein.io> + Licensed to the public under the Apache License 2.0. +-%> + +<%+header%> + +<%- + local node, redir_url = luci.dispatcher.lookup(luci.http.formvalue("redir")) + export("redirect", redir_url or url("admin/uci/changes")) + + include("admin_uci/changelog") +-%> + +<h2 name="content"><%:Configuration%> / <%:Revert%></h2> + +<% if changes then %> + <p><strong><%:The following changes have been reverted%>:</strong></p> + <%- uci_changelog(changes) -%> +<% else %> + <p><strong><%:There are no pending changes to revert!%></strong></p> +<% end %> + +<% if redir_url then %> + <div class="cbi-page-actions"> + <form class="inline" method="get" action="<%=luci.util.pcdata(redir_url)%>"> + <input class="cbi-button cbi-button-link" style="margin:0" type="submit" value="<%:Back%>" /> + </form> + </div> +<% end %> + +<%+footer%> diff --git a/modules/luci-base/luasrc/view/cbi/wireless_modefreq.htm b/modules/luci-base/luasrc/view/cbi/wireless_modefreq.htm new file mode 100644 index 0000000000..ebb02e489b --- /dev/null +++ b/modules/luci-base/luasrc/view/cbi/wireless_modefreq.htm @@ -0,0 +1,168 @@ +<%+cbi/valueheader%> + +<script type="text/javascript">//<![CDATA[ + var freqlist = <%= luci.http.write_json(self.iwinfo.freqlist) %>; + var hwmodes = <%= luci.http.write_json(self.iwinfo.hwmodelist or {}) %>; + var htmodes = <%= luci.http.write_json(self.iwinfo.htmodelist) %>; + + var channels = { + '11g': [ + 'auto', 'auto', true + ], + '11a': [ + 'auto', 'auto', true + ] + }; + + for (var i = 0; i < freqlist.length; i++) + channels[(freqlist[i].mhz > 2484) ? '11a' : '11g'].push( + freqlist[i].channel, + '%d (%d MHz)'.format(freqlist[i].channel, freqlist[i].mhz), + !freqlist[i].restricted + ); + + var modes = [ + '', 'Legacy', true, + 'n', 'N', hwmodes.n, + 'ac', 'AC', hwmodes.ac + ]; + + var htmodes = { + '': [ + '', '-', true + ], + 'n': [ + 'HT20', '20 MHz', htmodes.HT20, + 'HT40', '40 MHz', htmodes.HT40 + ], + 'ac': [ + 'VHT20', '20 MHz', htmodes.VHT20, + 'VHT40', '40 MHz', htmodes.VHT40, + 'VHT80', '80 MHz', htmodes.VHT80, + 'VHT160', '160 MHz', htmodes.VHT160 + ] + }; + + var bands = { + '': [ + '11g', '2.4 GHz', (channels['11g'].length > 3), + '11a', '5 GHz', (channels['11a'].length > 3) + ], + 'n': [ + '11g', '2.4 GHz', (channels['11g'].length > 3), + '11a', '5 GHz', (channels['11a'].length > 3) + ], + 'ac': [ + '11a', '5 GHz', true + ] + }; + + function cbi_set_values(sel, vals) + { + if (sel.vals) + sel.vals.selected = sel.selectedIndex; + + while (sel.options[0]) + sel.remove(0); + + for (var i = 0; vals && i < vals.length; i += 3) + { + if (!vals[i+2]) + continue; + + var opt = document.createElement('option'); + opt.value = vals[i+0]; + opt.text = vals[i+1]; + + sel.add(opt); + } + + if (!isNaN(vals.selected)) + sel.selectedIndex = vals.selected; + + sel.parentNode.style.display = (sel.options.length <= 1) ? 'none' : ''; + sel.vals = vals; + } + + function cbi_toggle_wifi_mode(id) + { + cbi_toggle_wifi_htmode(id); + cbi_toggle_wifi_band(id); + } + + function cbi_toggle_wifi_htmode(id) + { + var mode = document.getElementById(id + '.mode'); + var bwdt = document.getElementById(id + '.htmode'); + + cbi_set_values(bwdt, htmodes[mode.value]); + } + + function cbi_toggle_wifi_band(id) + { + var mode = document.getElementById(id + '.mode'); + var band = document.getElementById(id + '.band'); + + cbi_set_values(band, bands[mode.value]); + cbi_toggle_wifi_channel(id); + } + + function cbi_toggle_wifi_channel(id) + { + var band = document.getElementById(id + '.band'); + var chan = document.getElementById(id + '.channel'); + + cbi_set_values(chan, channels[band.value]); + } + + function cbi_init_wifi(id) + { + var mode = document.getElementById(id + '.mode'); + var band = document.getElementById(id + '.band'); + var chan = document.getElementById(id + '.channel'); + var bwdt = document.getElementById(id + '.htmode'); + + cbi_set_values(mode, modes); + + if (/VHT20|VHT40|VHT80|VHT160/.test(<%= luci.http.write_json(self.map:get(section, "htmode")) %>)) + mode.value = 'ac'; + else if (/HT20|HT40/.test(<%= luci.http.write_json(self.map:get(section, "htmode")) %>)) + mode.value = 'n'; + else + mode.value = ''; + + cbi_toggle_wifi_mode(id); + + if (/a/.test(<%= luci.http.write_json(self.map:get(section, "hwmode")) %>)) + band.value = '11a'; + else + band.value = '11g'; + + cbi_toggle_wifi_band(id); + + bwdt.value = <%= luci.http.write_json(self.map:get(section, "htmode")) %>; + chan.value = <%= luci.http.write_json(self.map:get(section, "channel")) %>; + } +//]]></script> + +<label style="float:left; margin-right:3px"> + <%:Mode%><br /> + <select style="width:auto" id="<%= cbid %>.mode" name="<%= cbid %>.mode" onchange="cbi_toggle_wifi_mode('<%= cbid %>')"></select> +</label> +<label style="float:left; margin-right:3px"> + <%:Band%><br /> + <select style="width:auto" id="<%= cbid %>.band" name="<%= cbid %>.band" onchange="cbi_toggle_wifi_band('<%= cbid %>')"></select> +</label> +<label style="float:left; margin-right:3px"> + <%:Channel%><br /> + <select style="width:auto" id="<%= cbid %>.channel" name="<%= cbid %>.channel"></select> +</label> +<label style="float:left; margin-right:3px"> + <%:Width%><br /> + <select style="width:auto" id="<%= cbid %>.htmode" name="<%= cbid %>.htmode"></select> +</label> +<br style="clear:left" /> + +<script type="text/javascript">cbi_init_wifi('<%= cbid %>');</script> + +<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/empty_node_placeholder.htm b/modules/luci-base/luasrc/view/empty_node_placeholder.htm new file mode 100644 index 0000000000..b7e276b960 --- /dev/null +++ b/modules/luci-base/luasrc/view/empty_node_placeholder.htm @@ -0,0 +1,11 @@ +<%# + Copyright 2010 Jo-Philipp Wich <jow@openwrt.org> + Copyright 2018 Daniel F. Dickinson <cshored@thecshore.com> + Licensed to the public under the Apache License 2.0. +-%> + +<%+header%> + +<p>Component not present.</p> + +<%+footer%> diff --git a/modules/luci-base/luasrc/view/lease_status.htm b/modules/luci-base/luasrc/view/lease_status.htm new file mode 100644 index 0000000000..15b6b6908e --- /dev/null +++ b/modules/luci-base/luasrc/view/lease_status.htm @@ -0,0 +1,95 @@ +<script type="text/javascript">//<![CDATA[ + XHR.poll(5, '<%=url('admin/dhcplease_status')%>', null, + function(x, st) + { + var tb = document.getElementById('lease_status_table'); + if (st && st[0] && tb) + { + var rows = []; + + for (var i = 0; i < st[0].length; i++) + { + var timestr; + + if (st[0][i].expires === false) + timestr = '<em><%:unlimited%></em>'; + else if (st[0][i].expires <= 0) + timestr = '<em><%:expired%></em>'; + else + timestr = String.format('%t', st[0][i].expires); + + rows.push([ + st[0][i].hostname || '?', + st[0][i].ipaddr, + st[0][i].macaddr, + timestr + ]); + } + + cbi_update_table(tb, rows, '<em><%:There are no active leases.%></em>'); + } + + var tb6 = document.getElementById('lease6_status_table'); + if (st && st[1] && tb6) + { + tb6.parentNode.style.display = 'block'; + + var rows = []; + + for (var i = 0; i < st[1].length; i++) + { + var timestr; + + if (st[1][i].expires === false) + timestr = '<em><%:unlimited%></em>'; + else if (st[1][i].expires <= 0) + timestr = '<em><%:expired%></em>'; + else + timestr = String.format('%t', st[1][i].expires); + + var name = st[1][i].hostname, + hint = st[1][i].host_hint; + + rows.push([ + hint ? '%h (%h)'.format(name || '?', hint) : (name || '?'), + st[1][i].ip6addr, + st[1][i].duid, + timestr + ]); + } + + cbi_update_table(tb6, rows, '<em><%:There are no active leases.%></em>'); + } + } + ); +//]]></script> + +<div class="cbi-section"> + <h3><%:Active DHCP Leases%></h3> + <div class="table" id="lease_status_table"> + <div class="tr table-titles"> + <div class="th"><%:Hostname%></div> + <div class="th"><%:IPv4-Address%></div> + <div class="th"><%:MAC-Address%></div> + <div class="th"><%:Leasetime remaining%></div> + </div> + <div class="tr placeholder"> + <div class="td"><em><%:Collecting data...%></em></div> + </div> + </div> +</div> + +<div class="cbi-section" style="display:none"> + <h3><%:Active DHCPv6 Leases%></h3> + <div class="table" id="lease6_status_table"> + <div class="tr table-titles"> + <div class="th"><%:Host%></div> + <div class="th"><%:IPv6-Address%></div> + <div class="th"><%:DUID%></div> + <div class="th"><%:Leasetime remaining%></div> + </div> + <div class="tr placeholder"> + <div class="td"><em><%:Collecting data...%></em></div> + </div> + </div> +</div> diff --git a/modules/luci-base/luasrc/view/wifi_assoclist.htm b/modules/luci-base/luasrc/view/wifi_assoclist.htm new file mode 100644 index 0000000000..700d998ad8 --- /dev/null +++ b/modules/luci-base/luasrc/view/wifi_assoclist.htm @@ -0,0 +1,82 @@ +<script type="text/javascript">//<![CDATA[ + function wifirate(bss, rx) { + var p = rx ? 'rx_' : 'tx_', + s = '%.1f <%:Mbit/s%>, %d<%:MHz%>' + .format(bss[p+'rate'] / 1000, bss[p+'mhz']), + ht = bss[p+'ht'], vht = bss[p+'vht'], + mhz = bss[p+'mhz'], nss = bss[p+'nss'], + mcs = bss[p+'mcs'], sgi = bss[p+'short_gi']; + + if (ht || vht) { + if (vht) s += ', VHT-MCS %d'.format(mcs); + if (nss) s += ', VHT-NSS %d'.format(nss); + if (ht) s += ', MCS %s'.format(mcs); + if (sgi) s += ', <%:Short GI%>'; + } + + return s; + } + + XHR.poll(5, '<%=url('admin/wireless_assoclist')%>', null, + function(x, st) + { + var tb = document.getElementById('wifi_assoclist_table'); + if (st && tb) + { + var rows = []; + + st.forEach(function(bss) { + var icon; + var q = (-1 * (bss.noise - bss.signal)) / 5; + if (q < 1) + icon = "<%=resource%>/icons/signal-0.png"; + else if (q < 2) + icon = "<%=resource%>/icons/signal-0-25.png"; + else if (q < 3) + icon = "<%=resource%>/icons/signal-25-50.png"; + else if (q < 4) + icon = "<%=resource%>/icons/signal-50-75.png"; + else + icon = "<%=resource%>/icons/signal-75-100.png"; + + rows.push([ + '<span class="ifacebadge" title="%q"><img src="<%=resource%>/icons/wifi.png" /> <a href="%s">%h</a><small> (%h)</small></span>'.format( + bss.radio, + bss.link, + bss.name, + bss.ifname), + bss.bssid, + bss.host_hint ? '%h (%h)'.format(bss.host_name || '?', bss.host_hint) : (bss.host_name || '?'), + '<span class="ifacebadge" title="<%:Signal%>: %d <%:dBm%> / <%:Noise%>: %d <%:dBm%> / <%:SNR%>: %d"><img src="%s" /> %d / %d <%:dBm%></span>'.format( + bss.signal, + bss.noise, + bss.signal - bss.noise, + icon, + bss.signal, + bss.noise), + E('span', {}, [ + E('span', wifirate(bss, true)), + E('br'), + E('span', wifirate(bss, false)) + ]) + ]); + }); + + cbi_update_table(tb, rows, '<em><%:No information available%></em>'); + } + } + ); +//]]></script> + +<div class="table" id="wifi_assoclist_table"> + <div class="tr table-titles"> + <div class="th nowrap"><%:Network%></div> + <div class="th hide-xs"><%:MAC-Address%></div> + <div class="th nowrap"><%:Host%></div> + <div class="th nowrap"><%:Signal%> / <%:Noise%></div> + <div class="th nowrap"><%:RX Rate%> / <%:TX Rate%></div> + </div> + <div class="tr placeholder"> + <div class="td"><em><%:Collecting data...%></em></div> + </div> +</div> |