From 2141016869f186f5397fc303cc23aa27586ff356 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 21 Oct 2026 01:19:43 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=8B=20Sync=202026-10-21=2001:19:43?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {openwrt-gately/gately => gately}/Makefile | 4 +- .../gately => gately}/files/gately.config | 0 .../gately => gately}/files/gately.init | 0 honk/Makefile | 14 +- .../Makefile | 0 .../luci-static/resources/view/gately/log.js | 0 .../resources/view/gately/settings.js | 0 .../resources/view/gately/status.js | 0 .../po/templates/gately.pot | 0 luci-app-gately/po/zh-cn | 1 + .../po/zh_Hans/gately.po | 0 .../root/etc/uci-defaults/66_luci-gately | 0 .../share/luci/menu.d/luci-app-gately.json | 0 .../usr/share/rpcd/acl.d/luci-app-gately.json | 0 .../root/usr/share/rpcd/ucode/luci.gately | 0 luci-app-passwall/Makefile | 9 +- luci-app-passwall2/Makefile | 2 +- luci-app-passwall2/luasrc/passwall2/api.lua | 19 + luci-app-passwall2/po/fa/passwall2.po | 3 + luci-app-passwall2/po/ru/passwall2.po | 3 + luci-app-passwall2/po/zh-cn/passwall2.po | 3 + luci-app-passwall2/po/zh-tw/passwall2.po | 3 + .../root/usr/share/passwall2/subscribe.lua | 95 ++- luci-app-vantage/Makefile | 2 +- .../luci-static/resources/vantage/app.css | 32 +- .../resources/view/vantage/overview.js | 25 +- luci-app-vantage/po/templates/vantage.pot | 740 +++++++++--------- luci-app-vantage/po/zh_Hans/vantage.po | 732 ++++++++--------- luci-theme-vantage/Makefile | 2 +- .../luci-static/resources/menu-vantage.js | 9 + .../resources/vantage-theme/nftflow.js | 480 ++++++++++++ .../resources/vantage-theme/nftmodel.js | 255 ++++++ .../htdocs/luci-static/vantage/vantage.css | 196 +++++ .../po/templates/vantage-theme.pot | 357 ++++++++- 34 files changed, 2169 insertions(+), 817 deletions(-) rename {openwrt-gately/gately => gately}/Makefile (98%) rename {openwrt-gately/gately => gately}/files/gately.config (100%) rename {openwrt-gately/gately => gately}/files/gately.init (100%) rename {openwrt-gately/luci-app-gately => luci-app-gately}/Makefile (100%) rename {openwrt-gately/luci-app-gately => luci-app-gately}/htdocs/luci-static/resources/view/gately/log.js (100%) rename {openwrt-gately/luci-app-gately => luci-app-gately}/htdocs/luci-static/resources/view/gately/settings.js (100%) rename {openwrt-gately/luci-app-gately => luci-app-gately}/htdocs/luci-static/resources/view/gately/status.js (100%) rename {openwrt-gately/luci-app-gately => luci-app-gately}/po/templates/gately.pot (100%) create mode 120000 luci-app-gately/po/zh-cn rename {openwrt-gately/luci-app-gately => luci-app-gately}/po/zh_Hans/gately.po (100%) rename {openwrt-gately/luci-app-gately => luci-app-gately}/root/etc/uci-defaults/66_luci-gately (100%) rename {openwrt-gately/luci-app-gately => luci-app-gately}/root/usr/share/luci/menu.d/luci-app-gately.json (100%) rename {openwrt-gately/luci-app-gately => luci-app-gately}/root/usr/share/rpcd/acl.d/luci-app-gately.json (100%) rename {openwrt-gately/luci-app-gately => luci-app-gately}/root/usr/share/rpcd/ucode/luci.gately (100%) create mode 100644 luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js create mode 100644 luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftmodel.js diff --git a/openwrt-gately/gately/Makefile b/gately/Makefile similarity index 98% rename from openwrt-gately/gately/Makefile rename to gately/Makefile index 5114f0cc2..34a885c14 100644 --- a/openwrt-gately/gately/Makefile +++ b/gately/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=gately -PKG_VERSION:=0.3.1 -PKG_RELEASE:=2 +PKG_VERSION:=0.5.2 +PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/wangwanjie/gately/tar.gz/v$(PKG_VERSION)? diff --git a/openwrt-gately/gately/files/gately.config b/gately/files/gately.config similarity index 100% rename from openwrt-gately/gately/files/gately.config rename to gately/files/gately.config diff --git a/openwrt-gately/gately/files/gately.init b/gately/files/gately.init similarity index 100% rename from openwrt-gately/gately/files/gately.init rename to gately/files/gately.init diff --git a/honk/Makefile b/honk/Makefile index d6ddc8832..a6092ce69 100644 --- a/honk/Makefile +++ b/honk/Makefile @@ -3,17 +3,17 @@ include $(TOPDIR)/rules.mk PKG_NAME:=honk -PKG_VERSION:=2026.10.15_pre1 -PKG_RELEASE:=19 +PKG_VERSION:=2026.10.21.1_pre1 +PKG_RELEASE:=20 # Raw upstream release tag. It keeps the dots in qualifiers (e.g. v0.0.1.beta.49) # because that is what the GitHub release asset name uses. -HONK_RELEASE_TAG:=debug.2026.10.15.native-api.1 +HONK_RELEASE_TAG:=debug.2026.10.21.1 HONK_ASSET_TAG:=debug # SHA256 of each release tarball, kept in sync by scripts/update_honk_version.sh. -HONK_HASH_X86_64:=b492c22fbf9347b741fe8904fbe1c6fb128e1f7b391b60f3925cec4cf14b5085 -HONK_HASH_AARCH64:=ce25b0df9bfeb371a5340392df91606a8da6d209f1779d59dd1bd5abafe2c8a4 +HONK_HASH_X86_64:=0714b035fb39efcdd9ab5f8b759ccd647847b3fe293ed51b4fafe11603834e3d +HONK_HASH_AARCH64:=d63a51bf922899ababf5bbddc9913a4a7a6df17fbbeb021a127b85bc740e0568 PKG_LICENSE:=AGPL-3.0-only PKG_LICENSE_FILE:=LICENSE @@ -33,7 +33,7 @@ HONK_SUFFIX:=-stock HONK_ASSET:=honk-core-$(HONK_ASSET_TAG)-$(HONK_TARGET)$(HONK_SUFFIX).tar.gz PKG_SOURCE:=$(HONK_ASSET) -PKG_SOURCE_URL:=https://github.com/Glassyiris/honk/releases/download/$(HONK_RELEASE_TAG)/ +PKG_SOURCE_URL:=https://github.com/daeuniverse/honk/releases/download/$(HONK_RELEASE_TAG)/ PKG_HASH:=skip include $(INCLUDE_DIR)/package.mk @@ -43,7 +43,7 @@ define Package/honk CATEGORY:=Network SUBMENU:=Web Servers/Proxies TITLE:=honk - eBPF transparent proxy engine (dae-compatible) - URL:=https://github.com/Glassyiris/honk + URL:=https://github.com/daeuniverse/honk DEPENDS:=@(x86_64||aarch64) \ +ca-bundle +ip-full \ +kmod-sched-core +kmod-sched-bpf +kmod-veth +kmod-nft-queue \ diff --git a/openwrt-gately/luci-app-gately/Makefile b/luci-app-gately/Makefile similarity index 100% rename from openwrt-gately/luci-app-gately/Makefile rename to luci-app-gately/Makefile diff --git a/openwrt-gately/luci-app-gately/htdocs/luci-static/resources/view/gately/log.js b/luci-app-gately/htdocs/luci-static/resources/view/gately/log.js similarity index 100% rename from openwrt-gately/luci-app-gately/htdocs/luci-static/resources/view/gately/log.js rename to luci-app-gately/htdocs/luci-static/resources/view/gately/log.js diff --git a/openwrt-gately/luci-app-gately/htdocs/luci-static/resources/view/gately/settings.js b/luci-app-gately/htdocs/luci-static/resources/view/gately/settings.js similarity index 100% rename from openwrt-gately/luci-app-gately/htdocs/luci-static/resources/view/gately/settings.js rename to luci-app-gately/htdocs/luci-static/resources/view/gately/settings.js diff --git a/openwrt-gately/luci-app-gately/htdocs/luci-static/resources/view/gately/status.js b/luci-app-gately/htdocs/luci-static/resources/view/gately/status.js similarity index 100% rename from openwrt-gately/luci-app-gately/htdocs/luci-static/resources/view/gately/status.js rename to luci-app-gately/htdocs/luci-static/resources/view/gately/status.js diff --git a/openwrt-gately/luci-app-gately/po/templates/gately.pot b/luci-app-gately/po/templates/gately.pot similarity index 100% rename from openwrt-gately/luci-app-gately/po/templates/gately.pot rename to luci-app-gately/po/templates/gately.pot diff --git a/luci-app-gately/po/zh-cn b/luci-app-gately/po/zh-cn new file mode 120000 index 000000000..8d69574dd --- /dev/null +++ b/luci-app-gately/po/zh-cn @@ -0,0 +1 @@ +zh_Hans \ No newline at end of file diff --git a/openwrt-gately/luci-app-gately/po/zh_Hans/gately.po b/luci-app-gately/po/zh_Hans/gately.po similarity index 100% rename from openwrt-gately/luci-app-gately/po/zh_Hans/gately.po rename to luci-app-gately/po/zh_Hans/gately.po diff --git a/openwrt-gately/luci-app-gately/root/etc/uci-defaults/66_luci-gately b/luci-app-gately/root/etc/uci-defaults/66_luci-gately similarity index 100% rename from openwrt-gately/luci-app-gately/root/etc/uci-defaults/66_luci-gately rename to luci-app-gately/root/etc/uci-defaults/66_luci-gately diff --git a/openwrt-gately/luci-app-gately/root/usr/share/luci/menu.d/luci-app-gately.json b/luci-app-gately/root/usr/share/luci/menu.d/luci-app-gately.json similarity index 100% rename from openwrt-gately/luci-app-gately/root/usr/share/luci/menu.d/luci-app-gately.json rename to luci-app-gately/root/usr/share/luci/menu.d/luci-app-gately.json diff --git a/openwrt-gately/luci-app-gately/root/usr/share/rpcd/acl.d/luci-app-gately.json b/luci-app-gately/root/usr/share/rpcd/acl.d/luci-app-gately.json similarity index 100% rename from openwrt-gately/luci-app-gately/root/usr/share/rpcd/acl.d/luci-app-gately.json rename to luci-app-gately/root/usr/share/rpcd/acl.d/luci-app-gately.json diff --git a/openwrt-gately/luci-app-gately/root/usr/share/rpcd/ucode/luci.gately b/luci-app-gately/root/usr/share/rpcd/ucode/luci.gately similarity index 100% rename from openwrt-gately/luci-app-gately/root/usr/share/rpcd/ucode/luci.gately rename to luci-app-gately/root/usr/share/rpcd/ucode/luci.gately diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index ac0993c16..8c469bf48 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -8,13 +8,14 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall PKG_VERSION:=26.10.16 -PKG_RELEASE:=341 +PKG_RELEASE:=342 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ CONFIG_PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Geoview \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_SmartDNS \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \ @@ -38,6 +39,7 @@ LUCI_DEPENDS:=+coreutils +coreutils-base64 +coreutils-nohup +coreutils-timeout + +microsocks +resolveip +tcping +lyaml \ +ipt2socks \ +PACKAGE_$(PKG_NAME)_INCLUDE_Geoview:geoview \ + +PACKAGE_$(PKG_NAME)_INCLUDE_SmartDNS:smartdns \ +PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy:haproxy \ +PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \ +PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \ @@ -86,7 +88,10 @@ config PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy config PACKAGE_$(PKG_NAME)_INCLUDE_Geoview bool "Include Geoview" - select PACKAGE_geoview + default y if aarch64||i386||x86_64 + +config PACKAGE_$(PKG_NAME)_INCLUDE_SmartDNS + bool "Include SmartDNS" default y if aarch64||i386||x86_64 config PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 46ec46277..4a8ca021b 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 PKG_VERSION:=26.10.20 -PKG_RELEASE:=147 +PKG_RELEASE:=148 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall2/luasrc/passwall2/api.lua b/luci-app-passwall2/luasrc/passwall2/api.lua index 8adf54b19..d9f841ce4 100644 --- a/luci-app-passwall2/luasrc/passwall2/api.lua +++ b/luci-app-passwall2/luasrc/passwall2/api.lua @@ -288,6 +288,25 @@ function UrlDecode(szText) end) or nil end +-- Calculate the MD5 hash of a file. +function md5_file(path) + if type(path) ~= "string" then return "" end + local quoted = "'" .. path:gsub("'", "'\\''") .. "'" + local out = sys.exec("md5sum " .. quoted) + if not out then return "" end + return out:sub(1, 32) +end + +-- Calculate the MD5 hash of a string. +function md5_string(str) + if type(str) ~= "string" then return "" end + local path = trim(sys.exec("mktemp /tmp/md5.XXXXXX") or "") + if path == "" then return "" end + local md5 = fs.writefile(path, str) == #str and md5_file(path) or "" + fs.unlink(path) + return md5 +end + -- Extract the domain name and port from the URL (no IP address). function get_domain_port_from_url(url) local scheme, domain, port = string.match(url, "^(https?)://([%w%.%-]+):?(%d*)") diff --git a/luci-app-passwall2/po/fa/passwall2.po b/luci-app-passwall2/po/fa/passwall2.po index 3aac913aa..b07cb5f3c 100644 --- a/luci-app-passwall2/po/fa/passwall2.po +++ b/luci-app-passwall2/po/fa/passwall2.po @@ -2450,6 +2450,9 @@ msgstr "شروع اشتراک‌گیری: %s" msgid "Subscription: [%s] No changes, no update required." msgstr "اشتراک: [%s] بدون تغییر، نیازی به به‌روزرسانی نیست." +msgid "Refresh subscription [%s] account usage and expiration information." +msgstr "به‌روزرسانی اطلاعات میزان مصرف حساب و زمان انقضای اشتراک [%s]." + msgid "[%s] Subscription failed. This could be due to an invalid subscription address or a network issue. Please diagnose the problem! [%s]" msgstr "[%s] اشتراک ناموفق بود. این می‌تواند به دلیل آدرس اشتراک نامعتبر یا مشکل شبکه باشد. لطفاً مشکل را بررسی کنید! [%s]" diff --git a/luci-app-passwall2/po/ru/passwall2.po b/luci-app-passwall2/po/ru/passwall2.po index 85588a2b6..8fcf23000 100644 --- a/luci-app-passwall2/po/ru/passwall2.po +++ b/luci-app-passwall2/po/ru/passwall2.po @@ -2451,6 +2451,9 @@ msgstr "Начало подписки: %s" msgid "Subscription: [%s] No changes, no update required." msgstr "Подписка: [%s] изменений нет, обновление не требуется." +msgid "Refresh subscription [%s] account usage and expiration information." +msgstr "Обновление информации об использовании трафика и сроке действия учётной записи подписки [%s]." + msgid "[%s] Subscription failed. This could be due to an invalid subscription address or a network issue. Please diagnose the problem! [%s]" msgstr "[%s] Ошибка подписки. Возможно, адрес подписки неверен или есть проблема с сетью. Пожалуйста, проведите диагностику! [%s]" diff --git a/luci-app-passwall2/po/zh-cn/passwall2.po b/luci-app-passwall2/po/zh-cn/passwall2.po index 4cda9e08f..243f722a9 100644 --- a/luci-app-passwall2/po/zh-cn/passwall2.po +++ b/luci-app-passwall2/po/zh-cn/passwall2.po @@ -2436,6 +2436,9 @@ msgstr "开始订阅:%s" msgid "Subscription: [%s] No changes, no update required." msgstr "订阅:【%s】没有变化,无需更新。" +msgid "Refresh subscription [%s] account usage and expiration information." +msgstr "刷新订阅【%s】账户用量与到期时间信息。" + msgid "[%s] Subscription failed. This could be due to an invalid subscription address or a network issue. Please diagnose the problem! [%s]" msgstr "【%s】订阅失败,可能是订阅地址无效,或是网络问题,请诊断![%s]" diff --git a/luci-app-passwall2/po/zh-tw/passwall2.po b/luci-app-passwall2/po/zh-tw/passwall2.po index 9cdc756b7..1b1ddd51f 100644 --- a/luci-app-passwall2/po/zh-tw/passwall2.po +++ b/luci-app-passwall2/po/zh-tw/passwall2.po @@ -2442,6 +2442,9 @@ msgstr "開始訂閱:%s" msgid "Subscription: [%s] No changes, no update required." msgstr "訂閱:【%s】沒有變化,無需更新。" +msgid "Refresh subscription [%s] account usage and expiration information." +msgstr "重新整理訂閱【%s】帳戶用量與到期時間資訊。" + msgid "[%s] Subscription failed. This could be due to an invalid subscription address or a network issue. Please diagnose the problem! [%s]" msgstr "【%s】訂閱失敗,可能是訂閱地址無效,或是網絡問題,請診斷![%s]" diff --git a/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua b/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua index 18a566f78..afcb4a73a 100755 --- a/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua +++ b/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua @@ -15,7 +15,22 @@ local base64Decode = api.base64Decode local jsonParse, jsonStringify = api.jsonc.parse, api.jsonc.stringify local UrlEncode, UrlDecode = api.UrlEncode, api.UrlDecode local fs = api.fs -local log = api.log +local log_buffer +local function log(...) + if log_buffer then + table.insert(log_buffer, {...}) + else + api.log(...) + end +end + +local function flush_log_buffer() + local buffered = log_buffer + log_buffer = nil + for _, args in ipairs(buffered or {}) do + log(unpack(args)) + end +end local i18n = api.i18n local uci, uci_get, uci_set, uci_del, uci_foreach, uci_save = api.uci, api.uci_get_c, api.uci_set_c, api.uci_del_c, api.uci_foreach_c, api.uci_save_c @@ -2389,10 +2404,29 @@ local function select_node(nodes, config, parentConfig) end end +-- Write account information only when it changes; commit together with node updates. +local function update_subscribe_info() + local changed = {} + for cfgid, info in pairs(subscribe_info) do + for key, value in pairs(info) do + value = value and value ~= "" and value or nil + if uci_get(cfgid, key) ~= value then + if value then + uci_set(cfgid, key, value) + else + uci_del(cfgid, key) + end + changed[cfgid] = true + end + end + end + return changed +end + local function update_node(manual) if next(nodeResult) == nil then log(1, i18n.translatef("No node information updates are available.")) - return + return false end local group = {} @@ -2479,17 +2513,6 @@ local function update_node(manual) end end end - -- Update subscription information - for cfgid, info in pairs(subscribe_info) do - for key, value in pairs(info) do - if value ~= "" then - uci_set(cfgid, key, value) - else - uci_del(cfgid, key) - end - end - end - if next(CONFIG) then local nodes = {} uci_foreach("nodes", function(node) @@ -2514,9 +2537,7 @@ local function update_node(manual) end end - uci_save(true) - - if manual ~= 1 then restart_required = true end + return true end local function parse_link(raw, add_mode, group, sub_cfg) @@ -2619,7 +2640,7 @@ local function parse_link(raw, add_mode, group, sub_cfg) ) end end - if #node_list > 0 then + if add_mode ~= "2" and #node_list > 0 then nodeResult[#nodeResult + 1] = { remark = group, list = node_list, @@ -2627,10 +2648,12 @@ local function parse_link(raw, add_mode, group, sub_cfg) } end log(2, i18n.translatef("Successfully resolved the [%s] node, number: %s", group, #node_list)) + return node_list else if add_mode == "2" then log(2, i18n.translatef("Get subscription content for [%s] is empty. This may be due to an invalid subscription address or a network problem. Please diagnose the issue!", group)) end + return {} end end @@ -2680,13 +2703,24 @@ local execute = function() local stdout = f:read("*all") f:close() local raw_data = api.trim(stdout) + -- Buffer parsing details until the parsed nodes are known to have changed. + log_buffer = {} + local parsed_nodes = parse_link(raw_data, "2", remark, value) local old_md5 = value.md5 or "" - local new_md5 = luci.sys.exec("md5sum " .. tmp_file .. " 2>/dev/null | awk '{printf \"%s\", $1}'") - if not manual_sub and old_md5 == new_md5 then + local new_md5 = #parsed_nodes > 0 and api.md5_string(jsonStringify(parsed_nodes)) or "" + if not manual_sub and new_md5 ~= "" and old_md5 == new_md5 then + log_buffer = nil log(1, i18n.translatef("Subscription: [%s] No changes, no update required.", remark)) else - parse_link(raw_data, "2", remark, value) - uci_set(cfgid, "md5", new_md5) + flush_log_buffer() + if #parsed_nodes > 0 then + nodeResult[#nodeResult + 1] = { + remark = remark, + list = parsed_nodes, + sub_cfg = value, + md5 = new_md5 + } + end end else fail_list[#fail_list + 1] = value @@ -2704,13 +2738,28 @@ local execute = function() log(1, i18n.translatef("[%s] Subscription failed. This could be due to an invalid subscription address or a network issue. Please diagnose the problem! [%s]", value.remark, tostring(value.http_code))) end end - update_node(0) + local nodes_changed = update_node(0) + local info_changed = update_subscribe_info() + -- Save nodes, references and their MD5 in the same commit. + for _, result in ipairs(nodeResult) do + uci_set(result.sub_cfg[".name"], "md5", result.md5) + end + if nodes_changed or next(info_changed) then + uci_save(true) + restart_required = nodes_changed + for _, value in ipairs(subscribe_list) do + if info_changed[value[".name"]] then + log(1, i18n.translatef("Refresh subscription [%s] account usage and expiration information.", value.remark or "")) + end + end + end end end if arg[1] == "start" then log(0, i18n.translate("Start subscribing...")) xpcall(execute, function(e) + flush_log_buffer() log(1, e) if type(debug) == "table" and type(debug.traceback) == "function" then log(1, debug.traceback()) @@ -2723,7 +2772,7 @@ elseif arg[1] == "add" then local raw = f:read('*all') f:close() parse_link(raw, "1", arg[2]) - update_node(1) + if update_node(1) then uci_save(true) end luci.sys.call("rm -f /tmp/links.conf") elseif arg[1] == "truncate" then truncate_nodes(arg[2]) diff --git a/luci-app-vantage/Makefile b/luci-app-vantage/Makefile index 62a252ce7..676db6e55 100644 --- a/luci-app-vantage/Makefile +++ b/luci-app-vantage/Makefile @@ -11,7 +11,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-vantage PKG_VERSION:=1.0.8 -PKG_RELEASE:=14 +PKG_RELEASE:=15 PKG_LICENSE:=GPL-3.0-or-later LUCI_TITLE:=Vantage dashboard diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/app.css b/luci-app-vantage/htdocs/luci-static/resources/vantage/app.css index 16beef809..8c9668497 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/vantage/app.css +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/app.css @@ -50,6 +50,7 @@ --vt-ctl: var(--v-ctl-h, 36px); /* every control: buttons, fields, chips */ --vt-r-ctl: var(--v-r, 6px); /* their corners, as the theme's controls */ --vt-shadow: var(--v-shadow, 0 1px 2px rgba(16, 20, 24, .05), 0 1px 1px rgba(16, 20, 24, .03)); + --vt-shadow-pop: var(--v-shadow-pop, 0 12px 32px rgba(16, 20, 24, .16), 0 2px 6px rgba(16, 20, 24, .08)); /* derived: readable accent for text/strokes on surfaces (a lime or vermilion accent is a fill colour, not a text colour) */ @@ -114,6 +115,7 @@ html[data-darkmode="true"] .vt-app { --vt-info: var(--v-info, #6aa8ff); --vt-info-soft: var(--v-info-soft, rgba(106, 168, 255, .14)); --vt-shadow: var(--v-shadow, 0 1px 0 rgba(255, 255, 255, .03) inset, 0 1px 2px rgba(0, 0, 0, .3)); + --vt-shadow-pop: var(--v-shadow-pop, 0 16px 40px rgba(0, 0, 0, .55)); --vt-accent-text: color-mix(in oklab, var(--vt-accent) 72%, var(--vt-text)); --vt-accent-line: var(--vt-accent); --vt-chart-1: var(--v-chart-1, #c8f031); @@ -354,6 +356,28 @@ html[data-darkmode="true"] .vt-app { background-position: calc(100% - 15px) 50%, calc(100% - 10px) 50%; background-size: 5px 5px, 5px 5px; } .vt-app .vt-select:hover { border-color: var(--vt-text-3); } +/* the open list: browsers that can style it (customizable select) draw + it like the theme's dropdowns; others keep their own */ +@supports (appearance: base-select) { + .vt-app .vt-select, .vt-app .vt-select::picker(select) { appearance: base-select; } + /* sized by the chosen label here, not the longest: keep room for + the longest ("Mirrored, scale per direction") so the bar holds still */ + .vt-app .vt-select { display: inline-flex; align-items: center; min-width: 16em; } + .vt-app .vt-select::picker-icon { display: none; } + .vt-app .vt-select::picker(select) { + margin: 4px 0; padding: 4px; + border: 1px solid var(--vt-line-2); border-radius: var(--vt-r-ctl); + background: var(--vt-surface); color: var(--vt-text); box-shadow: var(--vt-shadow-pop); + } + .vt-app .vt-select option { + min-height: 32px; padding: 0 10px; gap: 8px; + border-radius: var(--vt-r-sm); font-size: var(--vt-fs-base); cursor: pointer; + } + /* the option under the pointer or keyboard, as the theme's dropdowns mark it */ + .vt-app .vt-select option:is(:hover, :focus, :focus-visible) { background: var(--vt-surface-3); box-shadow: inset 2px 0 0 var(--vt-accent-text); outline: none; } + .vt-app .vt-select option:checked { font-weight: 600; } + .vt-app .vt-select option::checkmark { color: var(--vt-accent-text); } +} @container vt (max-width: 699px) { .vt-app .vt-editbar { padding: 8px 8px 8px 12px; gap: 8px; } .vt-app .vt-editbar-text { flex-basis: 0; } @@ -1010,7 +1034,11 @@ h2, h3{ /* ---------------------------------------------------- 10. talkers, SSIDs */ -.vt-app .vt-talkers { display: flex; flex-direction: column; gap: 2px; } +.vt-app .vt-talkers { display: flex; flex-direction: column; gap: 2px; position: relative; } +/* the rows a short list leaves free keep their room (one line per name, + so every row is as tall); the empty note sits over them */ +.vt-app .vt-talk-slot { visibility: hidden; cursor: default; } +.vt-app .vt-talkers > .vt-empty-inline { position: absolute; top: 0; left: 0; right: 0; margin: 0; } .vt-app .vt-talk-row, .vt-app .vt-ssid, .vt-app .vt-dlist-row { display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px; @@ -1021,7 +1049,7 @@ h2, h3{ .vt-app .vt-talk-rank { width: 14px; font-size: var(--vt-fs-sm); color: var(--vt-text-3); font-weight: 650; text-align: center; flex: none; } .vt-app .vt-talk-main { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; } .vt-app .vt-talk-top { display: flex; justify-content: space-between; gap: 10px; } -.vt-app .vt-talk-name { font-weight: 600; line-height: 1.3; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } +.vt-app .vt-talk-name { font-weight: 600; line-height: 1.3; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .vt-app .vt-talk-share { font-size: var(--vt-fs-sm); font-weight: 650; color: var(--vt-text-2); white-space: nowrap; } .vt-app .vt-talk-sub b { color: var(--vt-text); font-weight: 650; } .vt-app .vt-talk-bar { height: 5px; border-radius: 3px; background: var(--vt-surface-3); overflow: hidden; } diff --git a/luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js b/luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js index d7bfac3df..3d7222a30 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js +++ b/luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js @@ -22,6 +22,7 @@ var POLL_S = 5; var WINDOW_MS = 5 * 60 * 1000; /* throughput history shown */ var HIST_MAX = 90; var GONE_KEEP_MS = 5 * 60 * 1000; /* disconnected stations stay listed */ +var TALKERS = 3; /* top talkers shown; the tile keeps room for all */ var STORE_KEY = 'vantage.hist.v1'; var SVGNS = 'http://www.w3.org/2000/svg'; var HOSTAPD_OBJ = /^[A-Za-z0-9_.-]{1,64}$/; @@ -651,7 +652,7 @@ return view.extend({ st.health = insight.health(m, { cpu: st.cpu, uplinkRate: st.uplinkRate }); st.summary = insight.summary(st.health); st.radioInsights = insight.radioInsights(m.radios, st.radioRates); - st.talkers = insight.topTalkers(m.clients, st.staRates, 5); + st.talkers = insight.topTalkers(m.clients, st.staRates, TALKERS); this.m = m; this.lastRaw = raw; this.resolveMore(m); @@ -742,7 +743,7 @@ return view.extend({ this.markWired(m, null); this.stickyGen(m); m.clients.forEach(function(c) { c.exp = insight.experience(c); c.firstSeen = st.presence && st.presence.firstSeen[c.mac]; c.isNew = !!st.isNew[c.mac]; }); - st.talkers = insight.topTalkers(m.clients, st.staRates, 5); + st.talkers = insight.topTalkers(m.clients, st.staRates, TALKERS); st.health = insight.health(m, { cpu: st.cpu, uplinkRate: st.uplinkRate }); st.summary = insight.summary(st.health); this.m = m; @@ -2334,14 +2335,26 @@ return view.extend({ ]); }, + /* always TALKERS rows tall: unused rows stay as hidden slots, so the + tile keeps its height as talkers come and go */ paintTalkers: function() { var self = this, m = this.m, t = this.st.talkers || []; + var byMac = {}, slots = []; + m.clients.forEach(function(c) { byMac[c.mac] = c; }); + for (var k = t.length; k < TALKERS; k++) + slots.push(E('div', { 'class': 'vt-talk-row vt-talk-slot', 'aria-hidden': 'true' }, [ + E('span', { 'class': 'vt-talk-rank vt-tn' }, [ ' ' ]), + avatar({}, true), + E('span', { 'class': 'vt-talk-main' }, [ + E('span', { 'class': 'vt-talk-top' }, [ E('span', { 'class': 'vt-talk-name' }, [ ' ' ]) ]), + E('span', { 'class': 'vt-talk-bar' }), + E('span', { 'class': 'vt-talk-sub vt-tn' }, [ E('b', {}, [ ' ' ]), E('span', { 'class': 'vt-talk-share' }, [ ' ' ]) ]) + ]) + ])); if (!t.length) { - dom.content(this.el.talkers, [ E('p', { 'class': 'vt-empty-inline' }, [ m.clients.length ? _('Nobody is moving data right now.') : _('No clients connected.') ]) ]); + dom.content(this.el.talkers, [ E('p', { 'class': 'vt-empty-inline' }, [ m.clients.length ? _('Nobody is moving data right now.') : _('No clients connected.') ]) ].concat(slots)); return; } - var byMac = {}; - m.clients.forEach(function(c) { byMac[c.mac] = c; }); dom.content(this.el.talkers, t.map(function(x, i) { var c = byMac[x.mac] || { mac: x.mac, name: x.name, icon: 'device' }; var fill = E('span', { 'class': 'vt-talk-fill' }); @@ -2356,7 +2369,7 @@ return view.extend({ E('b', {}, [ fmt.bits(x.total) ]), E('span', { 'class': 'vt-talk-share' }, [ fmt.pct(x.share * 100) ]), '↓ ' + fmt.bitsShort(x.down) + ' ↑ ' + fmt.bitsShort(x.up) ]) ]) ]); - })); + }).concat(slots)); }, /* ------------------------------------------------------------ SSIDs */ diff --git a/luci-app-vantage/po/templates/vantage.pot b/luci-app-vantage/po/templates/vantage.pot index ae43d53d2..cef305aa5 100644 --- a/luci-app-vantage/po/templates/vantage.pot +++ b/luci-app-vantage/po/templates/vantage.pot @@ -1,7 +1,7 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2698 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2711 msgid "%d MHz (%d–%d MHz)" msgstr "" @@ -21,23 +21,23 @@ msgstr "" msgid "%d SSIDs · %d idle" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1262 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1491 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2061 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1263 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1492 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2062 msgid "%d clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2264 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2265 msgid "%d connected" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:101 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1568 msgid "%d down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2742 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2743 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2755 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2756 msgid "%d errors" msgstr "" @@ -45,24 +45,24 @@ msgstr "" msgid "%d h ago" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2744 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2757 msgid "%d in · %d out" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:373 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:374 msgid "%d min" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:90 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:367 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:368 msgid "%d min ago" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2264 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2265 msgid "%d of %d" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1150 msgid "%d of %d columns" msgstr "" @@ -74,7 +74,7 @@ msgstr "" msgid "%d older devices (Wi-Fi 4 or earlier) slow airtime" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1534 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1535 msgid "%d on %s" msgstr "" @@ -82,20 +82,20 @@ msgstr "" msgid "%d on this router, %d into your network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2053 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2054 msgid "%d radios" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:373 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:374 msgid "%d s" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:89 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:367 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:368 msgid "%d s ago" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2554 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2567 msgid "%d sent · %s retried · %s failed" msgstr "" @@ -112,7 +112,7 @@ msgstr "" msgid "%d weak" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2072 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2073 msgid "%d–%d MHz of the %d–%d MHz band" msgstr "" @@ -130,7 +130,7 @@ msgstr "" msgid "%s (IPv%d)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2549 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2562 msgid "%s (new this session)" msgstr "" @@ -141,10 +141,10 @@ msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:131 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:103 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2079 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2093 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2308 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2691 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2080 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2094 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2309 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2704 msgid "%s MHz" msgstr "" @@ -158,7 +158,7 @@ msgstr "" msgid "%s accepts every connection" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2548 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2561 msgid "%s ago" msgstr "" @@ -167,12 +167,12 @@ msgid "%s at %s; below %s roaming and throughput suffer" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:78 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1771 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1772 msgid "%s available" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2098 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2699 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2099 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2712 msgid "%s dBm" msgstr "" @@ -184,7 +184,7 @@ msgstr "" msgid "%s device on a newer radio; uses more airtime per byte" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2516 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2529 msgid "%s experience" msgstr "" @@ -200,7 +200,7 @@ msgstr "" msgid "%s has no carrier: cable unplugged or switch port down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1116 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1117 msgid "%s hidden" msgstr "" @@ -216,7 +216,7 @@ msgstr "" msgid "%s is in no zone and accepts every connection" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1109 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1110 msgid "%s is narrower" msgstr "" @@ -224,7 +224,7 @@ msgstr "" msgid "%s is not up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1112 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1113 msgid "%s is wider" msgstr "" @@ -240,23 +240,23 @@ msgstr "" msgid "%s may open the router's admin" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1230 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1231 msgid "%s moved" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1106 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1107 msgid "%s moved down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1097 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1098 msgid "%s moved left" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1100 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1101 msgid "%s moved right" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1103 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1104 msgid "%s moved up" msgstr "" @@ -269,9 +269,9 @@ msgid "%s negotiated only %d Mbit/s; a cable pair or port may be faulty" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:79 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1772 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1795 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2770 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1773 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1796 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2783 msgid "%s of %s" msgstr "" @@ -279,7 +279,7 @@ msgstr "" msgid "%s of %s available (%s in use)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1543 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1544 msgid "%s of Wi-Fi traffic" msgstr "" @@ -296,15 +296,15 @@ msgstr "" msgid "%s of frames to the device fail; interference likely" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2768 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2781 msgid "%s over %d cores" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1857 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1858 msgid "%s radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1155 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1156 msgid "%s shown" msgstr "" @@ -320,7 +320,7 @@ msgstr "" msgid "%s used" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1803 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1804 msgid "%s used of %s" msgstr "" @@ -328,7 +328,7 @@ msgstr "" msgid "%s · %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2546 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2559 msgid "%s · channel %d · %d MHz" msgstr "" @@ -344,22 +344,22 @@ msgstr "" msgid "%s: no carrier" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2699 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2712 msgid "(configured %d dBm, limited by regulatory rules)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1490 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2387 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1491 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2400 msgid "(hidden)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1262 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1491 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2061 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1263 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1492 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2062 msgid "1 client" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2264 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2265 msgid "1 connected" msgstr "" @@ -367,7 +367,7 @@ msgstr "" msgid "1 older device (Wi-Fi 4 or earlier) slows airtime" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2053 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2054 msgid "1 radio" msgstr "" @@ -392,19 +392,19 @@ msgstr "" msgid "60 GHz" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2188 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2189 msgid "Active" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2571 msgid "Address type" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2735 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2748 msgid "Addresses" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2100 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2101 msgid "Airtime" msgstr "" @@ -412,7 +412,7 @@ msgstr "" msgid "Alias" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2184 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2185 msgid "All" msgstr "" @@ -448,13 +448,13 @@ msgstr "" msgid "B" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1568 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1569 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1570 msgid "Busiest network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1543 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1545 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1544 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1546 msgid "Busiest radio" msgstr "" @@ -462,7 +462,7 @@ msgstr "" msgid "Busiest radio: %s of Wi-Fi traffic" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1742 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1743 msgid "Busy share of each CPU core" msgstr "" @@ -476,8 +476,8 @@ msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:68 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:69 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1736 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2768 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1737 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2781 msgid "CPU" msgstr "" @@ -485,81 +485,81 @@ msgstr "" msgid "Cache (reclaimable)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2634 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2647 msgid "Cancel" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2541 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2554 msgid "Capabilities" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2730 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2743 msgid "Carrier" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2698 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2711 msgid "Centre frequency" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2092 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2093 msgid "Ch %d" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1473 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2060 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1474 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2061 msgid "Ch %d · %d MHz" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2691 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2704 msgid "Channel" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1473 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1474 msgid "Channel —" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2124 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2125 msgid "Clear filter" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1316 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317 msgid "Click any node for details" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:884 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1539 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2097 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2132 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1540 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2098 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2133 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2134 msgid "Clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2703 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2716 msgid "Clients on this radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2404 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2417 msgid "Close" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2323 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2324 msgid "Connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2285 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2286 msgid "Connected after you opened this page" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2547 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2560 msgid "Connected for" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2544 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2557 msgid "Connection" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1764 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1765 msgid "Core %d: %s" msgstr "" @@ -567,15 +567,15 @@ msgstr "" msgid "Could not read the firewall configuration" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2617 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2630 msgid "Could not save the name (no permission or the device refused it)." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2741 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2754 msgid "Counters since boot" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2701 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2714 msgid "Country" msgstr "" @@ -584,13 +584,13 @@ msgid "" "Custom rule files are configured (%s); rules in them are not listed here." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1251 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1252 msgid "Customize" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1061 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1062 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1250 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1063 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1251 msgid "Customize the dashboard" msgstr "" @@ -598,16 +598,16 @@ msgstr "" msgid "DHCP" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2572 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2585 msgid "DHCP hostname" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:42 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2739 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2752 msgid "DNS" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1430 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1431 msgid "DNS %s" msgstr "" @@ -616,84 +616,84 @@ msgid "Dashboard" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:268 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2290 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2759 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2291 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2772 msgid "Device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2601 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2614 msgid "Device name" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2630 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2643 msgid "Device type" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1474 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2062 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2087 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2696 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1475 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2063 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2709 msgid "Disabled" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2510 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2523 msgid "Disconnected %s; shown from the last sample." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1075 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1076 msgid "Done" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:45 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1474 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2062 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2087 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2696 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1475 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2063 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2709 msgid "Down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1922 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1995 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1837 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1923 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1996 msgid "Download" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:319 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:320 msgid "Download (to clients)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2552 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2565 msgid "Downloaded" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1136 -msgid "" -"Drag a tile by its handle or use its buttons. Saved in this browser for " -"medium screens." -msgstr "" - #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1137 msgid "" "Drag a tile by its handle or use its buttons. Saved in this browser for " +"medium screens." +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1138 +msgid "" +"Drag a tile by its handle or use its buttons. Saved in this browser for " "narrow screens." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1135 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1136 msgid "" "Drag a tile by its handle or use its buttons. Saved in this browser for wide " "screens." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1089 msgid "Drag to move" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2744 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2757 msgid "Dropped" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2367 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2380 msgid "Edit" msgstr "" @@ -710,8 +710,8 @@ msgstr "" msgid "Excellent" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2317 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318 msgid "Experience" msgstr "" @@ -728,15 +728,15 @@ msgstr "" msgid "Fair signal %s; lower rates at range" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2121 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2122 msgid "Filter by name, address, SSID…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2122 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2123 msgid "Filter clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2762 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2775 msgid "Firmware" msgstr "" @@ -748,7 +748,7 @@ msgstr "" msgid "Forwarding is accepted by default" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2554 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2567 msgid "Frames to device" msgstr "" @@ -756,15 +756,15 @@ msgstr "" msgid "Free" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2539 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2552 msgid "From device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2306 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2307 msgid "From device: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2725 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2738 msgid "From network" msgstr "" @@ -774,8 +774,8 @@ msgid "" "files are not shown." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1428 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2738 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1429 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2751 msgid "Gateway" msgstr "" @@ -787,7 +787,7 @@ msgstr "" msgid "General Settings" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2540 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2553 msgid "Generation" msgstr "" @@ -795,11 +795,11 @@ msgstr "" msgid "GiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2571 msgid "Globally unique" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2571 msgid "Globally unique · %s" msgstr "" @@ -820,32 +820,32 @@ msgstr "" msgid "Half duplex" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:781 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:782 msgid "Health checks" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1152 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2387 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1153 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2400 msgid "Hidden" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1115 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1116 msgid "Hide %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2559 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2572 msgid "IP addresses" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2736 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2749 msgid "IPv4" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2737 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 msgid "IPv6" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2556 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2569 msgid "Identity" msgstr "" @@ -861,19 +861,19 @@ msgstr "" msgid "Input" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1453 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1454 msgid "Interface" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2733 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2746 msgid "Interface up for" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2723 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2736 msgid "Interfaces" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1428 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1429 msgid "Internet" msgstr "" @@ -899,11 +899,11 @@ msgid "" "the router itself." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2763 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2776 msgid "Kernel" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1809 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1810 msgid "Kernel %s" msgstr "" @@ -911,40 +911,40 @@ msgstr "" msgid "KiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2548 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2561 msgid "Last activity" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1073 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1074 msgid "Layout reset" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2284 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2285 msgid "Left %s" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:159 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2286 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2287 msgid "Legacy" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2537 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2729 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2550 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2742 msgid "Link" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2305 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2306 msgid "Link rate" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1270 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2310 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1271 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2311 msgid "Live" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2767 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2780 msgid "Load" msgstr "" @@ -956,19 +956,19 @@ msgstr "" msgid "Load %s · %d cores" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2769 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2782 msgid "Load average" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1725 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1726 msgid "Load average over 1, 5 and 15 minutes" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1759 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1760 msgid "Load avg %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2765 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2778 msgid "Local time" msgstr "" @@ -984,7 +984,7 @@ msgstr "" msgid "MAC" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2557 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2570 msgid "MAC address" msgstr "" @@ -992,15 +992,15 @@ msgstr "" msgid "MCS %d" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1108 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1109 msgid "Make %s narrower" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1111 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1112 msgid "Make %s wider" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2574 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2587 msgid "Manufacturer of the network adapter" msgstr "" @@ -1017,11 +1017,11 @@ msgid "Measuring…" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:78 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1746 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1747 msgid "Memory" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2770 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2783 msgid "Memory in use" msgstr "" @@ -1029,62 +1029,62 @@ msgstr "" msgid "MiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1038 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1039 msgid "Mirrored" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1039 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1040 msgid "Mirrored, scale per direction" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2697 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2710 msgid "Mode" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2760 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2773 msgid "Model" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1105 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1106 msgid "Move %s down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1096 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1097 msgid "Move %s left" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1099 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1100 msgid "Move %s right" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1102 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1103 msgid "Move %s up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1089 msgid "Move %s: drag, or use the arrow keys" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2629 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2642 msgid "Name" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:134 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2669 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2682 msgid "Name contains invisible or control characters" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2560 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2573 msgid "Name from" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2295 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2296 msgid "Name from: %s" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:132 #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:137 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2670 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2683 msgid "Name is longer than %d characters" msgstr "" @@ -1092,23 +1092,23 @@ msgstr "" msgid "Name must be text" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2501 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2514 msgid "Name this device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2302 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2545 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2303 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558 msgid "Network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:884 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1315 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1316 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317 msgid "Network path" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1568 msgid "Networks" msgstr "" @@ -1116,12 +1116,12 @@ msgstr "" msgid "Networks: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2190 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2285 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2191 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2286 msgid "New" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1401 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1402 msgid "No SSIDs" msgstr "" @@ -1129,23 +1129,23 @@ msgstr "" msgid "No clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2269 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2270 msgid "No clients connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2340 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2355 msgid "No clients connected." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2272 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2273 msgid "No clients in this view" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2272 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2273 msgid "No clients match “%s”" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2708 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2721 msgid "No clients; an idle radio is fine." msgstr "" @@ -1153,7 +1153,7 @@ msgstr "" msgid "No clients; idle radios are fine" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1429 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1430 msgid "No default route" msgstr "" @@ -1161,7 +1161,7 @@ msgstr "" msgid "No interface with a route" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2715 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2728 msgid "No interface with a route is up." msgstr "" @@ -1170,7 +1170,7 @@ msgid "No internet-facing zone found" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2730 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2743 msgid "No link" msgstr "" @@ -1178,7 +1178,7 @@ msgstr "" msgid "No network interface with a route is up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1382 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1383 msgid "No other interfaces are up" msgstr "" @@ -1188,7 +1188,7 @@ msgid "No problems detected" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1405 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1406 msgid "No radios reported" msgstr "" @@ -1205,11 +1205,11 @@ msgstr "" msgid "No stations are associated right now" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2376 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2389 msgid "No wireless networks configured." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2067 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2068 msgid "No wireless radios are reported by this device." msgstr "" @@ -1228,19 +1228,19 @@ msgstr "" msgid "Nobody associated" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2340 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2355 msgid "Nobody is moving data right now." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2099 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2100 msgid "Noise" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2542 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2555 msgid "Noise / SNR" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2700 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2713 msgid "Noise floor" msgstr "" @@ -1253,11 +1253,11 @@ msgid "None" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:150 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2668 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2681 msgid "Not a station MAC address" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2483 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2496 msgid "Not connected" msgstr "" @@ -1265,15 +1265,15 @@ msgstr "" msgid "Not in effect" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1789 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1790 msgid "Not reported" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2577 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2590 msgid "Nothing better known" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2575 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2588 msgid "Nothing better known; the address is randomised" msgstr "" @@ -1293,7 +1293,7 @@ msgstr "" msgid "Older %s device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2286 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2287 msgid "Older Wi-Fi generation than the radio; uses more airtime" msgstr "" @@ -1301,7 +1301,7 @@ msgstr "" msgid "On this router" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 msgid "Online" msgstr "" @@ -1316,7 +1316,7 @@ msgstr[1] "" msgid "Open" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2247 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2248 msgid "Open details of %s" msgstr "" @@ -1342,11 +1342,11 @@ msgid "" "new rules: what is open is unknown." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1036 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1037 msgid "Overlaid" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1037 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1038 msgid "Overlaid, log scale" msgstr "" @@ -1354,11 +1354,11 @@ msgstr "" msgid "Overview" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2541 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2554 msgid "PMF" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1268 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1269 msgid "Paused while hidden" msgstr "" @@ -1372,7 +1372,7 @@ msgid "" "on to your network: what every router lets in." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2761 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2774 msgid "Platform" msgstr "" @@ -1384,7 +1384,7 @@ msgstr "" msgid "Private" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2571 msgid "Private Wi-Fi address (randomised by the device)" msgstr "" @@ -1392,24 +1392,24 @@ msgstr "" msgid "Private device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2758 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2771 msgid "Processes" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2732 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2745 msgid "Protocol" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2126 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2127 msgid "Quick filters" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2546 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2695 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2559 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2708 msgid "Radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2089 msgid "Radio details" msgstr "" @@ -1421,46 +1421,46 @@ msgstr "" msgid "Radio is enabled but not up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2111 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2689 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2112 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2702 msgid "Radio settings" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:884 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2040 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2042 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2041 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2043 msgid "Radios" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1430 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1431 msgid "Reachability not probed" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2723 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2736 msgid "Realtime graphs" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2742 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2755 msgid "Received" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1269 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1270 msgid "Reconnecting…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2635 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2648 msgid "Remove name" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2501 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2514 msgid "Rename" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1074 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1075 msgid "Reset" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2570 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2583 msgid "Reverse DNS of its address" msgstr "" @@ -1478,19 +1478,19 @@ msgid "" "to the addresses you use." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2627 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2640 msgid "Save" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2549 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2562 msgid "Seen since" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2743 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2756 msgid "Sent" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1040 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1041 msgid "Separate lanes" msgstr "" @@ -1498,45 +1498,45 @@ msgstr "" msgid "Settings to check" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1154 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1155 msgid "Show %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2273 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2274 msgid "Show all clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1733 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1734 msgid "Show or hide system details" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1316 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317 msgid "Show or hide the network path" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2043 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2044 msgid "Show or hide the radio details" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1839 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1840 msgid "Show or hide the throughput chart" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2367 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2380 msgid "Show or hide the wireless networks" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1489 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2383 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1490 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2396 msgid "Show the clients of %s" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:113 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:114 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2299 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2525 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2300 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2538 msgid "Signal" msgstr "" @@ -1544,7 +1544,7 @@ msgstr "" msgid "Signal not reported" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2731 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2744 msgid "Speed" msgstr "" @@ -1554,20 +1554,20 @@ msgid_plural "Standard housekeeping: %d rules" msgstr[0] "" msgstr[1] "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2270 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2271 msgid "Stations appear here as soon as they associate with one of the SSIDs." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2696 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2709 msgid "Status" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:88 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1749 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1750 msgid "Storage" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2636 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2649 msgid "Stored on this device in /etc/config/vantage" msgstr "" @@ -1583,7 +1583,7 @@ msgstr "" msgid "Strong signal, %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1794 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1795 msgid "Swap" msgstr "" @@ -1591,13 +1591,13 @@ msgstr "" msgid "Switched off" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1732 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:886 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1733 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1734 msgid "System" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2758 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2771 msgid "System settings" msgstr "" @@ -1616,11 +1616,11 @@ msgid "" "reject in General Settings." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2673 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2686 msgid "The device could not write /etc/config/vantage." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2099 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2100 msgid "" "The driver reports a placeholder value, so no noise floor or SNR is shown" msgstr "" @@ -1635,7 +1635,7 @@ msgid "" "an uplink in no zone would be open. Set Input to reject in General Settings." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2573 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2586 msgid "The name the device announces (WPS)" msgstr "" @@ -1651,7 +1651,7 @@ msgstr "" msgid "The uplinks could not be checked" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1438 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1439 msgid "This access point" msgstr "" @@ -1659,11 +1659,11 @@ msgstr "" msgid "This address family is in no zone: the default policies apply." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1438 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1439 msgid "This device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2672 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2685 msgid "This device already stores %d names; remove some first." msgstr "" @@ -1677,7 +1677,7 @@ msgid "" "the firewall pages." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2680 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2693 msgid "This radio is not reported any more." msgstr "" @@ -1685,22 +1685,22 @@ msgstr "" msgid "This setup is beyond what this overview checks" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2483 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2496 msgid "This station is not associated right now." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:884 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1831 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1833 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2531 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1832 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1834 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2544 msgid "Throughput" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1045 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1046 msgid "Throughput chart" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1824 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1825 msgid "Throughput per link; arrow keys read the values over time" msgstr "" @@ -1708,31 +1708,31 @@ msgstr "" msgid "TiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2538 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2551 msgid "To device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2314 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2355 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2315 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2368 msgid "To device %s, from device %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2306 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2307 msgid "To device: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2726 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2739 msgid "To network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2331 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:886 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2332 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2333 msgid "Top talkers" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2551 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2692 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2564 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2705 msgid "Traffic" msgstr "" @@ -1747,13 +1747,13 @@ msgid "" "networks. Set Forward to reject in General Settings." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1541 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1565 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1542 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566 msgid "Traffic now" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2098 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2699 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2099 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2712 msgid "Tx power" msgstr "" @@ -1763,15 +1763,15 @@ msgid "" "it runs, and those are not listed here." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2482 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2495 msgid "Unknown device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2671 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2684 msgid "Unknown device type" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2680 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2693 msgid "Unknown radio" msgstr "" @@ -1785,13 +1785,13 @@ msgid "Unnamed rule" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2087 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2696 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2730 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2709 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2743 msgid "Up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1756 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1757 msgid "Up %s" msgstr "" @@ -1800,34 +1800,34 @@ msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:49 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1856 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2715 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1857 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2728 msgid "Uplink" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1856 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1857 msgid "Uplink %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2719 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2732 msgid "Uplink · %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1837 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1924 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1996 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1838 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1925 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1997 msgid "Upload" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:320 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:321 msgid "Upload (from clients)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2553 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2566 msgid "Uploaded" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2764 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2777 msgid "Uptime" msgstr "" @@ -1953,7 +1953,7 @@ msgstr "" msgid "WPS" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2561 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2574 msgid "WPS device name" msgstr "" @@ -1966,7 +1966,7 @@ msgid "Weak" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:142 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2189 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2190 msgid "Weak signal" msgstr "" @@ -1974,8 +1974,8 @@ msgstr "" msgid "Weak signal %s; may roam poorly" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1546 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1548 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1547 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1549 msgid "Weakest signal" msgstr "" @@ -1992,17 +1992,17 @@ msgstr "" msgid "Wi-Fi" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2366 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2367 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:886 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2379 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2380 msgid "Wireless networks" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2511 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2524 msgid "Wireless settings" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2569 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2582 msgid "Your name for this device" msgstr "" @@ -2026,7 +2026,7 @@ msgstr "" msgid "all protocols" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1568 msgid "all up" msgstr "" @@ -2042,11 +2042,11 @@ msgstr "" msgid "any zone (default policy)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2093 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2094 msgid "auto" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2549 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2562 msgid "before this page opened" msgstr "" @@ -2054,16 +2054,16 @@ msgstr "" msgid "bit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1953 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1954 msgid "collecting · %s of data" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1953 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1954 msgid "collecting · first samples" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:216 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1933 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:217 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1934 msgid "collecting…" msgstr "" @@ -2079,7 +2079,7 @@ msgstr "" msgid "drop" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2601 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2614 msgid "e.g. Living room TV" msgstr "" @@ -2115,7 +2115,7 @@ msgstr "" msgid "half duplex" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2392 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2405 msgid "idle" msgstr "" @@ -2155,14 +2155,14 @@ msgstr "" msgid "kbit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1741 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1952 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1742 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1953 msgid "last 5 min" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:160 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:104 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2308 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2309 msgid "legacy" msgstr "" @@ -2170,65 +2170,65 @@ msgstr "" msgid "mDNS" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2571 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2584 msgid "mDNS announcement" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1541 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1565 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2533 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1542 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2546 msgid "measuring" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1928 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1929 msgid "measuring…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1545 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1546 msgid "no Wi-Fi traffic yet" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1548 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1549 msgid "no clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1912 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1913 msgid "no data" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1569 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1570 msgid "no traffic yet" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1436 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1437 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567 msgid "no uplink" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1539 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1540 msgid "none connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2559 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2572 msgid "not known to this AP" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2099 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2100 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2700 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2101 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2713 msgid "not reported" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2700 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2713 msgid "not reported (driver placeholder %s)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2542 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2555 msgid "not reported by the driver" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1949 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2548 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1950 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2561 msgid "now" msgstr "" @@ -2236,15 +2236,15 @@ msgstr "" msgid "now %s down, %s up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2540 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2553 msgid "older than the radio (%s)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1927 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1928 msgid "peak" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1742 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1743 msgid "per core" msgstr "" @@ -2252,11 +2252,11 @@ msgstr "" msgid "port forward" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2527 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2540 msgid "range %s … %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2725 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2738 msgid "received on %s" msgstr "" @@ -2268,7 +2268,7 @@ msgstr "" msgid "router port %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2726 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2739 msgid "sent on %s" msgstr "" @@ -2296,11 +2296,11 @@ msgstr "" msgid "traffic rule" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1441 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1442 msgid "up %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2332 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2333 msgid "who uses the bandwidth" msgstr "" @@ -2316,11 +2316,11 @@ msgstr "" msgid "zones %s and %s if they share a device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1541 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1565 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1542 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566 msgid "↑ %s · via %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1946 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1947 msgid "−%d min" msgstr "" diff --git a/luci-app-vantage/po/zh_Hans/vantage.po b/luci-app-vantage/po/zh_Hans/vantage.po index e72057788..5693350f1 100644 --- a/luci-app-vantage/po/zh_Hans/vantage.po +++ b/luci-app-vantage/po/zh_Hans/vantage.po @@ -12,7 +12,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2698 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2711 msgid "%d MHz (%d–%d MHz)" msgstr "%d MHz(%d–%d MHz)" @@ -32,23 +32,23 @@ msgstr "%d 个 SSID 正在广播" msgid "%d SSIDs · %d idle" msgstr "%d 个 SSID · %d 个空闲" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1262 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1491 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2061 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1263 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1492 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2062 msgid "%d clients" msgstr "%d 个客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2264 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2265 msgid "%d connected" msgstr "已连接 %d 个" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:101 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1568 msgid "%d down" msgstr "%d 个已关闭" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2742 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2743 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2755 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2756 msgid "%d errors" msgstr "%d 个错误" @@ -56,24 +56,24 @@ msgstr "%d 个错误" msgid "%d h ago" msgstr "%d 小时前" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2744 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2757 msgid "%d in · %d out" msgstr "%d 入 · %d 出" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:373 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:374 msgid "%d min" msgstr "%d 分" #: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:90 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:367 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:368 msgid "%d min ago" msgstr "%d 分钟前" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2264 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2265 msgid "%d of %d" msgstr "%d/%d" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1150 msgid "%d of %d columns" msgstr "" @@ -85,7 +85,7 @@ msgstr "%d 个关闭" msgid "%d older devices (Wi-Fi 4 or earlier) slow airtime" msgstr "%d 台旧设备(Wi-Fi 4 或更早)拖慢空口时间" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1534 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1535 msgid "%d on %s" msgstr "%d 个在 %s" @@ -93,20 +93,20 @@ msgstr "%d 个在 %s" msgid "%d on this router, %d into your network" msgstr "路由器上 %d 项,进入你的网络 %d 项" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2053 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2054 msgid "%d radios" msgstr "%d 个射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:373 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:374 msgid "%d s" msgstr "%d 秒" #: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:89 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:367 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:368 msgid "%d s ago" msgstr "%d 秒前" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2554 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2567 msgid "%d sent · %s retried · %s failed" msgstr "发送 %d · 重传 %s · 失败 %s" @@ -123,7 +123,7 @@ msgstr "%d 个已启用" msgid "%d weak" msgstr "%d 个信号弱" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2072 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2073 msgid "%d–%d MHz of the %d–%d MHz band" msgstr "%d–%d MHz 属于 %d–%d MHz 频段" @@ -141,7 +141,7 @@ msgstr "%s(%s)已启用但未上线" msgid "%s (IPv%d)" msgstr "%s(IPv%d)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2549 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2562 msgid "%s (new this session)" msgstr "%s(本次新增)" @@ -152,10 +152,10 @@ msgstr "%s Gbit/s" #: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:131 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:103 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2079 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2093 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2308 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2691 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2080 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2094 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2309 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2704 msgid "%s MHz" msgstr "%s MHz" @@ -169,7 +169,7 @@ msgstr "%s Mbit/s" msgid "%s accepts every connection" msgstr "%s 接受所有连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2548 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2561 msgid "%s ago" msgstr "%s 前" @@ -178,12 +178,12 @@ msgid "%s at %s; below %s roaming and throughput suffer" msgstr "%s(%s);低于 %s 时漫游和吞吐量会受影响" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:78 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1771 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1772 msgid "%s available" msgstr "可用 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2098 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2699 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2099 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2712 msgid "%s dBm" msgstr "%s dBm" @@ -195,7 +195,7 @@ msgstr "%s 设备" msgid "%s device on a newer radio; uses more airtime per byte" msgstr "%s 设备连接在较新的射频上,每字节占用更多空口时间" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2516 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2529 msgid "%s experience" msgstr "%s 体验" @@ -211,7 +211,7 @@ msgstr "overlay 空闲 %s(已用 %s)" msgid "%s has no carrier: cable unplugged or switch port down" msgstr "%s 无载波:网线未插或交换机端口关闭" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1116 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1117 msgid "%s hidden" msgstr "" @@ -227,7 +227,7 @@ msgstr "%s 被转发到 %s" msgid "%s is in no zone and accepts every connection" msgstr "%s 不属于任何区域,接受所有连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1109 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1110 msgid "%s is narrower" msgstr "" @@ -235,7 +235,7 @@ msgstr "" msgid "%s is not up" msgstr "%s 未上线" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1112 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1113 msgid "%s is wider" msgstr "" @@ -251,23 +251,23 @@ msgstr "%s 链路" msgid "%s may open the router's admin" msgstr "%s 可能开放了路由器管理" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1230 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1231 msgid "%s moved" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1106 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1107 msgid "%s moved down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1097 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1098 msgid "%s moved left" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1100 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1101 msgid "%s moved right" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1103 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1104 msgid "%s moved up" msgstr "" @@ -280,9 +280,9 @@ msgid "%s negotiated only %d Mbit/s; a cable pair or port may be faulty" msgstr "%s 仅协商到 %d Mbit/s;网线对线或端口可能故障" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:79 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1772 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1795 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2770 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1773 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1796 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2783 msgid "%s of %s" msgstr "%s / %s" @@ -290,7 +290,7 @@ msgstr "%s / %s" msgid "%s of %s available (%s in use)" msgstr "可用 %s / 共 %s(已用 %s)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1543 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1544 msgid "%s of Wi-Fi traffic" msgstr "占 Wi-Fi 流量的 %s" @@ -307,15 +307,15 @@ msgstr "发往设备的帧失败率:%s" msgid "%s of frames to the device fail; interference likely" msgstr "发往设备的帧失败率:%s,可能存在干扰" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2768 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2781 msgid "%s over %d cores" msgstr "%s / %d 核" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1857 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1858 msgid "%s radio" msgstr "%s 射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1155 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1156 msgid "%s shown" msgstr "" @@ -331,7 +331,7 @@ msgstr "%s 协商速率为 %s" msgid "%s used" msgstr "已用 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1803 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1804 msgid "%s used of %s" msgstr "已用 %s / 共 %s" @@ -339,7 +339,7 @@ msgstr "已用 %s / 共 %s" msgid "%s · %s" msgstr "%s · %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2546 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2559 msgid "%s · channel %d · %d MHz" msgstr "%s · 信道 %d · %d MHz" @@ -355,22 +355,22 @@ msgstr "%s · 链路较慢" msgid "%s: no carrier" msgstr "%s:无载波" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2699 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2712 msgid "(configured %d dBm, limited by regulatory rules)" msgstr "(配置 %d dBm,受监管规则限制)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1490 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2387 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1491 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2400 msgid "(hidden)" msgstr "(隐藏)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1262 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1491 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2061 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1263 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1492 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2062 msgid "1 client" msgstr "1 个客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2264 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2265 msgid "1 connected" msgstr "已连接 1 个" @@ -378,7 +378,7 @@ msgstr "已连接 1 个" msgid "1 older device (Wi-Fi 4 or earlier) slows airtime" msgstr "1 台旧设备(Wi-Fi 4 或更早)拖慢空口时间" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2053 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2054 msgid "1 radio" msgstr "1 个射频" @@ -403,19 +403,19 @@ msgstr "6 GHz" msgid "60 GHz" msgstr "60 GHz" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2188 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2189 msgid "Active" msgstr "活跃" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2571 msgid "Address type" msgstr "地址类型" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2735 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2748 msgid "Addresses" msgstr "地址" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2100 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2101 msgid "Airtime" msgstr "空口时间" @@ -423,7 +423,7 @@ msgstr "空口时间" msgid "Alias" msgstr "别名" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2184 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2185 msgid "All" msgstr "全部" @@ -459,13 +459,13 @@ msgstr "互联网上的任何主机都能访问路由器本身。请将此区域 msgid "B" msgstr "B" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1568 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1569 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1570 msgid "Busiest network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1543 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1545 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1544 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1546 msgid "Busiest radio" msgstr "最繁忙射频" @@ -473,7 +473,7 @@ msgstr "最繁忙射频" msgid "Busiest radio: %s of Wi-Fi traffic" msgstr "最繁忙射频:占 Wi-Fi 流量的 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1742 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1743 msgid "Busy share of each CPU core" msgstr "每个 CPU 核心的繁忙占比" @@ -487,8 +487,8 @@ msgstr "繁忙;负载 %s(%d 核);查看最繁忙进程" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:68 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:69 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1736 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2768 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1737 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2781 msgid "CPU" msgstr "CPU" @@ -496,81 +496,81 @@ msgstr "CPU" msgid "Cache (reclaimable)" msgstr "缓存(可回收)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2634 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2647 msgid "Cancel" msgstr "取消" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2541 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2554 msgid "Capabilities" msgstr "能力" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2730 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2743 msgid "Carrier" msgstr "链路状态" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2698 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2711 msgid "Centre frequency" msgstr "中心频率" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2092 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2093 msgid "Ch %d" msgstr "信道 %d" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1473 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2060 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1474 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2061 msgid "Ch %d · %d MHz" msgstr "信道 %d · %d MHz" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2691 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2704 msgid "Channel" msgstr "信道" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1473 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1474 msgid "Channel —" msgstr "信道 —" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2124 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2125 msgid "Clear filter" msgstr "清除筛选" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1316 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317 msgid "Click any node for details" msgstr "点击任意节点查看详情" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:884 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1539 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2097 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2132 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1540 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2098 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2133 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2134 msgid "Clients" msgstr "客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2703 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2716 msgid "Clients on this radio" msgstr "此射频上的客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2404 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2417 msgid "Close" msgstr "关闭" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2323 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2324 msgid "Connected" msgstr "已连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2285 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2286 msgid "Connected after you opened this page" msgstr "打开本页面后连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2547 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2560 msgid "Connected for" msgstr "已连接时长" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2544 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2557 msgid "Connection" msgstr "连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1764 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1765 msgid "Core %d: %s" msgstr "核心 %d:%s" @@ -578,15 +578,15 @@ msgstr "核心 %d:%s" msgid "Could not read the firewall configuration" msgstr "无法读取防火墙配置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2617 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2630 msgid "Could not save the name (no permission or the device refused it)." msgstr "无法保存名称(无权限或设备拒绝)。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2741 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2754 msgid "Counters since boot" msgstr "自启动以来的计数器" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2701 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2714 msgid "Country" msgstr "国家" @@ -595,13 +595,13 @@ msgid "" "Custom rule files are configured (%s); rules in them are not listed here." msgstr "已配置自定义规则文件(%s);其中的规则不会在此列出。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1251 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1252 msgid "Customize" msgstr "自定义" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1061 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1062 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1250 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1063 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1251 msgid "Customize the dashboard" msgstr "自定义仪表盘" @@ -609,16 +609,16 @@ msgstr "自定义仪表盘" msgid "DHCP" msgstr "DHCP" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2572 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2585 msgid "DHCP hostname" msgstr "DHCP 主机名" #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:42 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2739 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2752 msgid "DNS" msgstr "DNS" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1430 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1431 msgid "DNS %s" msgstr "DNS %s" @@ -627,84 +627,84 @@ msgid "Dashboard" msgstr "仪表盘" #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:268 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2290 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2759 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2291 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2772 msgid "Device" msgstr "设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2601 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2614 msgid "Device name" msgstr "设备名" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2630 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2643 msgid "Device type" msgstr "设备类型" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1474 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2062 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2087 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2696 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1475 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2063 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2709 msgid "Disabled" msgstr "已禁用" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2510 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2523 msgid "Disconnected %s; shown from the last sample." msgstr "断开于 %s;显示来自最后一次采样。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1075 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1076 msgid "Done" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:45 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1474 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2062 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2087 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2696 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1475 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2063 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2709 msgid "Down" msgstr "断开" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1922 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1995 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1837 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1923 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1996 msgid "Download" msgstr "下载" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:319 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:320 msgid "Download (to clients)" msgstr "下载(到客户端)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2552 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2565 msgid "Downloaded" msgstr "已下载" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1136 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1137 msgid "" "Drag a tile by its handle or use its buttons. Saved in this browser for " "medium screens." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1137 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1138 msgid "" "Drag a tile by its handle or use its buttons. Saved in this browser for " "narrow screens." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1135 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1136 msgid "" "Drag a tile by its handle or use its buttons. Saved in this browser for wide " "screens." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1089 msgid "Drag to move" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2744 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2757 msgid "Dropped" msgstr "已丢弃" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2367 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2380 msgid "Edit" msgstr "编辑" @@ -721,8 +721,8 @@ msgstr "一切看起来正常" msgid "Excellent" msgstr "极好" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2317 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318 msgid "Experience" msgstr "体验" @@ -739,15 +739,15 @@ msgstr "信号一般" msgid "Fair signal %s; lower rates at range" msgstr "信号一般 %s;远距离速率较低" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2121 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2122 msgid "Filter by name, address, SSID…" msgstr "按名称、地址、SSID…筛选" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2122 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2123 msgid "Filter clients" msgstr "筛选客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2762 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2775 msgid "Firmware" msgstr "固件" @@ -759,7 +759,7 @@ msgstr "从 %s 转发到 %s" msgid "Forwarding is accepted by default" msgstr "默认接受转发" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2554 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2567 msgid "Frames to device" msgstr "发往设备的帧" @@ -767,15 +767,15 @@ msgstr "发往设备的帧" msgid "Free" msgstr "空闲" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2539 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2552 msgid "From device" msgstr "来自设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2306 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2307 msgid "From device: %s" msgstr "来自设备:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2725 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2738 msgid "From network" msgstr "来自网络" @@ -785,8 +785,8 @@ msgid "" "files are not shown." msgstr "内容来自防火墙配置。由 UPnP 或自定义规则文件开放的端口不会显示。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1428 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2738 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1429 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2751 msgid "Gateway" msgstr "网关" @@ -798,7 +798,7 @@ msgstr "Gbit/s" msgid "General Settings" msgstr "基本设置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2540 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2553 msgid "Generation" msgstr "代际" @@ -806,11 +806,11 @@ msgstr "代际" msgid "GiB" msgstr "GiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2571 msgid "Globally unique" msgstr "全局唯一" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2571 msgid "Globally unique · %s" msgstr "全局唯一 · %s" @@ -831,32 +831,32 @@ msgstr "信号良好 %s" msgid "Half duplex" msgstr "半双工" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:781 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:782 msgid "Health checks" msgstr "健康检查" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1152 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2387 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1153 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2400 msgid "Hidden" msgstr "隐藏" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1115 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1116 msgid "Hide %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2559 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2572 msgid "IP addresses" msgstr "IP 地址" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2736 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2749 msgid "IPv4" msgstr "IPv4" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2737 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 msgid "IPv6" msgstr "IPv6" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2556 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2569 msgid "Identity" msgstr "身份" @@ -872,19 +872,19 @@ msgstr "使用中" msgid "Input" msgstr "入站数据" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1453 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1454 msgid "Interface" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2733 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2746 msgid "Interface up for" msgstr "接口已启用时长" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2723 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2736 msgid "Interfaces" msgstr "接口" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1428 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1429 msgid "Internet" msgstr "互联网" @@ -914,11 +914,11 @@ msgstr "" "它将来自互联网上任何地址的 SSH 或网页端口转发到 %s。无法读取接口列表,因此本" "页无法判断该地址是否为路由器本身。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2763 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2776 msgid "Kernel" msgstr "内核" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1809 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1810 msgid "Kernel %s" msgstr "内核 %s" @@ -926,40 +926,40 @@ msgstr "内核 %s" msgid "KiB" msgstr "KiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2548 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2561 msgid "Last activity" msgstr "最后活动" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1073 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1074 msgid "Layout reset" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2284 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2285 msgid "Left %s" msgstr "离开于 %s" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:159 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2286 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2287 msgid "Legacy" msgstr "旧版" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2537 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2729 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2550 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2742 msgid "Link" msgstr "链路" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2305 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2306 msgid "Link rate" msgstr "链路速率" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1270 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2310 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1271 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2311 msgid "Live" msgstr "实时" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2767 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2780 msgid "Load" msgstr "负载" @@ -971,19 +971,19 @@ msgstr "负载 %s(%d 核)" msgid "Load %s · %d cores" msgstr "负载 %s · %d 核" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2769 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2782 msgid "Load average" msgstr "平均负载" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1725 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1726 msgid "Load average over 1, 5 and 15 minutes" msgstr "1、5、15 分钟平均负载" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1759 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1760 msgid "Load avg %s" msgstr "平均负载 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2765 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2778 msgid "Local time" msgstr "本地时间" @@ -999,7 +999,7 @@ msgstr "相对其信号链路速率偏低" msgid "MAC" msgstr "MAC" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2557 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2570 msgid "MAC address" msgstr "MAC 地址" @@ -1007,15 +1007,15 @@ msgstr "MAC 地址" msgid "MCS %d" msgstr "MCS %d" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1108 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1109 msgid "Make %s narrower" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1111 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1112 msgid "Make %s wider" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2574 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2587 msgid "Manufacturer of the network adapter" msgstr "网卡制造商" @@ -1032,11 +1032,11 @@ msgid "Measuring…" msgstr "测量中…" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:78 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1746 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1747 msgid "Memory" msgstr "内存" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2770 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2783 msgid "Memory in use" msgstr "已用内存" @@ -1044,62 +1044,62 @@ msgstr "已用内存" msgid "MiB" msgstr "MiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1038 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1039 msgid "Mirrored" msgstr "镜像" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1039 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1040 msgid "Mirrored, scale per direction" msgstr "镜像,每个方向单独刻度" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2697 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2710 msgid "Mode" msgstr "模式" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2760 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2773 msgid "Model" msgstr "型号" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1105 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1106 msgid "Move %s down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1096 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1097 msgid "Move %s left" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1099 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1100 msgid "Move %s right" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1102 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1103 msgid "Move %s up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1089 msgid "Move %s: drag, or use the arrow keys" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2629 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2642 msgid "Name" msgstr "名称" #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:134 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2669 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2682 msgid "Name contains invisible or control characters" msgstr "名称包含不可见或控制字符" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2560 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2573 msgid "Name from" msgstr "名称来源" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2295 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2296 msgid "Name from: %s" msgstr "名称来源:%s" #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:132 #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:137 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2670 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2683 msgid "Name is longer than %d characters" msgstr "名称超过 %d 个字符" @@ -1107,23 +1107,23 @@ msgstr "名称超过 %d 个字符" msgid "Name must be text" msgstr "名称必须是文本" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2501 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2514 msgid "Name this device" msgstr "命名此设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2302 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2545 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2303 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558 msgid "Network" msgstr "网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:884 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1315 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1316 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317 msgid "Network path" msgstr "网络路径" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1568 msgid "Networks" msgstr "" @@ -1131,12 +1131,12 @@ msgstr "" msgid "Networks: %s" msgstr "网络:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2190 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2285 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2191 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2286 msgid "New" msgstr "新增" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1401 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1402 msgid "No SSIDs" msgstr "无 SSID" @@ -1144,23 +1144,23 @@ msgstr "无 SSID" msgid "No clients" msgstr "无客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2269 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2270 msgid "No clients connected" msgstr "无客户端连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2340 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2355 msgid "No clients connected." msgstr "没有客户端连接。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2272 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2273 msgid "No clients in this view" msgstr "此视图中没有客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2272 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2273 msgid "No clients match “%s”" msgstr "没有匹配“%s”的客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2708 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2721 msgid "No clients; an idle radio is fine." msgstr "无客户端;空闲的射频是正常的。" @@ -1168,7 +1168,7 @@ msgstr "无客户端;空闲的射频是正常的。" msgid "No clients; idle radios are fine" msgstr "无客户端;空闲的射频是正常的" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1429 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1430 msgid "No default route" msgstr "无默认路由" @@ -1176,7 +1176,7 @@ msgstr "无默认路由" msgid "No interface with a route" msgstr "无带路由的接口" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2715 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2728 msgid "No interface with a route is up." msgstr "没有带路由的接口处于启用状态。" @@ -1185,7 +1185,7 @@ msgid "No internet-facing zone found" msgstr "未找到面向互联网的区域" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2730 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2743 msgid "No link" msgstr "无链路" @@ -1193,7 +1193,7 @@ msgstr "无链路" msgid "No network interface with a route is up" msgstr "没有带路由的网络接口处于启用状态" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1382 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1383 msgid "No other interfaces are up" msgstr "" @@ -1203,7 +1203,7 @@ msgid "No problems detected" msgstr "未检测到问题" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1405 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1406 msgid "No radios reported" msgstr "未报告射频" @@ -1220,11 +1220,11 @@ msgstr "无信号" msgid "No stations are associated right now" msgstr "当前没有站点关联" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2376 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2389 msgid "No wireless networks configured." msgstr "未配置无线网络。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2067 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2068 msgid "No wireless radios are reported by this device." msgstr "此设备未报告任何无线射频。" @@ -1245,19 +1245,19 @@ msgstr "尚未配置区域。" msgid "Nobody associated" msgstr "无关联站点" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2340 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2355 msgid "Nobody is moving data right now." msgstr "当前没有设备在传输数据。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2099 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2100 msgid "Noise" msgstr "噪声" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2542 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2555 msgid "Noise / SNR" msgstr "噪声 / 信噪比" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2700 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2713 msgid "Noise floor" msgstr "噪声底" @@ -1270,11 +1270,11 @@ msgid "None" msgstr "无" #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:150 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2668 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2681 msgid "Not a station MAC address" msgstr "不是站点 MAC 地址" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2483 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2496 msgid "Not connected" msgstr "未连接" @@ -1282,15 +1282,15 @@ msgstr "未连接" msgid "Not in effect" msgstr "未生效" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1789 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1790 msgid "Not reported" msgstr "未报告" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2577 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2590 msgid "Nothing better known" msgstr "无更多信息" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2575 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2588 msgid "Nothing better known; the address is randomised" msgstr "无更多信息;地址已随机化" @@ -1310,7 +1310,7 @@ msgstr "OWE" msgid "Older %s device" msgstr "较旧的 %s 设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2286 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2287 msgid "Older Wi-Fi generation than the radio; uses more airtime" msgstr "比射频支持的 Wi-Fi 代际更旧;占用更多空口时间" @@ -1318,7 +1318,7 @@ msgstr "比射频支持的 Wi-Fi 代际更旧;占用更多空口时间" msgid "On this router" msgstr "在此路由器上" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 msgid "Online" msgstr "在线" @@ -1332,7 +1332,7 @@ msgstr[0] "只有标准的常规规则(ping、DHCP 续租等):%d 条" msgid "Open" msgstr "开放" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2247 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2248 msgid "Open details of %s" msgstr "打开 %s 的详情" @@ -1360,11 +1360,11 @@ msgstr "" "基本设置中的选项 %s 的值被 firewall4 拒绝,因此不会加载新规则:无法确定开放了" "哪些内容。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1036 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1037 msgid "Overlaid" msgstr "叠加" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1037 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1038 msgid "Overlaid, log scale" msgstr "叠加,对数刻度" @@ -1372,11 +1372,11 @@ msgstr "叠加,对数刻度" msgid "Overview" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2541 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2554 msgid "PMF" msgstr "PMF" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1268 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1269 msgid "Paused while hidden" msgstr "隐藏时暂停" @@ -1392,7 +1392,7 @@ msgstr "" "Ping 和其他控制消息、组播、DHCP 续租以及转发到你网络的 IPsec:每台路由器都会" "放行的流量。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2761 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2774 msgid "Platform" msgstr "平台" @@ -1404,7 +1404,7 @@ msgstr "较差" msgid "Private" msgstr "私有" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2571 msgid "Private Wi-Fi address (randomised by the device)" msgstr "私有 Wi-Fi 地址(设备随机化)" @@ -1412,24 +1412,24 @@ msgstr "私有 Wi-Fi 地址(设备随机化)" msgid "Private device" msgstr "私有设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2758 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2771 msgid "Processes" msgstr "进程" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2732 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2745 msgid "Protocol" msgstr "协议" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2126 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2127 msgid "Quick filters" msgstr "快速筛选" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2546 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2695 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2559 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2708 msgid "Radio" msgstr "射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2089 msgid "Radio details" msgstr "射频详情" @@ -1441,46 +1441,46 @@ msgstr "射频已禁用" msgid "Radio is enabled but not up" msgstr "射频已启用但未上线" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2111 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2689 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2112 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2702 msgid "Radio settings" msgstr "射频设置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:884 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2040 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2042 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2041 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2043 msgid "Radios" msgstr "射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1430 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1431 msgid "Reachability not probed" msgstr "未探测可达性" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2723 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2736 msgid "Realtime graphs" msgstr "实时图表" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2742 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2755 msgid "Received" msgstr "已接收" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1269 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1270 msgid "Reconnecting…" msgstr "重新连接中…" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2635 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2648 msgid "Remove name" msgstr "移除名称" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2501 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2514 msgid "Rename" msgstr "重命名" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1074 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1075 msgid "Reset" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2570 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2583 msgid "Reverse DNS of its address" msgstr "其地址的反向 DNS" @@ -1499,19 +1499,19 @@ msgid "" msgstr "" "SSH 或网页管理界面会响应互联网上的任何地址。请将此规则限制为你使用的地址。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2627 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2640 msgid "Save" msgstr "保存" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2549 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2562 msgid "Seen since" msgstr "首次出现" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2743 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2756 msgid "Sent" msgstr "已发送" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1040 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1041 msgid "Separate lanes" msgstr "分开显示" @@ -1519,45 +1519,45 @@ msgstr "分开显示" msgid "Settings to check" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1154 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1155 msgid "Show %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2273 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2274 msgid "Show all clients" msgstr "显示全部客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1733 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1734 msgid "Show or hide system details" msgstr "显示/隐藏系统详情" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1316 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317 msgid "Show or hide the network path" msgstr "显示/隐藏网络路径" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2043 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2044 msgid "Show or hide the radio details" msgstr "显示/隐藏射频详情" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1839 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1840 msgid "Show or hide the throughput chart" msgstr "显示/隐藏吞吐量图表" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2367 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2380 msgid "Show or hide the wireless networks" msgstr "显示/隐藏无线网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1489 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2383 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1490 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2396 msgid "Show the clients of %s" msgstr "显示 %s 的客户端" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:113 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:114 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2299 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2525 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2300 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2538 msgid "Signal" msgstr "信号强度" @@ -1565,7 +1565,7 @@ msgstr "信号强度" msgid "Signal not reported" msgstr "未报告信号" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2731 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2744 msgid "Speed" msgstr "速率" @@ -1574,20 +1574,20 @@ msgid "Standard housekeeping: %d rule" msgid_plural "Standard housekeeping: %d rules" msgstr[0] "标准常规规则:%d 条" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2270 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2271 msgid "Stations appear here as soon as they associate with one of the SSIDs." msgstr "站点一旦关联到任一 SSID 便会显示在这里。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2696 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2709 msgid "Status" msgstr "状态" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:88 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1749 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1750 msgid "Storage" msgstr "存储" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2636 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2649 msgid "Stored on this device in /etc/config/vantage" msgstr "保存在本设备 /etc/config/vantage 中" @@ -1603,7 +1603,7 @@ msgstr "信号强 %s,链路 %s" msgid "Strong signal, %s" msgstr "信号强,%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1794 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1795 msgid "Swap" msgstr "交换分区" @@ -1611,13 +1611,13 @@ msgstr "交换分区" msgid "Switched off" msgstr "已关闭" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1732 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:886 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1733 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1734 msgid "System" msgstr "系统" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2758 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2771 msgid "System settings" msgstr "系统设置" @@ -1638,11 +1638,11 @@ msgstr "" "该处适用默认入站数据策略且为接受,因此互联网上的任何主机都能访问路由器本身。" "请将其加入 wan 区域,或在基本设置中将入站数据设为拒绝。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2673 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2686 msgid "The device could not write /etc/config/vantage." msgstr "设备无法写入 /etc/config/vantage。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2099 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2100 msgid "" "The driver reports a placeholder value, so no noise floor or SNR is shown" msgstr "" @@ -1659,7 +1659,7 @@ msgstr "" "无法读取接口列表,且默认入站数据策略为接受:不属于任何区域的上行接口将会开" "放。请在基本设置中将入站数据设为拒绝。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2573 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2586 msgid "The name the device announces (WPS)" msgstr "设备广播的名称(WPS)" @@ -1675,7 +1675,7 @@ msgstr "保存的名称包含无效的节 ID" msgid "The uplinks could not be checked" msgstr "无法检查上行接口" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1438 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1439 msgid "This access point" msgstr "此接入点" @@ -1683,11 +1683,11 @@ msgstr "此接入点" msgid "This address family is in no zone: the default policies apply." msgstr "此地址族不属于任何区域:适用默认策略。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1438 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1439 msgid "This device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2672 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2685 msgid "This device already stores %d names; remove some first." msgstr "此设备已存储 %d 个名称;请先移除部分。" @@ -1701,7 +1701,7 @@ msgid "" "the firewall pages." msgstr "本页无法判断开放了哪些内容。请重新加载;如果仍无效,请检查防火墙页面。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2680 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2693 msgid "This radio is not reported any more." msgstr "此射频不再被报告。" @@ -1709,22 +1709,22 @@ msgstr "此射频不再被报告。" msgid "This setup is beyond what this overview checks" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2483 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2496 msgid "This station is not associated right now." msgstr "此站点当前未关联。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:884 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1831 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1833 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2531 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1832 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1834 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2544 msgid "Throughput" msgstr "吞吐量" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1045 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1046 msgid "Throughput chart" msgstr "吞吐量图表" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1824 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1825 msgid "Throughput per link; arrow keys read the values over time" msgstr "每条链路的吞吐量;方向键可查看历史值" @@ -1732,31 +1732,31 @@ msgstr "每条链路的吞吐量;方向键可查看历史值" msgid "TiB" msgstr "TiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2538 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2551 msgid "To device" msgstr "到设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2314 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2355 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2315 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2368 msgid "To device %s, from device %s" msgstr "到设备 %s,来自设备 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2306 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2307 msgid "To device: %s" msgstr "到设备:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2726 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2739 msgid "To network" msgstr "发往网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2331 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:886 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2332 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2333 msgid "Top talkers" msgstr "流量大户" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2551 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2692 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2564 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2705 msgid "Traffic" msgstr "流量" @@ -1773,13 +1773,13 @@ msgstr "" "未被任何转发覆盖的互联网流量仍会到达你的其他网络。请在基本设置中将转发设为拒" "绝。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1541 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1565 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1542 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566 msgid "Traffic now" msgstr "当前流量" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2098 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2699 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2099 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2712 msgid "Tx power" msgstr "发射功率" @@ -1790,15 +1790,15 @@ msgid "" msgstr "" "已安装 UPnP:它运行时,你网络中的设备可以自行开放端口,这些端口不会在此列出。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2482 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2495 msgid "Unknown device" msgstr "未知设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2671 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2684 msgid "Unknown device type" msgstr "未知设备类型" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2680 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2693 msgid "Unknown radio" msgstr "未知射频" @@ -1812,13 +1812,13 @@ msgid "Unnamed rule" msgstr "未命名的规则" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2087 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2696 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2730 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2709 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2743 msgid "Up" msgstr "正常" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1756 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1757 msgid "Up %s" msgstr "已运行 %s" @@ -1827,34 +1827,34 @@ msgstr "已运行 %s" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:49 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1856 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2715 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1857 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2728 msgid "Uplink" msgstr "上行链路" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1856 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1857 msgid "Uplink %s" msgstr "上行链路 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2719 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2732 msgid "Uplink · %s" msgstr "上行链路 · %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1837 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1924 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1996 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1838 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1925 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1997 msgid "Upload" msgstr "上传" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:320 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:321 msgid "Upload (from clients)" msgstr "上传(来自客户端)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2553 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2566 msgid "Uploaded" msgstr "已上传" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2764 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2777 msgid "Uptime" msgstr "运行时间" @@ -1980,7 +1980,7 @@ msgstr "WPA3 个人版" msgid "WPS" msgstr "WPS" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2561 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2574 msgid "WPS device name" msgstr "WPS 设备名称" @@ -1993,7 +1993,7 @@ msgid "Weak" msgstr "弱" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:142 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2189 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2190 msgid "Weak signal" msgstr "信号弱" @@ -2001,8 +2001,8 @@ msgstr "信号弱" msgid "Weak signal %s; may roam poorly" msgstr "信号弱 %s;漫游可能不佳" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1546 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1548 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1547 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1549 msgid "Weakest signal" msgstr "最弱信号" @@ -2019,17 +2019,17 @@ msgstr "" msgid "Wi-Fi" msgstr "Wi-Fi" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2366 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2367 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:886 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2379 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2380 msgid "Wireless networks" msgstr "无线网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2511 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2524 msgid "Wireless settings" msgstr "无线设置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2569 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2582 msgid "Your name for this device" msgstr "你为此设备设置的名称" @@ -2053,7 +2053,7 @@ msgstr "除 %s 以外的所有端口" msgid "all protocols" msgstr "所有协议" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1568 msgid "all up" msgstr "" @@ -2069,11 +2069,11 @@ msgstr "任意区域" msgid "any zone (default policy)" msgstr "任意区域(默认策略)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2093 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2094 msgid "auto" msgstr "自动" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2549 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2562 msgid "before this page opened" msgstr "打开本页之前" @@ -2081,16 +2081,16 @@ msgstr "打开本页之前" msgid "bit/s" msgstr "bit/s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1953 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1954 msgid "collecting · %s of data" msgstr "采集中 · 已采集 %s 数据" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1953 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1954 msgid "collecting · first samples" msgstr "采集中 · 首个样本" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:216 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1933 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:217 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1934 msgid "collecting…" msgstr "采集中…" @@ -2106,7 +2106,7 @@ msgstr "dBm" msgid "drop" msgstr "丢弃" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2601 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2614 msgid "e.g. Living room TV" msgstr "例如:客厅电视" @@ -2142,7 +2142,7 @@ msgstr "网关 %s" msgid "half duplex" msgstr "半双工" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2392 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2405 msgid "idle" msgstr "空闲" @@ -2182,14 +2182,14 @@ msgstr "刚刚" msgid "kbit/s" msgstr "kbit/s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1741 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1952 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1742 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1953 msgid "last 5 min" msgstr "最近 5 分钟" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:160 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:104 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2308 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2309 msgid "legacy" msgstr "旧版" @@ -2197,65 +2197,65 @@ msgstr "旧版" msgid "mDNS" msgstr "mDNS" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2571 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2584 msgid "mDNS announcement" msgstr "mDNS 广播" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1541 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1565 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2533 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1542 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2546 msgid "measuring" msgstr "测量中" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1928 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1929 msgid "measuring…" msgstr "测量中…" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1545 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1546 msgid "no Wi-Fi traffic yet" msgstr "尚无 Wi-Fi 流量" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1548 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1549 msgid "no clients" msgstr "无客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1912 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1913 msgid "no data" msgstr "无数据" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1569 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1570 msgid "no traffic yet" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1436 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1437 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567 msgid "no uplink" msgstr "无上行链路" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1539 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1540 msgid "none connected" msgstr "无连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2559 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2572 msgid "not known to this AP" msgstr "此 AP 未知" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2099 #: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2100 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2700 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2101 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2713 msgid "not reported" msgstr "未报告" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2700 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2713 msgid "not reported (driver placeholder %s)" msgstr "未报告(驱动占位 %s)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2542 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2555 msgid "not reported by the driver" msgstr "驱动未报告" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1949 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2548 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1950 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2561 msgid "now" msgstr "现在" @@ -2263,15 +2263,15 @@ msgstr "现在" msgid "now %s down, %s up" msgstr "当前下行 %s,上行 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2540 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2553 msgid "older than the radio (%s)" msgstr "比射频支持的标准更旧(%s)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1927 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1928 msgid "peak" msgstr "峰值" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1742 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1743 msgid "per core" msgstr "每核" @@ -2279,11 +2279,11 @@ msgstr "每核" msgid "port forward" msgstr "端口转发" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2527 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2540 msgid "range %s … %s" msgstr "范围 %s … %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2725 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2738 msgid "received on %s" msgstr "在 %s 上接收" @@ -2295,7 +2295,7 @@ msgstr "拒绝" msgid "router port %s" msgstr "路由器端口 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2726 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2739 msgid "sent on %s" msgstr "在 %s 上发送" @@ -2323,11 +2323,11 @@ msgstr "此路由器" msgid "traffic rule" msgstr "通信规则" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1441 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1442 msgid "up %s" msgstr "已运行 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2332 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2333 msgid "who uses the bandwidth" msgstr "带宽使用者" @@ -2343,12 +2343,12 @@ msgstr "区域转发" msgid "zones %s and %s if they share a device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1541 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1565 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1542 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566 msgid "↑ %s · via %s" msgstr "↑ %s · 经 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1946 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1947 msgid "−%d min" msgstr "−%d 分钟" diff --git a/luci-theme-vantage/Makefile b/luci-theme-vantage/Makefile index 41c4f17ec..7212a28f9 100644 --- a/luci-theme-vantage/Makefile +++ b/luci-theme-vantage/Makefile @@ -11,7 +11,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-theme-vantage PKG_VERSION:=1.0.8 -PKG_RELEASE:=19 +PKG_RELEASE:=20 PKG_LICENSE:=GPL-3.0-or-later LUCI_TITLE:=Vantage theme diff --git a/luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js b/luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js index e7483414c..48d6b1c12 100644 --- a/luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js +++ b/luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js @@ -588,6 +588,14 @@ function setupCharts() { if (/^admin-status-channel_analysis/.test(page) && window.MutationObserver) setupChannelAnalysis(); } +/* Status -> Firewall: the ruleset as a flow chart (vantage-theme.nftflow, + loaded on that page only) */ +function setupNftFlow() { + const view = document.getElementById('view'); + if (!view || !window.MutationObserver || document.body.getAttribute('data-page') !== 'admin-status-nftables') return; + L.require('vantage-theme.nftflow').then((m) => m.attach(view)).catch((e) => { if (window.console) console.warn('vantage: firewall flow', e); }); +} + return baseclass.extend({ __init__() { this.root = document.documentElement; @@ -605,6 +613,7 @@ return baseclass.extend({ this.setupTooltips(); setupStockEnhancers(); setupCharts(); + setupNftFlow(); this.setupKeys(); this.loadHost(); diff --git a/luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js b/luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js new file mode 100644 index 000000000..6f774c997 --- /dev/null +++ b/luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js @@ -0,0 +1,480 @@ +'use strict'; +'require baseclass'; +'require fs'; +'require vantage-theme.nftmodel as nftmodel'; + +/* + * Vantage theme - Status -> Firewall as a flow chart. + * + * LuCI's view lists every chain as a table of rules. On top of it this + * draws (a Flow / Rules table switch picks one): + * - one chart of the way a packet goes: in through prerouting, then + * either input, this device and output, or forward, and out through + * postrouting; each stage names its chains and says whether it drops + * unmatched packets; ingress, bridge and egress hooks sit where a packet + * meets them; a second row for frames bridged between ports; + * - every base chain as a list of steps: the rule's name (fw4's comment), + * its conditions and what it does; a jump opens the chain it jumps to + * in place, so a packet's whole way reads top to bottom. + * The ruleset comes from the command LuCI's page runs (same ACL). The + * conditions are LuCI's own rendering of each rule, copied as text and a + * few formatting tags; LuCI read the ruleset separately, so a chain whose + * rows don't match its rules (a reload in between) shows no conditions. + * Rules as in menu-vantage.js: E() with array content only, LuCI's nodes + * stay where they are (hidden by a class in Flow mode). + * ------------------------------------------------------------------------ */ + +const MODE_KEY = 'vantage.nft.mode'; +const MAX_DEPTH = 8; +const MAX_STEPS = 200; /* rules drawn per chain before "Show all" */ +const CTX = 'Status -> Firewall flow chart'; + +function storageGet(k) { try { return localStorage.getItem(k); } catch (e) { return null; } } +function storageSet(k, v) { try { localStorage.setItem(k, v); } catch (e) {} } +function reducedMotion() { return !!(window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches); } + +function hookName(h) { + switch (h) { + case 'prerouting': return _('Prerouting', CTX); + case 'input': return _('Input', CTX); + case 'forward': return _('Forward', CTX); + case 'output': return _('Output', CTX); + case 'postrouting': return _('Postrouting', CTX); + case 'ingress': return _('Ingress', CTX); + case 'egress': return _('Egress', CTX); + default: return h; + } +} + +function stageName(s) { + switch (s.hook) { + case 'bridgeIn': case 'bridgeOut': return _('Bridge', CTX); + case 'bridged': return _('Bridged between ports', CTX); + default: return hookName(s.hook); + } +} + +function familyName(f) { + return f === 'ip' ? 'IPv4' : f === 'ip6' ? 'IPv6' : f === 'inet' ? 'IPv4/IPv6' : f; +} + +/* LuCI's table headings, so they read as in the Rules table */ +function tableTitle(t) { + switch (t.family) { + case 'ip': return _('IPv4 traffic table "%h"').format(t.name); + case 'ip6': return _('IPv6 traffic table "%h"').format(t.name); + case 'inet': return _('IPv4/IPv6 traffic table "%h"').format(t.name); + case 'arp': return _('ARP traffic table "%h"').format(t.name); + case 'bridge': return _('Bridge traffic table "%h"').format(t.name); + case 'netdev': return _('Network device table "%h"').format(t.name); + default: return _('"%h" table "%h"', 'Yet unknown nftables table family ("family" table "name")').format(t.family, t.name); + } +} + +/* LuCI's rows per chain key, in the ruleset's order: tables, chains and + rules are rendered in JSON order, one row per rule. A chain's rows are + used only when they agree with its rules: same count, same comments, + same jump targets (LuCI read the ruleset on its own; a reload between + the two reads must not pair a rule with another rule's conditions). */ +function luciRows(root, m) { + const out = Object.create(null); + const tables = root.querySelectorAll(':scope > .nft-table'); + m.tables.forEach((t, i) => { + const box = tables[i]; + if (!box) return; + const cards = box.querySelectorAll('.nft-chain'); + t.chains.forEach((k, j) => { + const c = m.chains[k], card = cards[j], h = card && card.querySelector(':scope > h4'); + if (!h || h.id !== t.name + '.' + c.name) return; + const rows = Array.prototype.filter.call(card.querySelectorAll('.nft-rules .tr'), (tr) => !tr.classList.contains('table-titles')); + if (rows.length === c.rules.length && c.rules.every((r, n) => agrees(r, rows[n]))) + out[k] = rows; + }); + }); + return out; +} + +function agrees(r, tr) { + const tip = tr.querySelector('.nft-comment .cbi-tooltip'); + if (!!tip !== !!r.comment || (tip && tip.textContent.indexOf(r.comment) < 0)) return false; + const v = r.verdict, want = v.target ? [ v.target ] : (v.map || []).filter((e) => e.target).map((e) => e.target); + const have = Array.prototype.map.call(tr.querySelectorAll('a[href^="#"]'), (a) => a.getAttribute('href').replace(/^#[^.]*\./, '')); + return want.every((t) => have.indexOf(t) >= 0); +} + +/* a copy of LuCI's rendering as text and its formatting tags only: no + attribute but class (LuCI's tooltips take data-tooltip as markup, so it + stays behind), nothing that loads or runs */ +function copyOf(node) { + if (node.nodeType === 3) return document.createTextNode(node.data); + if (node.nodeType !== 1) return null; + const kids = []; + node.childNodes.forEach((n) => { const c = copyOf(n); if (c) kids.push(c); }); + const cls = node.getAttribute('class') || ''; + switch (node.tagName) { + case 'VAR': return E('var', { 'class': cls }, kids); + case 'STRONG': return E('strong', { 'class': cls }, kids); + case 'EM': return E('em', { 'class': cls }, kids); + case 'B': return E('b', { 'class': cls }, kids); + case 'I': return E('i', { 'class': cls }, kids); + case 'SMALL': return E('small', { 'class': cls }, kids); + case 'DIV': return E('div', { 'class': cls }, kids); + case 'BR': return E('br', { 'class': cls }, []); + default: return E('span', { 'class': cls }, kids); + } +} + +/* a rule's conditions as LuCI shows them, without its comment and counter; + vmap: the verdict chips say it all where LuCI can only show a placeholder + (LuCI 24.10: "{ vmap }", its fallback for an expression it can't read) */ +function conditions(tr, vmap) { + const td = tr && tr.firstElementChild; + if (!td) return null; + const keep = Array.prototype.filter.call(td.childNodes, (n) => !(n.nodeType === 1 && n.matches('.nft-comment, .nft-counter')) + && !(vmap && n.nodeType === 1 && n.matches('.ifacebadge[data-tooltip]') && /^\{\s*vmap\s*\}$/.test(n.textContent.trim()))); + const c = E('div', { 'class': 'v-nft-cond' }, keep.map(copyOf).filter(Boolean)); + return c.textContent.trim() ? c : null; +} + +/* the actions LuCI shows besides the deciding one (log, a helper, a mark); + for NAT the deciding one too: it holds the address and port */ +function sideActions(tr, parts, nat) { + const td = tr && tr.children[1]; + if (!td || td.children.length !== parts.acts) return null; + const keep = Array.prototype.filter.call(td.children, (n, i) => nat || i !== parts.last).map(copyOf).filter(Boolean); + return keep.length ? E('div', { 'class': 'v-nft-cond v-nft-also' }, keep) : null; +} + +function chip(kind, label, title) { + const el = E('span', { 'class': 'v-nft-verdict', 'data-kind': kind }, [ label ]); + if (title) el.setAttribute('title', title); + return el; +} + +function verdictLabel(v) { + switch (v.kind) { + case 'accept': return _('Accept', CTX); + case 'drop': return _('Drop', CTX); + case 'reject': return _('Reject', CTX); + case 'queue': return _('Queue to a program', CTX); + case 'nat': + return v.nat === 'masquerade' ? _('Masquerade', CTX) : v.nat === 'snat' ? _('Rewrite source', CTX) + : v.nat === 'dnat' ? _('Rewrite destination', CTX) : _('Redirect', CTX); + default: return _('Next rule', CTX); + } +} + +/* a chain with something to show: rules, or a policy that drops */ +function live(c) { return c.rules.length > 0 || (c.base && c.policy === 'drop'); } + +return baseclass.extend({ + attach(view) { + const ready = () => { + const t = view.querySelector('.nft-table'); + return t && t.parentNode; + }; + const go = (root) => { + L.resolveDefault(fs.exec_direct('/usr/sbin/nft', [ '--terse', '--json', 'list', 'ruleset' ], 'json'), null).then((json) => { + if (!json || root.querySelector(':scope > .v-nft')) return; + const m = nftmodel.build(json); + if (!m.bases.length && !m.others.length) return; + this.draw(root, m); + }).catch((e) => { if (window.console) console.warn('vantage: firewall flow', e); }); + }; + const root = ready(); + if (root) return go(root); + /* wait for LuCI's tables; give up once the view shows something + else ("No nftables ruleset loaded.") or after a minute */ + const done = () => { mo.disconnect(); window.clearTimeout(timer); }; + const mo = new MutationObserver(() => { + const r = ready(); + if (r) { done(); go(r); } + else if (!view.querySelector('.spinning') && view.textContent.trim()) done(); + }); + const timer = window.setTimeout(done, 60000); + mo.observe(view, { childList: true, subtree: true }); + }, + + draw(root, m) { + this.m = m; + this.rows = luciRows(root, m); + this.ids = Object.create(null); + Object.keys(m.chains).forEach((k, i) => { this.ids[k] = 'v-nft-c' + i; }); + this.cards = Object.create(null); + + const tabs = E('ul', { 'class': 'cbi-tabmenu v-nft-tabs', 'role': 'group', 'aria-label': _('View', CTX) }); + const panel = E('div', { 'class': 'v-nft-panel' }, [ + E('h3', {}, [ _('Packet path', CTX) ]), + this.chart(), + E('h3', {}, [ _('Chains', CTX) ]), + E('div', { 'class': 'v-nft-chains' }, this.cardsOf(m.bases)) + ]); + m.others.forEach((t) => { + panel.appendChild(E('h3', {}, [ tableTitle(t) ])); + panel.appendChild(E('div', { 'class': 'v-nft-chains' }, this.cardsOf(t.chains))); + }); + if (m.unused.length) { + panel.appendChild(E('h3', {}, [ m.namedMaps ? _('Chains no rule jumps to directly', CTX) : _('Chains no rule jumps to', CTX) ])); + panel.appendChild(E('div', { 'class': 'v-nft-chains' }, this.cardsOf(m.unused, true))); + } + + const box = E('div', { 'class': 'v-nft' }, [ tabs, panel ]); + const set = (mode) => { + root.classList.toggle('v-nft-flowmode', mode === 'flow'); + Array.prototype.forEach.call(tabs.children, (li) => { + const on = li.getAttribute('data-mode') === mode; + li.className = on ? 'cbi-tab' : 'cbi-tab-disabled'; + li.firstElementChild.setAttribute('aria-pressed', String(on)); + }); + if (mode === 'flow') this.fit(); + }; + /* LuCI's tab markup for the look; buttons for what they do */ + [ [ 'flow', _('Flow', CTX) ], [ 'table', _('Rules table', CTX) ] ].forEach((t) => { + const pick = (ev) => { ev.preventDefault(); storageSet(MODE_KEY, t[0]); set(t[0]); }; + tabs.appendChild(E('li', { 'data-mode': t[0], 'role': 'presentation' }, [ + E('a', { 'href': '#', 'role': 'button', 'click': pick, + 'keydown': (ev) => { if (ev.key === ' ' || ev.key === 'Spacebar') pick(ev); } }, [ t[1] ]) + ])); + }); + root.insertBefore(box, root.firstChild); + set(storageGet(MODE_KEY) === 'table' ? 'table' : 'flow'); + if (window.ResizeObserver) new ResizeObserver(() => this.fit()).observe(this.el); + }, + + /* the way through the hooks: in, a fork (to this device and back out, + or forwarded), out; below it the way of frames bridged between ports */ + chart() { + const st = this.m.stages; + const arrow = () => E('span', { 'class': 'v-nft-arrow', 'aria-hidden': 'true' }); + const pass = () => E('span', { 'class': 'v-nft-pass', 'aria-hidden': 'true' }); + const end = (where) => E('span', { 'class': 'v-nft-endpoint', 'data-where': where }, [ where === 'device' ? _('This device', CTX) : _('Network', CTX) ]); + const row = [ end('net') ]; + [ st.ingress, st.bridgeIn, st.prerouting ].filter(Boolean).forEach((s) => { row.push(arrow(), this.stage(s)); }); + row.push(arrow(), E('div', { 'class': 'v-nft-fork' }, [ + E('div', { 'class': 'v-nft-branch' }, [ this.stage(st.input), arrow(), end('device'), arrow(), this.stage(st.output), pass() ]), + E('div', { 'class': 'v-nft-branch' }, [ this.stage(st.forward), pass() ]) + ]), arrow(), this.stage(st.postrouting)); + [ st.bridgeOut, st.egress ].filter(Boolean).forEach((s) => { row.push(arrow(), this.stage(s)); }); + row.push(arrow(), end('net')); + + const bridged = [ end('net') ]; + [ st.ingress, st.bridged, st.egress ].filter(Boolean).forEach((s) => { bridged.push(arrow(), this.stage(s)); }); + bridged.push(pass(), arrow(), end('net')); + + const notes = []; + if (!st.bridged.chains.length) + notes.push(E('p', { 'class': 'v-nft-note' }, [ _('Frames bridged between ports of one bridge, such as Wi-Fi and LAN in br-lan on an access point, never reach the input, forward or output chains, and no bridge chain filters them here. (The kernel can hand them to the IP chains if br_netfilter is enabled; the ruleset doesn\'t show that.)', CTX) ])); + if (this.m.offload) + notes.push(E('p', { 'class': 'v-nft-note' }, [ _('Flow offloading is on: once a forwarded connection is established, its packets can skip prerouting, forward and postrouting, so these chains and their counters see only its first packets.', CTX) ])); + + this.el = E('div', { 'class': 'v-nft-chart' }, [ + E('div', { 'class': 'v-nft-chart-row' }, row), + E('div', { 'class': 'v-nft-chart-row' }, bridged) + ].concat(notes)); + return this.el; + }, + + /* the chart runs across while it fits, else down (again only when + its width changed: switching changes the height alone) */ + fit() { + const el = this.el; + if (!el || !el.offsetWidth || el.offsetWidth === this.fitW) return; + this.fitW = el.offsetWidth; + el.classList.remove('v-nft-vertical'); + const wide = Array.prototype.some.call(el.querySelectorAll(':scope > .v-nft-chart-row'), (r) => r.scrollWidth > r.clientWidth + 1); + el.classList.toggle('v-nft-vertical', wide); + }, + + /* a stage: its name, whether it drops, its chains with something to show */ + stage(s) { + const m = this.m, list = s.chains.filter((k) => live(m.chains[k])); + const none = s.hook === 'bridged' && !s.chains.length; + const name = [ stageName(s) ]; + if (s.drops === 'all') + name.push(E('small', {}, [ s.only ? _('drops unmatched %s', CTX).format(familyName(s.only)) : _('drops unmatched', CTX) ])); + else if (s.drops === 'some') + name.push(E('small', {}, [ _('rules drop some', CTX) ])); + else if (none) + name.push(E('small', {}, [ _('no bridge chains', CTX) ])); + /* a name twice at one hook (docker, mwan3): say whose */ + const seen = Object.create(null); + s.chains.forEach((k) => { seen[m.chains[k].name] = (seen[m.chains[k].name] || 0) + 1; }); + return E('div', { 'class': 'v-nft-stage', 'data-drops': none ? 'open' : s.drops, 'data-edge': String(nftmodel.HOOKS.indexOf(s.hook) < 0) }, [ + E('div', { 'class': 'v-nft-stage-name' }, name), + E('div', { 'class': 'v-nft-stage-chains' }, list.length ? list.map((k) => { + const c = m.chains[k]; + const b = E('button', { 'type': 'button', 'class': 'v-nft-link', 'click': () => this.show(k), + 'title': _('%s: table %s (%s), priority %d', CTX).format(c.name, c.table, familyName(c.family), c.prio) }, [ c.name ]); + if (seen[c.name] > 1 || (nftmodel.HOOKS.indexOf(s.hook) < 0 && c.family !== 'netdev' && c.family !== 'bridge')) + b.appendChild(E('small', {}, [ c.table + ' · ' + familyName(c.family) ])); + else if (c.type === 'nat') + b.appendChild(E('small', {}, [ _('NAT', CTX) ])); + return b; + }) : none ? [] : [ E('span', { 'class': 'v-nft-none' }, [ _('no rules', CTX) ]) ]) + ]); + }, + + /* open a chain's card and bring it into view */ + show(k) { + const card = this.cards[k]; + if (!card) return; + card.open = true; + card.scrollIntoView({ block: 'start', behavior: reducedMotion() ? 'auto' : 'smooth' }); + const s = card.querySelector('summary'); + if (s) s.focus({ preventScroll: true }); + }, + + /* a card per chain with something to show; the empty ones on one line */ + cardsOf(keys, regular) { + const c = (k) => this.m.chains[k]; + const out = keys.filter((k) => regular ? c(k).rules.length : live(c(k))).map((k) => this.card(k)); + const empty = keys.filter((k) => regular ? !c(k).rules.length : !live(c(k))); + if (empty.length) + out.push(E('p', { 'class': 'v-nft-empty' }, [ _('No rules: %s', CTX).format(empty.map((k) => c(k).name).join(', ')) ])); + return out; + }, + + card(k) { + const m = this.m, c = m.chains[k]; + const meta = []; + if (c.base) { + meta.push(hookName(c.hook), _('priority %d', CTX).format(c.prio)); + if (c.family !== 'inet') meta.push(familyName(c.family)); + if (c.type === 'nat') meta.push(_('NAT', CTX)); + if (c.dev.length) meta.push(_('on %s', CTX).format(c.dev.join(', '))); + } + meta.push(N_(c.rules.length, '%d rule', '%d rules').format(c.rules.length)); + /* other chains at the same hook (and family group) still see what + this one accepts */ + if (c.base) { + const group = (f) => f === 'bridge' ? 'bridge' : f === 'netdev' ? 'netdev' : 'ip'; + const more = Object.keys(m.chains).filter((o) => o !== k && m.chains[o].base && m.chains[o].hook === c.hook + && group(m.chains[o].family) === group(c.family) && live(m.chains[o])).length; + if (more) meta.push(N_(more, '%d more chain at this hook', '%d more chains at this hook').format(more)); + } + const card = E('details', { 'class': 'v-nft-card', 'id': this.ids[k], 'data-chain': c.name, 'data-family': c.family }, [ + E('summary', {}, [ E('strong', {}, [ c.name ]), E('span', { 'class': 'v-nft-meta' }, [ meta.join(' · ') ]) ].concat(c.base ? [ this.policyChip(c) ] : [])) + ]); + /* the chains that drop what no rule accepts start open */ + card.open = c.base && c.policy === 'drop'; + let built = false; + const fill = () => { if (!built && card.open) { built = true; card.appendChild(this.flow(k, [ k ], [])); } }; + card.addEventListener('toggle', fill); + fill(); + this.cards[k] = card; + return card; + }, + + policyChip(c) { + if (c.policy === 'drop') return chip('drop', _('Drops unmatched', CTX)); + if (c.type === 'filter') return chip('accept', _('Passes unmatched', CTX)); + return chip('none', _('Leaves unmatched unchanged', CTX)); + }, + + /* where a packet goes when it leaves the chain without a verdict: + back to the chain that last jumped (a goto doesn't come back), or, + with none, the base chain's policy */ + away(path, stack) { + const up = stack.length ? this.m.chains[stack[stack.length - 1]] : null; + if (up) return chip('return', _('Back to %s', CTX).format(up.name)); + const b = this.m.chains[path[0]]; + if (!b.base) return chip('return', _('Back to the calling chain', CTX)); + if (b.policy === 'drop') return chip('drop', _('Drop: %s policy', CTX).format(b.name)); + if (b.type === 'filter') return chip('accept', _('Pass: %s policy', CTX).format(b.name)); + return chip('none', _('Unchanged', CTX)); + }, + + /* a chain's rules as steps. path: the chains opened above it (to stop + at a loop); stack: the chains to come back to (a jump adds its + chain, a goto doesn't) */ + flow(k, path, stack) { + const c = this.m.chains[k], rows = this.rows[k]; + const list = E('ol', { 'class': 'v-nft-flow' }); + const step = (r) => { + const row = rows && rows[r.index]; + const cond = r.parts.conds && row ? conditions(row, r.verdict.kind === 'vmap') : null; + const nat = r.verdict.kind === 'nat'; + const also = row && r.verdict.kind !== 'vmap' && (nat || r.parts.acts > (r.parts.last >= 0 ? 1 : 0)) ? sideActions(row, r.parts, nat) : null; + /* a rule with conditions LuCI's rows can't supply never reads + as "Any packet" */ + const label = r.comment || (cond ? '' : r.parts.conds ? _('Conditions in the rules table', CTX) : _('Any packet', 'nft match any traffic')); + const what = [ E('div', { 'class': 'v-nft-what-name', 'data-muted': String(!r.comment && !cond && !!r.parts.conds) }, [ label ]) ]; + if (!r.comment && cond) what[0] = cond; + else if (cond) what.push(cond); + if (also) what.push(also); + const then = this.outcome(r.verdict, c, path, stack); + if (r.counter) + then.push(E('span', { 'class': 'v-nft-count', 'title': _('Traffic matched by rule: %.1000mPackets, %.1024mBytes', 'nft counter').format(r.counter.packets, r.counter.bytes) }, + [ _('%s matched', CTX).format('%.1024mB'.format(r.counter.bytes)) ])); + return E('li', { 'class': 'v-nft-step' }, [ + E('span', { 'class': 'v-nft-n' }, [ String(r.index + 1) ]), + E('div', { 'class': 'v-nft-what' }, what), + E('div', { 'class': 'v-nft-then' }, then) + ]); + }; + c.rules.slice(0, MAX_STEPS).forEach((r) => list.appendChild(step(r))); + if (c.rules.length > MAX_STEPS) { + const more = E('li', { 'class': 'v-nft-step v-nft-step-more' }, [ + E('span', { 'class': 'v-nft-n', 'aria-hidden': 'true' }), + E('button', { 'type': 'button', 'class': 'v-nft-verdict v-nft-jump', 'click': () => { + c.rules.slice(MAX_STEPS).forEach((r) => list.insertBefore(step(r), more)); + more.remove(); + } }, [ N_(c.rules.length - MAX_STEPS, 'Show %d more rule', 'Show %d more rules').format(c.rules.length - MAX_STEPS) ]) + ]); + list.appendChild(more); + } + list.appendChild(this.end(path, stack)); + return list; + }, + + /* what a rule does: a verdict, or the chain it jumps to (opens below) */ + outcome(v, c, path, stack) { + const jump = (kind, target, key) => { + const tk = nftmodel.keyOf(c.family, c.table, target); + const label = (key != null ? key + ' → ' : '→ ') + target; + if (!this.m.chains[tk]) return chip(kind, label); + if (path.indexOf(tk) >= 0) return chip(kind, label + ' ' + _('(open above)', CTX)); + if (path.length >= MAX_DEPTH) return chip(kind, label + ' ' + _('(too deep to open here)', CTX)); + const b = E('button', { 'type': 'button', 'class': 'v-nft-verdict v-nft-jump', 'data-kind': kind, 'aria-expanded': 'false', + 'title': kind === 'goto' ? _('Continues in %s and does not come back here', CTX).format(target) : _('Continues in %s, then comes back here', CTX).format(target) }, [ label ]); + let sub = null; + b.addEventListener('click', () => { + if (!sub) { + const back = kind === 'jump' ? stack.concat([ c.key ]) : stack; + sub = E('div', { 'class': 'v-nft-sub' }, [ this.flow(tk, path.concat([ tk ]), back) ]); + b.closest('.v-nft-step').appendChild(sub); + } + const open = b.getAttribute('aria-expanded') !== 'true'; + sub.hidden = !open; + b.setAttribute('aria-expanded', String(open)); + }); + return b; + }; + if (v.kind === 'return') return [ this.away(path, stack) ]; + if (v.kind === 'jump' || v.kind === 'goto') return [ jump(v.kind, v.target) ]; + if (v.kind === 'vmap' && v.named) return [ chip('none', _('Verdict map %s', CTX).format(v.named)) ]; + if (v.kind === 'vmap') { + /* keys with the same verdict share a chip: "established, related → Accept" */ + const out = [], same = Object.create(null); + v.map.forEach((e) => { + if (e.kind === 'jump' || e.kind === 'goto') return out.push(jump(e.kind, e.target, e.key)); + const kind = e.kind === 'return' ? 'return' : e.kind; + if (same[kind]) return same[kind].push(e.key); + same[kind] = [ e.key ]; + out.push(kind); + }); + return out.map((x) => typeof x !== 'string' ? x + : chip(x === 'return' ? 'return' : x, same[x].join(', ') + ' → ' + (x === 'return' ? this.away(path, stack).textContent : verdictLabel({ kind: x })))); + } + return [ chip(v.kind, verdictLabel(v)) ]; + }, + + /* where a packet goes when no rule of the chain decided */ + end(path, stack) { + return E('li', { 'class': 'v-nft-step v-nft-step-end' }, [ + E('span', { 'class': 'v-nft-n', 'aria-hidden': 'true' }), + E('div', { 'class': 'v-nft-what' }, [ _('No rule matched', CTX) ]), + E('div', { 'class': 'v-nft-then' }, [ this.away(path, stack) ]) + ]); + } +}); diff --git a/luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftmodel.js b/luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftmodel.js new file mode 100644 index 000000000..1f28da5c6 --- /dev/null +++ b/luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftmodel.js @@ -0,0 +1,255 @@ +'use strict'; +'require baseclass'; + +/* + * Vantage theme - the live nftables ruleset as a model for the flow view + * on Status -> Firewall (vantage-theme.nftflow draws it). + * + * Input: the JSON of `nft --terse --json list ruleset`, the command LuCI's + * own page runs. Output: tables, chains with their rules and what each + * rule finally does, and the stages a packet passes (the IP hooks, and + * the ingress, bridge and egress hooks around them) with their base + * chains in priority order. Pure functions, no DOM, unit tested in + * tests/nftflow.test.js. + */ + +/* the IP families share the hooks; other families get their own list */ +const IP = { ip: true, ip6: true, inet: true }; +const HOOKS = [ 'prerouting', 'input', 'forward', 'output', 'postrouting' ]; +/* every hook in the order a packet can meet it, to sort other families */ +const ORDER = [ 'ingress', 'prerouting', 'input', 'forward', 'output', 'postrouting', 'egress' ]; +/* where a packet meets the other hooks: ingress first (netdev, and inet + since Linux 5.10) and netdev egress last, on their device; bridge hooks + on a bridge port, prerouting and input before the IP stack, output and + postrouting after it; prerouting, forward and postrouting for frames + bridged from port to port, which never reach the IP hooks (unless the + kernel's br_netfilter hands them over, which the ruleset doesn't show) */ +const EDGES = { + ingress: [ [ 'netdev', 'inet', 'ip', 'ip6' ], [ 'ingress' ] ], + bridgeIn: [ [ 'bridge' ], [ 'prerouting', 'input' ] ], + bridgeOut: [ [ 'bridge' ], [ 'output', 'postrouting' ] ], + egress: [ [ 'netdev' ], [ 'egress' ] ], + bridged: [ [ 'bridge' ], [ 'prerouting', 'forward', 'postrouting' ] ] +}; + +/* statements that end the rule (the last one wins); everything else + (counter, limit, log, mangle, ct helper, notrack, flow) lets the packet + go on to the next rule */ +const NAT = { masquerade: true, snat: true, dnat: true, redirect: true }; + +/* what LuCI's view counts as an action (its isActionExpression); it shows + every other statement but a counter among the rule's conditions */ +const ACTIONS = [ 'accept', 'notrack', 'reject', 'drop', 'jump', 'goto', 'continue', 'snat', 'dnat', + 'redirect', 'mangle', 'masquerade', 'return', 'flow', 'ct helper', 'log' ]; +/* nft prints "flow add @ft" as a bare string */ +const FLOW_ADD = /^flow add @\S+$/; + +function own(o, k) { return o != null && Object.prototype.hasOwnProperty.call(o, k); } +function str(v) { return typeof v === 'string' ? v : ''; } +function num(v) { return typeof v === 'number' && isFinite(v) ? v : null; } +function obj(v) { return v != null && typeof v === 'object'; } + +function isAction(st) { + if (typeof st === 'string') return FLOW_ADD.test(st); + return obj(st) && ACTIONS.some((k) => own(st, k)); +} + +/* names can't hold a newline: no two chains share a key */ +function keyOf(family, table, name) { return family + '\n' + table + '\n' + name; } + +/* a verdict object ({ accept: null }, { jump: { target } }, ...) */ +function verdict(v) { + if (!obj(v)) return null; + if (own(v, 'accept')) return { kind: 'accept' }; + if (own(v, 'drop')) return { kind: 'drop' }; + if (own(v, 'reject')) return { kind: 'reject' }; + if (own(v, 'return')) return { kind: 'return' }; + if (own(v, 'continue')) return { kind: 'continue' }; + if (own(v, 'queue')) return { kind: 'queue' }; + for (const k of [ 'jump', 'goto' ]) + if (own(v, k) && v[k] && str(v[k].target)) return { kind: k, target: v[k].target }; + return null; +} + +/* a map key as text: strings and numbers; prefixes and ranges roughly */ +function keyText(k) { + if (typeof k === 'string' || typeof k === 'number') return String(k); + if (obj(k)) { + if (own(k, 'prefix') && k.prefix) return str(k.prefix.addr) + '/' + String(num(k.prefix.len) != null ? k.prefix.len : ''); + if (Array.isArray(k.range)) return k.range.map(keyText).join('-'); + if (Array.isArray(k.concat)) return k.concat.map(keyText).join(' . '); + } + return '…'; +} + +const DROPS = { drop: true, reject: true }; + +return baseclass.extend({ + HOOKS: HOOKS, + + keyOf: keyOf, + + /* fw4 marks its own comments with "!fw4: " */ + comment(c) { return str(c).replace(/^!fw4:\s*/, '').trim(); }, + + /* what a rule's statements finally do: + { kind: accept|drop|reject|return|continue|queue|jump|goto|nat|vmap|none, + target (jump, goto), nat (its statement), map (vmap: [{ key, kind, + target }]), named (a vmap looked up in a named map: its name) } */ + ruleVerdict(expr) { + let out = { kind: 'none' }; + (Array.isArray(expr) ? expr : []).forEach((st) => { + if (!obj(st)) return; + const v = verdict(st); + if (v) { out = v; return; } + for (const k in NAT) if (own(st, k)) { out = { kind: 'nat', nat: k }; return; } + if (!own(st, 'vmap') || !st.vmap) return; + const data = st.vmap.data; + if (typeof data === 'string') { out = { kind: 'vmap', map: [], named: data.replace(/^@/, '') }; return; } + const map = []; + (data && Array.isArray(data.set) ? data.set : []).forEach((e) => { + const d = Array.isArray(e) ? verdict(e[1]) : null; + if (d) map.push({ key: keyText(e[0]), kind: d.kind, target: d.target }); + }); + out = { kind: 'vmap', map: map }; + }); + return out; + }, + + /* matched packets and bytes, when the rule counts */ + counter(expr) { + const c = (Array.isArray(expr) ? expr : []).find((st) => obj(st) && own(st, 'counter') && st.counter); + return c && num(c.counter.packets) != null ? { packets: c.counter.packets, bytes: num(c.counter.bytes) || 0 } : null; + }, + + /* how LuCI's view splits the statements: { conds, acts, last }; conds: + statements it shows as conditions (all but counters and actions, the + vmap's lookup included), acts: the actions in order, last: the index + among them of the one that decides (-1: none does) */ + parts(expr) { + const out = { conds: 0, acts: 0, last: -1 }; + (Array.isArray(expr) ? expr : []).forEach((st) => { + if (obj(st) && own(st, 'counter')) return; + if (obj(st) && own(st, 'vmap')) { out.conds++; return; } + if (!isAction(st)) { out.conds++; return; } + if (verdict(st) || Object.keys(NAT).some((k) => own(st, k))) out.last = out.acts; + out.acts++; + }); + return out; + }, + + build(json) { + const items = json && Array.isArray(json.nftables) ? json.nftables : []; + const tables = [], chains = Object.create(null), byTable = Object.create(null); + let offload = false; + + items.forEach((it) => { + if (obj(it) && obj(it.flowtable)) offload = true; + const t = it && it.table; + if (!obj(t) || !str(t.family) || !str(t.name)) return; + const tk = keyOf(t.family, t.name, ''); + if (byTable[tk]) return; + byTable[tk] = { family: t.family, name: t.name, chains: [] }; + tables.push(byTable[tk]); + }); + items.forEach((it) => { + const c = it && it.chain; + if (!obj(c) || !str(c.family) || !str(c.table) || !str(c.name)) return; + const k = keyOf(c.family, c.table, c.name); + if (chains[k]) return; + const base = str(c.hook) !== ''; + const dev = Array.isArray(c.dev) ? c.dev.filter((d) => typeof d === 'string') : str(c.dev) ? [ c.dev ] : []; + chains[k] = { + key: k, family: c.family, table: c.table, name: c.name, + type: str(c.type), hook: str(c.hook), prio: num(c.prio) || 0, + policy: base ? (str(c.policy) || 'accept') : '', base: base, dev: dev, + rules: [], callers: [] + }; + const tk = keyOf(c.family, c.table, ''); + if (!byTable[tk]) { byTable[tk] = { family: c.family, name: c.table, chains: [] }; tables.push(byTable[tk]); } + byTable[tk].chains.push(k); + }); + items.forEach((it) => { + const r = it && it.rule; + if (!obj(r) || !str(r.family) || !str(r.table) || !str(r.chain)) return; + const c = chains[keyOf(r.family, r.table, r.chain)]; + if (!c) return; + const expr = Array.isArray(r.expr) ? r.expr : []; + if (expr.some((st) => (typeof st === 'string' && FLOW_ADD.test(st)) || (obj(st) && own(st, 'flow')))) + offload = true; + c.rules.push({ + index: c.rules.length, + comment: this.comment(r.comment), + verdict: this.ruleVerdict(expr), + counter: this.counter(expr), + parts: this.parts(expr) + }); + }); + + /* who jumps where: targets live in the caller's table */ + const targets = (c, r) => (r.verdict.target ? [ r.verdict.target ] : (r.verdict.map || []).map((e) => e.target)) + .map((t) => t && chains[keyOf(c.family, c.table, t)]).filter(Boolean); + Object.keys(chains).forEach((k) => { + const c = chains[k]; + c.rules.forEach((r) => { + targets(c, r).forEach((to) => { if (to.callers.indexOf(k) < 0) to.callers.push(k); }); + }); + }); + + /* whether a rule of the chain, or of a chain it jumps or goes to, + drops or rejects: fw4 keeps most of its filtering in zone chains */ + const memo = new Map(); + const mayDrop = (k, seen) => { + if (memo.has(k)) return memo.get(k); + if (seen.has(k)) return false; + seen.add(k); + const c = chains[k]; + const out = c.rules.some((r) => DROPS[r.verdict.kind] || (r.verdict.map || []).some((e) => DROPS[e.kind]) + || targets(c, r).some((to) => mayDrop(to.key, seen))); + memo.set(k, out); + return out; + }; + Object.keys(chains).forEach((k) => { chains[k].mayDrop = mayDrop(k, new Set()); }); + + const byPrio = (a, b) => chains[a].prio - chains[b].prio || (chains[a].name < chains[b].name ? -1 : chains[a].name > chains[b].name ? 1 : 0); + const byHook = (a, b) => ORDER.indexOf(chains[a].hook) - ORDER.indexOf(chains[b].hook) || byPrio(a, b); + const of = (families, hooks) => Object.keys(chains).filter((k) => families.indexOf(chains[k].family) >= 0 && hooks.indexOf(chains[k].hook) >= 0).sort(byHook); + const stage = (hook, list) => { + /* unmatched packets: a filter chain that drops them stops them + here (for its family only); otherwise a rule may drop some */ + const droppers = list.filter((k) => chains[k].type === 'filter' && chains[k].policy === 'drop'); + const fams = droppers.map((k) => chains[k].family); + return { + hook: hook, chains: list, + drops: droppers.length ? 'all' : list.some((k) => chains[k].mayDrop) ? 'some' : 'none', + /* 'ip' or 'ip6' when only that family's chains drop unmatched */ + only: droppers.length && fams.indexOf('inet') < 0 && fams.every((f) => f === fams[0]) && fams[0] !== 'bridge' && fams[0] !== 'netdev' ? fams[0] : '' + }; + }; + + /* the IP hooks always; the others only where they have chains, but + for the bridged path, which the chart always shows: without a + bridge chain nothing in the ruleset filters it */ + const stages = {}; + HOOKS.forEach((h) => { stages[h] = stage(h, of([ 'ip', 'ip6', 'inet' ], [ h ])); }); + Object.keys(EDGES).forEach((id) => { + const list = of(EDGES[id][0], EDGES[id][1]); + stages[id] = list.length || id === 'bridged' ? stage(id, list) : null; + }); + + /* the IP base chains in the order a packet meets them */ + const bases = of([ 'ip', 'ip6', 'inet' ], ORDER); + + /* other families (bridge, netdev, arp): their tables' base chains */ + const others = tables.filter((t) => !IP[t.family]) + .map((t) => ({ family: t.family, name: t.name, chains: t.chains.filter((k) => chains[k].base).sort(byHook) })) + .filter((t) => t.chains.length); + + /* regular chains no rule jumps to (a named verdict map may still: + its contents aren't in the terse ruleset) */ + const unused = Object.keys(chains).filter((k) => !chains[k].base && !chains[k].callers.length); + const namedMaps = Object.keys(chains).some((k) => chains[k].rules.some((r) => r.verdict.named)); + + return { tables: tables, chains: chains, stages: stages, bases: bases, others: others, unused: unused, namedMaps: namedMaps, offload: offload }; + } +}); diff --git a/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css b/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css index 49aa043da..1f5425436 100644 --- a/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css +++ b/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css @@ -175,6 +175,7 @@ html[data-darkmode="true"] { --v-r-lg: var(--r-lg); --v-ctl-h: var(--ctl-h); /* every control: 36px, 44px on touch */ --v-shadow: 0 1px 2px rgba(20, 23, 26, .06), 0 1px 0 rgba(20, 23, 26, .03); + --v-shadow-pop: var(--shadow-pop); /* lists and menus that open over the page */ /* where sticky content may start: below the top bar (page tabs scroll) */ --v-stick-top: var(--stick-top); @@ -2613,6 +2614,196 @@ select[id^="widget.cbid.firewall."] > option { color: var(--text); font-weight: .nft-rules .td > div > span:first-child:not(.ifacebadge) { margin-right: 6px; color: var(--text-3); } .nft-rules em { font-style: normal; color: var(--text-3); } +/* Status -> Firewall as a flow chart (vantage-theme/nftflow.js): a Flow / + Rules table switch over LuCI's view; Flow hides LuCI's tables (they stay + in the DOM). The chart: one row, in -> prerouting -> a fork (input, this + device, output | forward) -> postrouting -> out, the fork drawn as a + bracket each side, and a row for frames bridged between ports; a + stage's top edge is red where unmatched packets are dropped, amber where + some rules drop, grey on the bridged path when no bridge chain filters + it; ingress, bridge and egress stages dashed. When a row doesn't fit, + the script sets .v-nft-vertical: the rows run down and the fork's + branches stand side by side. Lines and arrows in --text-3 (they carry + the direction). The chains: a card each (details), its rules as + numbered steps on a rail, the verdict on the right; a jump opens its + chain beneath. */ +.v-nft-flowmode > .nft-table { display: none; } +:not(.v-nft-flowmode) > .v-nft > .v-nft-panel { display: none; } +.v-nft-panel > h3 { margin: var(--sp-5) 0 var(--sp-3); font-size: var(--fs-md); } +.v-nft-panel > h3:first-child { margin-top: 0; } +.v-nft-chains { display: grid; gap: var(--sp-2); } +.v-nft-chart, .v-nft-card { + background: var(--s1); + border: 1px solid var(--line); + border-radius: var(--r-lg); + box-shadow: var(--v-shadow); +} +.v-nft-chart { display: grid; gap: var(--sp-3); padding: 14px var(--card-px); } +.v-nft-chart-row { display: flex; align-items: center; min-width: 0; } +.v-nft-chart-row + .v-nft-chart-row { padding-top: var(--sp-3); border-top: 1px dashed var(--line); } +.v-nft-note { max-width: 90ch; margin: 0; color: var(--text-2); font-size: var(--fs-sm); } +.v-nft-endpoint { + flex: none; + padding: 4px 10px; + border-radius: 999px; + background: var(--s3); color: var(--text-2); + font-size: var(--fs-sm); font-weight: 600; white-space: nowrap; +} +.v-nft-endpoint[data-where="device"] { background: var(--accent-soft); color: var(--accent-text); } +.v-nft-arrow { position: relative; flex: 0 0 18px; height: 2px; margin-right: 6px; background: var(--text-3); } +.v-nft-arrow::after { + content: ""; position: absolute; right: -6px; top: -4px; + border: 5px solid transparent; border-left: 6px solid var(--text-3); border-right: 0; +} +/* a line that carries a branch on to the bracket */ +.v-nft-pass { flex: 1 0 12px; height: 2px; background: var(--text-3); } +.v-nft-stage { + flex: none; max-width: 210px; + padding: 6px 10px 8px; + background: var(--s2); + border: 1px solid var(--line); border-top: 3px solid var(--ok); + border-radius: var(--r); +} +.v-nft-stage[data-drops="all"] { border-top-color: var(--err); } +.v-nft-stage[data-drops="some"] { border-top-color: var(--warn); } +.v-nft-stage[data-drops="open"] { border-top-color: var(--line-2); } +.v-nft-stage[data-edge="true"] { border-style: dashed; border-top-style: solid; border-color: var(--line-2); } +.v-nft-stage[data-edge="true"][data-drops="all"] { border-top-color: var(--err); } +.v-nft-stage[data-edge="true"][data-drops="some"] { border-top-color: var(--warn); } +.v-nft-stage[data-edge="true"][data-drops="none"] { border-top-color: var(--ok); } +.v-nft-stage-name { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 6px; margin-bottom: 5px; font-size: var(--fs-sm); font-weight: 600; white-space: nowrap; } +.v-nft-stage-name small { font-size: var(--fs-micro); font-weight: 500; } +.v-nft-stage[data-drops="all"] .v-nft-stage-name small { color: var(--err-text); } +.v-nft-stage[data-drops="some"] .v-nft-stage-name small { color: var(--warn-text); } +.v-nft-stage[data-drops="open"] .v-nft-stage-name small { color: var(--text-2); } +.v-nft-stage-chains { display: flex; flex-wrap: wrap; gap: 4px; min-width: 0; } +.v-nft-none { color: var(--text-3); font-size: var(--fs-micro); } +.v-nft-link { + display: inline-flex; align-items: center; flex-wrap: wrap; gap: 0 4px; + min-height: 22px; max-width: 100%; margin: 0; padding: 1px 7px; + background: var(--s1); color: var(--text); + border: 1px solid var(--line-2); border-radius: var(--r-sm); + box-shadow: none; cursor: pointer; + font: 500 var(--fs-micro)/1.3 var(--mono); text-transform: none; text-align: left; + overflow-wrap: anywhere; +} +.v-nft-link:hover { border-color: var(--text-3); } +.v-nft-link small { color: var(--text-3); font: 600 var(--fs-micro)/1.3 var(--font); letter-spacing: .02em; } +/* the fork: two branches between brackets; each branch reaches both. The + brackets run between the centres of the two branches' lines */ +.v-nft-fork { position: relative; display: grid; grid-auto-rows: 1fr; gap: 10px; flex: 1 1 auto; } +.v-nft-fork::before, .v-nft-fork::after { content: ""; position: absolute; top: calc(25% - 3.5px); bottom: calc(25% - 3.5px); width: 2px; background: var(--text-3); } +.v-nft-fork::before { left: -6px; } +.v-nft-fork::after { right: 0; } +.v-nft-branch { display: flex; align-items: center; min-width: 0; } +.v-nft-branch::before { content: ""; flex: 0 0 8px; height: 2px; margin-left: -6px; background: var(--text-3); } +.v-nft-branch > .v-nft-pass:last-child { margin-right: 0; } +.v-nft-vertical .v-nft-chart-row { flex-direction: column; align-items: stretch; } +.v-nft-vertical .v-nft-endpoint { align-self: center; } +.v-nft-vertical .v-nft-arrow { flex-basis: 16px; width: 2px; height: auto; margin: 0 auto 6px; } +.v-nft-vertical .v-nft-arrow::after { right: -4px; top: auto; bottom: -6px; border: 5px solid transparent; border-top: 6px solid var(--text-3); border-bottom: 0; } +/* one line a stage: its name, then its chains */ +.v-nft-vertical .v-nft-stage { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; max-width: none; padding: 5px 10px 6px; } +.v-nft-vertical .v-nft-stage-name { margin: 0; } +.v-nft-vertical .v-nft-fork { grid-auto-rows: auto; grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 2px 0 0; } +.v-nft-vertical .v-nft-fork::before, .v-nft-vertical .v-nft-fork::after { left: calc(25% - 3.5px); right: calc(25% - 3.5px); width: auto; height: 2px; } +.v-nft-vertical .v-nft-fork::before { top: 0; bottom: auto; } +.v-nft-vertical .v-nft-fork::after { top: auto; bottom: 0; } +.v-nft-vertical .v-nft-branch { flex-direction: column; align-items: stretch; } +.v-nft-vertical .v-nft-branch::before { flex: 0 0 10px; width: 2px; height: auto; margin: 0 auto; } +.v-nft-vertical :is(.v-nft-pass, .v-nft-branch > .v-nft-pass:last-child) { flex: 1 0 10px; width: 2px; height: auto; margin: 0 auto; } + +.v-nft-card > summary { + display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; + min-height: 44px; padding: 8px var(--card-px); + list-style: none; cursor: pointer; + border-radius: var(--r-lg); +} +.v-nft-card > summary::-webkit-details-marker { display: none; } +.v-nft-card > summary::before { + content: ""; flex: none; width: 7px; height: 7px; margin: 0 4px 2px 0; + border-right: 2px solid var(--text-3); border-bottom: 2px solid var(--text-3); + transform: rotate(-45deg); transition: transform .15s; +} +.v-nft-card[open] > summary::before { transform: rotate(45deg); margin-bottom: 4px; } +.v-nft-card[open] > summary { border-bottom: 1px solid var(--line); border-radius: var(--r-lg) var(--r-lg) 0 0; } +.v-nft-card > summary > strong { font: 600 var(--fs-base) var(--mono); } +.v-nft-card > summary > .v-nft-verdict:last-child { margin-left: auto; } +.v-nft-meta { color: var(--text-3); font-size: var(--fs-sm); } + +.v-nft-flow { position: relative; margin: 0; padding: 4px var(--card-px) 6px; list-style: none; } +/* the rail through the step numbers */ +.v-nft-flow::before { content: ""; position: absolute; left: calc(var(--card-px) + 9px); top: 16px; bottom: 16px; width: 2px; background: var(--line); } +.v-nft-step { + position: relative; + display: grid; grid-template-columns: 20px minmax(0, 1fr) auto; align-items: start; gap: 2px 12px; + padding: 6px 0; +} +.v-nft-step + .v-nft-step { border-top: 1px solid var(--line); } +.v-nft-n { + position: relative; z-index: 1; + width: 20px; height: 20px; + border-radius: 50%; + background: var(--s3); color: var(--text-2); box-shadow: 0 0 0 3px var(--s1); + font: 600 var(--fs-micro)/20px var(--mono); text-align: center; +} +.v-nft-what { min-width: 0; padding-top: 1px; } +.v-nft-what-name { font-weight: 600; overflow-wrap: anywhere; } +.v-nft-what-name[data-muted="true"] { color: var(--text-3); font-weight: 500; } +/* the chain's end: one quiet line */ +.v-nft-step-end { padding: 4px 0 2px; } +.v-nft-step-end .v-nft-n { width: 10px; height: 10px; margin: 4px 5px; border-radius: 3px; background: var(--line-2); } +.v-nft-step-end .v-nft-what { color: var(--text-3); font-size: var(--fs-sm); } +.v-nft-step-end .v-nft-verdict { min-height: 20px; padding: 0 8px; font-size: var(--fs-micro); } +.v-nft-step-more { grid-template-columns: 20px auto; } +.v-nft-cond { margin-top: 2px; color: var(--text-2); font-size: var(--fs-sm); overflow-wrap: anywhere; } +.v-nft-what > .v-nft-cond:first-child { margin-top: 0; color: var(--text); font-size: inherit; } +.v-nft-cond .ifacebadge { + display: inline; margin: 0 10px 0 0; padding: 0; + background: none; border: 0; border-radius: 0; + font-size: inherit; white-space: normal; vertical-align: baseline; +} +.v-nft-cond .ifacebadge .ifacebadge { margin-right: 0; } +/* LuCI's view boxes a set's items at 200px; here they run on as text */ +.v-nft-cond :is(.nft-set, .nft-list, .nft-set-items, .nft-list-items) { display: inline; max-width: none; overflow: visible; vertical-align: baseline; } +.v-nft-cond em { font-style: normal; color: var(--text-3); } +.v-nft-cond var { font-style: normal; } +.v-nft-also { color: var(--text-3); } +.v-nft-empty { margin: 0; padding: 0 var(--sp-1); color: var(--text-3); font-size: var(--fs-sm); } +.v-nft-count { color: var(--text-3); font: var(--fs-micro) var(--mono); white-space: nowrap; } +.v-nft-then { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; } +.v-nft-verdict { + display: inline-flex; align-items: center; gap: 4px; + min-height: 22px; margin: 0; padding: 1px 9px; + background: var(--s3); color: var(--text-2); + border: 1px solid transparent; border-radius: 999px; + box-shadow: none; + font: 600 var(--fs-sm)/1.3 var(--font); white-space: nowrap; text-transform: none; +} +.v-nft-verdict[data-kind="accept"] { background: var(--ok-soft); color: var(--ok-text); } +.v-nft-verdict:is([data-kind="drop"], [data-kind="reject"]) { background: var(--err-soft); color: var(--err-text); } +.v-nft-verdict[data-kind="nat"] { background: var(--info-soft); color: var(--info-text); } +.v-nft-jump { background: var(--s1); border-color: var(--line-2); color: var(--accent-text); font-family: var(--mono); font-weight: 500; cursor: pointer; } +.v-nft-jump::after { + content: ""; width: 5px; height: 5px; margin: 0 1px 2px 3px; + border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; + transform: rotate(45deg); transition: transform .15s; +} +.v-nft-jump[aria-expanded="true"] { background: var(--accent-soft); border-color: var(--accent-line); } +.v-nft-jump[aria-expanded="true"]::after { transform: rotate(-135deg); margin-bottom: -2px; } +.v-nft-jump:hover { border-color: var(--text-3); } +/* the chain a rule jumps to, beneath the rule */ +.v-nft-sub { + grid-column: 2 / -1; + margin: 4px 0 0; + background: var(--s2); + border: 1px solid var(--line); border-left: 3px solid var(--accent-line); + border-radius: var(--r); +} +.v-nft-sub > .v-nft-flow { padding: 2px 10px 4px; } +.v-nft-sub > .v-nft-flow::before { left: 19px; } +.v-nft-sub .v-nft-n { box-shadow: 0 0 0 3px var(--s2); } + /* Status -> System Log / Kernel Log: LuCI's filter rows (Not, box, label, field) as wrapping rows; the gap replaces LuCI's inline margins */ #content_syslog > div:has(> :is(input, select)) { @@ -2897,6 +3088,10 @@ select[id^="widget.cbid.firewall."] > option { color: var(--text); font-weight: .table:has(.cbi-section-table-titles.named[data-title]) .cbi-section-table-row[data-title]:hover::before { background: none; } /* nftables rule cards: LuCI's !important cell padding, on the card's edge */ #view .nft-rules .tr > .td, #view .nft-rules .tr > .td:is(:first-child, :last-child) { padding: 3px var(--card-px) !important; } + /* firewall flow: a step's verdict goes under its text */ + .v-nft-step { grid-template-columns: 20px minmax(0, 1fr); } + .v-nft-then { grid-column: 2; align-items: flex-start; } + .v-nft-sub { grid-column: 1 / -1; } /* log filters: each field on its own line under its label */ #content_syslog > div > :is(select, input:not([type="checkbox"])) { flex: 1 1 100%; } #content_syslog > div > :is(select, input:not([type="checkbox"])) + label { margin-left: 0 !important; } @@ -2960,6 +3155,7 @@ select[id^="widget.cbid.firewall."] > option { color: var(--text); font-weight: .cbi-dropdown[open] > ul.dropdown { transition-duration: .01s; } .cbi-progressbar > div { transition: none; } .vt-crumb-switch > svg, .vt-rail-caret, .vt-rail-pin svg { transition: none; } + .v-nft-card > summary::before, .v-nft-jump::after { transition: none; } } @media print { diff --git a/luci-theme-vantage/po/templates/vantage-theme.pot b/luci-theme-vantage/po/templates/vantage-theme.pot index 8a0e5aa49..afc83e5d4 100644 --- a/luci-theme-vantage/po/templates/vantage-theme.pot +++ b/luci-theme-vantage/po/templates/vantage-theme.pot @@ -1,13 +1,59 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1085 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:70 +msgctxt "Yet unknown nftables table family (\"family\" table \"name\")" +msgid "\"%h\" table \"%h\"" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:353 +msgid "%d more chain at this hook" +msgid_plural "%d more chains at this hook" +msgstr[0] "" +msgstr[1] "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:346 +msgid "%d rule" +msgid_plural "%d rules" +msgstr[0] "" +msgstr[1] "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:408 +msgid "%s matched" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:307 +msgid "%s: table %s (%s), priority %d" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:436 +msgid "(open above)" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:437 +msgid "(too deep to open here)" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:67 +msgid "ARP traffic table \"%h\"" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:156 +msgid "Accept" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1094 msgid "Actions" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1081 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1082 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1083 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:400 +msgctxt "nft match any traffic" +msgid "Any packet" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1090 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1091 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1092 msgid "Appearance" msgstr "" @@ -15,14 +61,34 @@ msgstr "" msgid "Authorization Required" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1264 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1273 msgid "Auto" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:379 +msgid "Back to %s" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:381 +msgid "Back to the calling chain" +msgstr "" + #: luci-theme-vantage/ucode/template/themes/vantage/header.ut:69 msgid "Breadcrumb" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:51 +msgid "Bridge" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:68 +msgid "Bridge traffic table \"%h\"" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:52 +msgid "Bridged between ports" +msgstr "" + #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:278 msgid "Buffered" msgstr "" @@ -37,36 +103,99 @@ msgstr "" msgid "Cached" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:209 +msgid "Chains" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:217 +msgid "Chains no rule jumps to" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:217 +msgid "Chains no rule jumps to directly" +msgstr "" + #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:359 msgid "Channel" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:736 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:745 msgid "Collapse navigation" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1265 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1274 #: luci-theme-vantage/ucode/template/themes/vantage/header.ut:81 msgid "Colour theme" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1106 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1115 msgid "Command palette" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1264 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:400 +msgid "Conditions in the rules table" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:439 +msgid "Continues in %s and does not come back here" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:439 +msgid "Continues in %s, then comes back here" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1273 msgid "Dark" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:736 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:157 +msgid "Drop" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:382 +msgid "Drop: %s policy" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:369 +msgid "Drops unmatched" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:44 +msgid "Egress" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:745 #: luci-theme-vantage/ucode/template/themes/vantage/header.ut:54 msgid "Expand navigation" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1083 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:232 +msgid "Flow" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:268 +msgid "" +"Flow offloading is on: once a forwarded connection is established, its " +"packets can skip prerouting, forward and postrouting, so these chains and " +"their counters see only its first packets." +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1092 msgid "Follow system theme" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:40 +msgid "Forward" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:266 +msgid "" +"Frames bridged between ports of one bridge, such as Wi-Fi and LAN in br-lan " +"on an access point, never reach the input, forward or output chains, and no " +"bridge chain filters them here. (The kernel can hand them to the IP chains " +"if br_netfilter is enabled; the ruleset doesn't show that.)" +msgstr "" + #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:290 #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:304 msgid "Free" @@ -76,21 +205,45 @@ msgstr "" msgid "Home" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:64 +msgid "IPv4 traffic table \"%h\"" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:66 +msgid "IPv4/IPv6 traffic table \"%h\"" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:65 +msgid "IPv6 traffic table \"%h\"" +msgstr "" + #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:289 #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:298 #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:302 msgid "In use" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:43 +msgid "Ingress" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:39 +msgid "Input" +msgstr "" + #: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:48 msgid "Invalid username and/or password! Please try again." msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1102 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1111 msgid "Jump to a page or action…" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1264 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:371 +msgid "Leaves unmatched unchanged" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1273 msgid "Light" msgstr "" @@ -99,7 +252,7 @@ msgstr "" msgid "Log in" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1084 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1093 #: luci-theme-vantage/ucode/template/themes/vantage/header.ut:84 msgid "Log out" msgstr "" @@ -108,59 +261,142 @@ msgstr "" msgid "Main navigation" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:161 +msgid "Masquerade" +msgstr "" + #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:273 #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:288 msgid "Memory" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1493 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1510 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1502 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1519 msgid "More actions" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1177 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:311 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:343 +msgid "NAT" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:250 +msgid "Network" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:69 +msgid "Network device table \"%h\"" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:163 +msgid "Next rule" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1186 msgid "No matching pages" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1011 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:476 +msgid "No rule matched" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:333 +msgid "No rules: %s" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1020 msgid "Other pages in %s" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:41 +msgid "Output" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:207 +msgid "Packet path" +msgstr "" + #: luci-theme-vantage/ucode/template/themes/vantage/header.ut:90 msgid "Page tabs" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:383 +msgid "Pass: %s policy" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:370 +msgid "Passes unmatched" +msgstr "" + #: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:57 msgid "Password" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:885 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:42 +msgid "Postrouting" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:38 +msgid "Prerouting" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:894 msgid "Press" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1104 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:159 +msgid "Queue to a program" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:162 +msgid "Redirect" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:158 +msgid "Reject" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1113 msgid "Results" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1102 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:162 +msgid "Rewrite destination" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:161 +msgid "Rewrite source" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:232 +msgid "Rules table" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1111 #: luci-theme-vantage/ucode/template/themes/vantage/header.ut:72 #: luci-theme-vantage/ucode/template/themes/vantage/header.ut:74 msgid "Search pages" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1084 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1093 msgid "Session" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1647 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:422 +msgid "Show %d more rule" +msgid_plural "Show %d more rules" +msgstr[0] "" +msgstr[1] "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1656 msgid "Show full description" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1636 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1645 msgid "Show full help" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1636 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1645 msgid "Show full help: %s" msgstr "" @@ -181,6 +417,10 @@ msgstr "" msgid "Swap free" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:250 +msgid "This device" +msgstr "" + #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:290 msgid "Total" msgstr "" @@ -189,11 +429,20 @@ msgstr "" msgid "Total Available" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1081 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:407 +msgctxt "nft counter" +msgid "Traffic matched by rule: %.1000mPackets, %.1024mBytes" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:384 +msgid "Unchanged" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1090 msgid "Use dark theme" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1082 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1091 msgid "Use light theme" msgstr "" @@ -205,6 +454,14 @@ msgstr "" msgid "Username" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:455 +msgid "Verdict map %s" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:205 +msgid "View" +msgstr "" + #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:352 msgid "Wireless" msgstr "" @@ -213,44 +470,72 @@ msgstr "" msgid "available" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1112 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1121 msgid "close" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:294 +msgid "drops unmatched" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:294 +msgid "drops unmatched %s" +msgstr "" + #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:340 #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:343 msgid "free" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1179 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1188 msgid "items" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1110 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1119 msgid "navigate" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1111 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:298 +msgid "no bridge chains" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:313 +msgid "no rules" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:344 +msgid "on %s" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1120 msgid "open" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:865 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:939 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:874 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:948 msgid "page" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:865 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:939 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:874 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:948 msgid "pages" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:341 +msgid "priority %d" +msgstr "" + #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:289 #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:299 #: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:303 msgid "reclaimable" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:885 +#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:296 +msgid "rules drop some" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:894 msgid "to search all pages" msgstr ""