From 45b207395d12f1f11069abe9b1b8397d4b51bb31 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 5 Nov 2026 19:25:07 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=9E=20Sync=202026-11-05=2019:25:07?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ariang/Makefile | 3 +- honk/Makefile | 6 +- honk/build_honk_core.sh | 2 +- honk/files/honk.init | 7 +- isp-split/Makefile | 4 +- isp-split/files/usr/lib/isp-split/doctor.sh | 504 ++++- isp-split/files/usr/sbin/isp-split | 2 +- luci-app-cf-dns-speedtest/.gitignore | 4 + luci-app-cf-dns-speedtest/Makefile | 2 +- luci-app-cf-dns-speedtest/README.md | 4 + luci-app-cf-dns-speedtest/docs/APK.md | 18 + luci-app-cf-dns-speedtest/tools/build_apk.py | 119 ++ luci-app-isp-split/Makefile | 4 +- .../luci-static/resources/view/natmap.js | 81 +- luci-app-natmapt/po/cs/natmap.po | 51 +- luci-app-natmapt/po/da/natmap.po | 51 +- luci-app-natmapt/po/de/natmap.po | 51 +- luci-app-natmapt/po/es/natmap.po | 51 +- luci-app-natmapt/po/fr/natmap.po | 51 +- luci-app-natmapt/po/it/natmap.po | 51 +- luci-app-natmapt/po/lt/natmap.po | 51 +- luci-app-natmapt/po/nl/natmap.po | 51 +- luci-app-natmapt/po/pl/natmap.po | 51 +- luci-app-natmapt/po/pt/natmap.po | 51 +- luci-app-natmapt/po/pt_BR/natmap.po | 51 +- luci-app-natmapt/po/ro/natmap.po | 51 +- luci-app-natmapt/po/ru/natmap.po | 51 +- luci-app-natmapt/po/sv/natmap.po | 51 +- luci-app-natmapt/po/templates/natmap.pot | 51 +- luci-app-natmapt/po/tr/natmap.po | 51 +- luci-app-natmapt/po/vi/natmap.po | 51 +- luci-app-natmapt/po/zh_Hans/natmap.po | 51 +- luci-app-natmapt/po/zh_Hant/natmap.po | 51 +- luci-app-open-box/Makefile | 4 +- luci-app-vantage/Makefile | 4 +- .../luci-static/resources/vantage/app.css | 640 ++++--- .../luci-static/resources/vantage/fmt.js | 47 +- .../luci-static/resources/vantage/fwglance.js | 24 +- .../luci-static/resources/vantage/insight.js | 42 +- .../luci-static/resources/vantage/layout.js | 2 +- .../luci-static/resources/vantage/model.js | 2 + .../luci-static/resources/vantage/names.js | 18 +- .../luci-static/resources/vantage/series.js | 8 - .../resources/view/vantage/firewall.js | 31 +- .../resources/view/vantage/overview.js | 646 +++++-- luci-app-vantage/po/templates/vantage.pot | 1533 +++++++-------- luci-app-vantage/po/zh_Hans/vantage.po | 1703 +++++++++-------- luci-theme-vantage/Makefile | 4 +- .../luci-static/resources/menu-vantage.js | 235 ++- .../resources/vantage-theme/host.js | 22 +- .../htdocs/luci-static/vantage/vantage.css | 302 +-- .../po/templates/vantage-theme.pot | 201 +- .../po/zh_Hans/vantage-theme.po | 219 ++- .../ucode/template/themes/vantage/header.ut | 10 +- .../ucode/template/themes/vantage/sysauth.ut | 7 +- meow/Makefile | 4 +- node-pnpm/Makefile | 4 +- openwrt-natmapt/Makefile | 2 +- openwrt-natmapt/files/ddns/Cloudflare | 13 +- openwrt-natmapt/files/natmap-update.sh | 6 +- openwrt-natmapt/files/natmap.init | 8 +- vsftpd/Makefile | 3 +- wwand/Makefile | 6 +- 63 files changed, 4401 insertions(+), 3078 deletions(-) create mode 100644 luci-app-cf-dns-speedtest/docs/APK.md create mode 100644 luci-app-cf-dns-speedtest/tools/build_apk.py diff --git a/ariang/Makefile b/ariang/Makefile index 65654536a..10324f0c8 100644 --- a/ariang/Makefile +++ b/ariang/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ariang PKG_VERSION:=1.3.15 -PKG_RELEASE:=6 +PKG_RELEASE:=7 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).zip PKG_SOURCE_URL:=https://github.com/mayswind/AriaNg/releases/download/$(PKG_VERSION) @@ -40,6 +40,7 @@ define Package/ariang-nginx $(Package/ariang/default) EXTRA_DEPENDS:=nginx$(if $(CONFIG_USE_APK), (>=0)) TITLE += for nginx webserver + CONFLICTS:=ariang endef define Build/Compile diff --git a/honk/Makefile b/honk/Makefile index 268a55781..7df7d3014 100644 --- a/honk/Makefile +++ b/honk/Makefile @@ -5,11 +5,11 @@ include $(TOPDIR)/rules.mk PKG_NAME:=honk -PKG_VERSION:=2026.11.04~88d470c -PKG_RELEASE:=30 +PKG_VERSION:=2026.11.05~9e31cc0 +PKG_RELEASE:=31 HONK_SRC_URL:=https://github.com/daeuniverse/honk.git -HONK_SRC_VERSION:=88d470c662e0ee7a3de3e67afc6129f67e66c1bf +HONK_SRC_VERSION:=9e31cc0bd28825afdc0e384dc989bc3f076e69cf PKG_LICENSE:=AGPL-3.0-only PKG_LICENSE_FILES:=LICENSE diff --git a/honk/build_honk_core.sh b/honk/build_honk_core.sh index 8a3ef4c0e..14e69a2d3 100755 --- a/honk/build_honk_core.sh +++ b/honk/build_honk_core.sh @@ -138,7 +138,7 @@ echo "==> Building honk-core for $RUST_TARGET..." cargo build --release --locked \ -p honk-core \ --no-default-features \ - --features ebpf,rprx,clash-api,native-api,mimalloc \ + --features ebpf,rprx,clash-api,native-api,jemalloc \ --target "$RUST_TARGET" BUILT_BIN="$SRC_DIR/target/$RUST_TARGET/release/honk-core" diff --git a/honk/files/honk.init b/honk/files/honk.init index 386a2a8bf..07d4c3842 100644 --- a/honk/files/honk.init +++ b/honk/files/honk.init @@ -87,9 +87,10 @@ start_service() { hijack_resolv_conf procd_open_instance "$CONF" - # mimalloc pre-reserves a 1 GiB arena; VSZ only, but it dwarfs the real - # footprint in ps. MIMALLOC_ARENA_RESERVE=0: grow on demand instead. - procd_set_param env DAE_LOCATION_ASSET="/usr/share/v2ray" MIMALLOC_ARENA_RESERVE="0" + procd_set_param env \ + DAE_LOCATION_ASSET="/usr/share/v2ray" \ + MIMALLOC_ARENA_RESERVE="0" \ + MALLOC_CONF="retain:false" procd_set_param command "$PROG" --config "$config_file" procd_set_param netdev "$HONK_HOST_IFACE" "$HONK_PEER_IFACE" procd_set_param limits core="unlimited" diff --git a/isp-split/Makefile b/isp-split/Makefile index c888f5870..39ee60971 100644 --- a/isp-split/Makefile +++ b/isp-split/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=isp-split -PKG_VERSION:=0.4.0 -PKG_RELEASE:=6 +PKG_VERSION:=0.4.1 +PKG_RELEASE:=7 PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE PKG_MAINTAINER:=jihebube diff --git a/isp-split/files/usr/lib/isp-split/doctor.sh b/isp-split/files/usr/lib/isp-split/doctor.sh index aaaaed820..8f5537efe 100644 --- a/isp-split/files/usr/lib/isp-split/doctor.sh +++ b/isp-split/files/usr/lib/isp-split/doctor.sh @@ -234,7 +234,13 @@ doc_mwan3_is_nft() { doc_mwan3_table() { _doc_have nft || return 1 - nft list table inet mwan3 >/dev/null 2>&1 + nft list table inet mwan3 >/dev/null 2>&1 && return 0 + # 3.6 的 nft 端口用 inet;个别固件(Kwrt 兼容层 / iptables-nft 残留)会同时 + # 留 ip、ip6 同名表。判据是"表在不在",不能被 family 写死:只认 inet 会让 + # ip mwan3 里的 mwan3 自家规则整表落到 legacy 分支(fix38 的误报根因之一)。 + nft list table ip mwan3 >/dev/null 2>&1 && return 0 + nft list table ip6 mwan3 >/dev/null 2>&1 && return 0 + return 1 } # 版本(P10):opkg 与 apk 双分支;两者都没有 -> 空(不判"漂移",判 unknown) @@ -568,7 +574,9 @@ doc_p4b_table() { } # 写者枚举(检查三/五共用):一次 awk 出 TSV,位运算留给 shell(busybox awk -# 没有 and()/or())。字段:fam tab chain handle field form mask value comment +# 没有 and()/or())。字段:fam tab chain handle field form mask value comment src +# src = RHS 首个操作数的来源:meta / ct / lit / other(老夹具没有这列时为空, +# 求值按"同字段"处理,与 fix38 行为一致) doc_p4_writers() { DOC_W="" [ -n "${DOC_P4:-}" ] || { @@ -596,7 +604,10 @@ doc_p4_writers() { if (p == 0) next field = "mark" if (index(line, "ct mark set") > 0) { - field = "ctmark"; p = index(line, "ct mark set") + 13 + # "ct mark set" 是 11 字符 + 1 个空格 -> 值的起点是 index+12。 + # 旧实现写的 +13 会吃掉值的首字符:`ct mark set 0x100` 被读成 + # "x100" -> form=other -> ct 写者整条漏掉(fix38 顺带修的解析 bug)。 + field = "ctmark"; p = index(line, "ct mark set") + 12 } else if (index(line, "meta mark set") > 0) { p = index(line, "meta mark set") + 14 } else { @@ -607,7 +618,14 @@ doc_p4_writers() { q = index(rest, "# handle ") if (q > 0) { h = substr(rest, q + 9); rest = trim(substr(rest, 1, q - 1)) } sub(/[^0-9].*$/, "", h) - form = "other"; mask = "-"; value = "-" + form = "other"; mask = "-"; value = "-"; src = "other" + # RHS 的首个操作数说明"这条规则读的是哪个字段":meta mark / ct mark / + # 字面值。fix39 的掩码求值靠它区分三种形态——跨字段同步(读 A 写 B)、 + # 同字段掩码(读 B 写 B)、读向(只写 packet mark,不写 ct mark)。 + # 只认行首锚定,避免把 `ct mark & ... != ...` 的条件部分误当来源。 + if (rest ~ /^meta mark/) src = "meta" + else if (rest ~ /^ct mark/) src = "ct" + else if (rest ~ /^0x/) src = "lit" if (index(rest, "&") > 0) { q = index(rest, "&") r2 = trim(substr(rest, q + 1)) @@ -627,38 +645,189 @@ doc_p4_writers() { form = "mask_clear" } } else { - split(rest, C, " ") - value = C[1] - form = "set" + # `meta mark set meta mark | 0x100`(OR 立即数):nft 打印的是 + # `|`,不是 "or",旧实现只认 & 分支会把它读成 other -> 漏掉。 + if (index(rest, "|") > 0) { + q2 = index(rest, "|") + split(trim(substr(rest, q2 + 1)), C, " ") + value = C[1] + form = "or" + } else { + split(rest, C, " ") + value = C[1] + form = "set" + } } if (value != "-" && value != "" && substr(value, 1, 2) != "0x") { form = "other"; value = "-"; mask = "-" } if (fam == "" || tab == "") next - printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", fam, tab, chain, (h == "" ? "-" : h), field, form, mask, value, (cm == "" ? "-" : cm) + printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", fam, tab, chain, (h == "" ? "-" : h), field, form, mask, value, (cm == "" ? "-" : cm), src }') DOC_W_ROWS=$(printf '%s\n' "$DOC_W" | _doc_cnt) } -# 归属(检查五 5.2 的顺序,写死):① inet mwan3 + mwan3* 链 -> mwan3; -# ② 同一张表里 comment 含 isp-split -> isp-split;③ 非 inet 表 -> legacy; -# ④ 其余 -> third_party。顺序即优先级。 +# 归属(检查三/五共用,顺序即优先级): +# ① 表名是 mwan3(任意 family:inet/ip/ip6 都算)-> 整张表连同全部子链都是 +# mwan3 自己的(iface_in_*、policy_*、mwan3_hook、dynamic、mwan3_or_ct_* 等); +# ② 表名是 isp-split 自己的表(isptest / isp_split*)-> isp-split; +# ③ 任何表里链名是 mwan3* / iface_in_* / iface_out_* -> mwan3(表名被改过时兜底); +# ④ comment 含 isp-split -> isp-split;⑤ 非 inet 表 -> legacy(iptables-nft 残留); +# ⑥ 其余 -> third_party。 +# +# 红线(fix38):只看"表/链是谁的",不看 mark 的值。mwan3 的线路值 +# (0x100/0x200/...,掩码 mmx_mask)与 OAF 的默认 ct mark 0x100 完全撞值, +# 值签名永远不能当归属判据——否则 mwan3 自己的线路打标会被判成第三方 DPI。 _doc_owner_of() { # fam tab chain comment + case "$2" in + mwan3 | mwan3_* | mwan3-*) printf 'mwan3'; return 0 ;; + isp_split | isp_split_* | isp-split | isp-split_* | isptest) printf 'isp-split'; return 0 ;; + esac + case "$3" in + mwan3* | iface_in_* | iface_out_*) printf 'mwan3'; return 0 ;; + esac + case "${4:-}" in + *isp-split*) printf 'isp-split'; return 0 ;; + esac case "$1" in - inet) - if [ "$2" = "mwan3" ]; then - case "$3" in - mwan3* | "") printf 'mwan3' ;; - *) printf 'isp-split' ;; - esac - return 0 - fi - case "${4:-}" in - *isp-split*) printf 'isp-split' ;; - *) printf 'third_party' ;; + inet) printf 'third_party' ;; + *) printf 'legacy' ;; + esac +} + +# 值是否整个落在 mmx_mask 位段内(mwan3 线路 mark 家族:0x100/0x200/... 或掩码本身)。 +# 只用于"这条写者是不是线路打标形态"的说明与 hint,绝不参与归属判定。 +_doc_val_in_mask() { # 0x.. + _doc_hx "${1:-}" + [ "$HEX" -ne 0 ] || return 1 + [ "$(( HEX & DOC_MMX_MASK_DEC ))" -eq "$HEX" ] +} + +# 写向位求值(检查三/五共用,唯一实现):一条写 mark 的规则到底"写了哪些位"。 +# +# nft 打印出来的写向有四种形态,旧实现把它们混在一起(mask 之外的位一律算成 +# "清掉了位段内的位"),于是 OpenWrt 自带 fwmark 同步的 OUTPUT 规则必然误报: +# ① `ct mark set 0x100`(字面值) 覆盖位 = 值 & mmx_mask +# ② `... set <别的字段> & 0x00ff0000`(跨字段/同步)覆盖位 = mask | orbits +# ③ `... set <同字段> & 0xffffc1ff | 0x100`(清位+置位)写 = orbits,清 = ~mask +# ④ `... set <别的字段>`(整值写,无掩码) 不可判定 -> 保守 +# ②的语义:规则只把来源字段的 mask 段搬进目标字段,mask 之外的位由来源字段的 +# 当时取值决定(OpenWrt 用 `ct state new` 限定,位段本身与 0x3f00 无重叠), +# 因此判据是"mask | orbits 与 mmx_mask 是否有交集",不是"mask 之外被清了多少位"。 +# +# 读向:`meta mark set ct mark & 0x00ff0000` 只写 packet mark、不写 ct mark, +# 进不了 conntrack,C3 不计(断言 a 的 PREROUTING 行)。 +_doc_wr_eval() { #
+ _wre_f=${1:-} + _wre_form=${2:-other} + _wre_msk=${3:--} + _wre_val=${4:--} + _wre_src=${5:-} + WR_BITS=0 # 写进目标字段的位(可静态求值时) + WR_CLEAR=0 # 被清 0 的位(只有同字段掩码写才算) + WR_KNOWN=1 # 0 = 无法静态求值 -> 调用方按"整段可能被写"保守处理 + WR_KIND="" + # 同字段(自引用)?空 src(老夹具/信息缺失)按同字段处理,保持 fix38 行为。 + _wre_own=1 + case "$_wre_src" in + meta) [ "$_wre_f" = "mark" ] || _wre_own=0 ;; + ct) [ "$_wre_f" = "ctmark" ] || _wre_own=0 ;; + lit | other) _wre_own=0 ;; + esac + case "$_wre_form" in + set) + _doc_hx "$_wre_val" + WR_BITS=$HEX + WR_KIND=literal + ;; + or) + case "$_wre_src:$_wre_f" in + ct:mark) + WR_KIND=read_from_ct + ;; + meta:ctmark) + # `ct mark set meta mark | 0x100`:没有 & 的整值写,来源位未知 + WR_KNOWN=0 + WR_KIND=unevaluable + ;; + *) + _doc_hx "$_wre_val" + WR_BITS=$HEX + WR_KIND=or_literal + ;; esac ;; - *) printf 'legacy' ;; + mask_set | mask_or | mask_clear) + case "$_wre_src:$_wre_f" in + ct:mark) + WR_KIND=read_from_ct + ;; + *) + if [ "$_wre_own" = "1" ]; then + # 同字段掩码写:mask 内是"写进去的位",mask 外是"清掉的位", + # 两半都动了目标字段 -> 取并集(与 fix38 相同的保守口径) + _doc_hx "$_wre_val" + WR_BITS=$HEX + _doc_hx "$_wre_msk" + WR_CLEAR=$(( ~HEX & DOC_MMX_MASK_DEC )) + WR_KIND=same_field_mask + else + # 跨字段掩码写(fwmark 同步):覆盖位 = mask | orbits + _doc_hx "$_wre_msk" + _wre_b=$HEX + [ "$_wre_val" = "-" ] || { + _doc_hx "$_wre_val" + _wre_b=$(( _wre_b | HEX )) + } + WR_BITS=$_wre_b + WR_KIND=mask_expr + fi + ;; + esac + ;; + *) + case "$_wre_src:$_wre_f" in + ct:mark) + WR_KIND=read_from_ct + ;; + ct:ctmark | meta:mark) + # 自赋值(`ct mark set ct mark`):一个位都不改 + WR_KIND=self_noop + ;; + *) + # 无掩码整值写 / 无法解析的表达式:不知道会写哪些位 -> 保守 + WR_KNOWN=0 + WR_KIND=unevaluable + ;; + esac + ;; + esac +} + +# 写向规则的 RHS 文本(人读/JSON 里的判定依据,不是判据本身) +_doc_wr_src_expr() { # + case "${1:-}" in + meta) printf 'meta mark' ;; + ct) printf 'ct mark' ;; + lit) printf '' ;; + *) + # src 缺失(老夹具):按目标字段反推自引用,显示才不会出现 "?" + case "${2:-}" in + mark) printf 'meta mark' ;; + ctmark) printf 'ct mark' ;; + *) printf '?' ;; + esac + ;; + esac +} + +_doc_wr_expr() { # + case "${2:-}" in + set) printf '%s' "${4:--}" ;; + or) printf '%s | %s' "$(_doc_wr_src_expr "${5:-}" "${1:-}")" "${4:--}" ;; + mask_set | mask_or) printf '%s & %s | %s' "$(_doc_wr_src_expr "${5:-}" "${1:-}")" "${3:--}" "${4:--}" ;; + mask_clear) printf '%s & %s' "$(_doc_wr_src_expr "${5:-}" "${1:-}")" "${3:--}" ;; + *) printf '%s(整值写)' "$(_doc_wr_src_expr "${5:-}" "${1:-}")" ;; esac } @@ -675,6 +844,19 @@ _doc_guess_product() { # fam tab chain esac } +# 产品名的展示写法(hint 用;不改变判据) +_doc_product_label() { + case "$1" in + oaf) printf 'OAF' ;; + openclash) printf 'OpenClash' ;; + passwall) printf 'PassWall' ;; + tailscale) printf 'Tailscale' ;; + mihomo) printf 'mihomo' ;; + sing-box) printf 'sing-box' ;; + *) printf '%s' "${1:-}" ;; + esac +} + # P5:ip rule。无掩码规则等价掩码 0xffffffff——不补全会让位段判据全错。 doc_p5_iprule() { [ "${DOC_P5_DONE:-0}" = "1" ] && return 0 @@ -1227,48 +1409,86 @@ doc_check_mark() { fi _c3_writers="" + _c3_writers_n=0 + _c3_excluded="" + _c3_excl_n=0 + _c3_excl_mw=0 + _c3_excl_own=0 _c3_wn=0 _c3_third=0 _c3_overlap=0 _c3_overlap_ordered=0 _c3_overlap_unordered=0 _c3_ct=0 + _c3_ct_names="" + _c3_hint="" + _c3_hint_conf="none" + _c3_hint_basis="none" _c3_outside="" _c3_outside_n=0 # 第三方重叠写者的明细,供检查五继承 DOC_C3_OVERLAP_NAMES="" - while IFS=" " read -r _w_fam _w_tab _w_chn _w_hnd _w_fld _w_form _w_msk _w_val _w_cm; do + # fix39:掩码表达式求值的判定记录(facts 里给用户看"为什么没报") + _c3_eval="" # 第三方写者的形态/覆盖位/是否重叠 + # 「无重叠(已验证)」的 info:按 表/链/位段 去重,最多 4 条 + _c3_disjoint="" + _c3_disjoint_keys=" " + _c3_disjoint_n=0 + _c3_readn=0 + _c3_read_txt="" + _c3_unknown_n=0 + _c3_ct_unknown=0 + _c3_find="" + _doc_find3() { + _c3_find="${_c3_find}${_c3_find:+,}{\"code\":$(_doc_jstr "$1"),\"verdict\":$(_doc_jstr "$2"),\"detail\":$(_doc_jstr "$3"),\"evidence\":$(_doc_jstr "$4")}" + } + while IFS=" " read -r _w_fam _w_tab _w_chn _w_hnd _w_fld _w_form _w_msk _w_val _w_cm _w_src; do [ -n "${_w_fam:-}" ] || continue _c3_wn=$((_c3_wn + 1)) _w_owner=$(_doc_owner_of "$_w_fam" "$_w_tab" "$_w_chn" "$_w_cm") - _w_owned=0 - _w_cleared=0 - case "$_w_form" in - set) - _doc_hx "$_w_val" - _w_owned=$(( HEX & _M )) - ;; - mask_set | mask_or) - _doc_hx "$_w_msk" - _w_mk=$HEX - _doc_hx "$_w_val" - _w_owned=$(( HEX & _M )) - _w_cleared=$(( (~_w_mk) & _M )) - ;; - mask_clear) - _doc_hx "$_w_msk" - _w_mk=$HEX - _w_cleared=$(( (~_w_mk) & _M )) - ;; - esac - _w_touched=$(( _w_cleared | _w_owned )) - _w_prod=$(_doc_guess_product "$_w_fam" "$_w_tab" "$_w_chn") - if [ "$_c3_wn" -le 40 ]; then - _c3_writers="${_c3_writers}${_c3_writers:+,}{\"fam\":$(_doc_jstr "$_w_fam"),\"table\":$(_doc_jstr "$_w_tab"),\"chain\":$(_doc_jstr "$_w_chn"),\"handle\":$(_doc_jstr "$_w_hnd"),\"field\":$(_doc_jstr "$_w_fld"),\"form\":$(_doc_jstr "$_w_form"),\"mask\":$(_doc_jstr "$([ "$_w_msk" = "-" ] && printf '' || printf '%s' "$_w_msk")"),\"value\":$(_doc_jstr "$([ "$_w_val" = "-" ] && printf '' || printf '%s' "$_w_val")"),\"touched\":$(_doc_jstr "$(_doc_hxstr "$_w_touched")"),\"owner\":$(_doc_jstr "$_w_owner")}" + # 写向位求值(唯一实现,检查五同源):形态 -> 覆盖位/清位/可否判定 + _doc_wr_eval "$_w_fld" "$_w_form" "$_w_msk" "$_w_val" "${_w_src:-}" + _w_kind=$WR_KIND + _w_known=$WR_KNOWN + if [ "$_w_known" = "0" ]; then + # 不可判定(整值写/无法解析):按"整段都可能被写"保守处理 + _w_touched=$_M + else + _w_touched=$(( WR_CLEAR | WR_BITS )) fi + _w_prod=$(_doc_guess_product "$_w_fam" "$_w_tab" "$_w_chn") case "$_w_owner" in - third_party | legacy) + mwan3 | isp-split) + # 排除清单(fix38):mwan3 自家表/链(iface_in_*、policy_*、mwan3_hook、 + # dynamic、mwan3_or_ct_* 等,任意 family)与 isp-split 自家表里的写者, + # 都不是第三方。它们写的正是 mmx_mask 位段内的线路值——值签名不能 + # 反过来当"第三方 DPI"的证据。 + _c3_excl_n=$((_c3_excl_n + 1)) + case "$_w_owner" in + mwan3) _c3_excl_mw=$((_c3_excl_mw + 1)) ;; + *) _c3_excl_own=$((_c3_excl_own + 1)) ;; + esac + if [ "$_c3_excl_n" -le 40 ]; then + _c3_excluded="${_c3_excluded}${_c3_excluded:+,}{\"fam\":$(_doc_jstr "$_w_fam"),\"table\":$(_doc_jstr "$_w_tab"),\"chain\":$(_doc_jstr "$_w_chn"),\"field\":$(_doc_jstr "$_w_fld"),\"form\":$(_doc_jstr "$_w_form"),\"mask\":$(_doc_jstr "$([ "$_w_msk" = "-" ] && printf '' || printf '%s' "$_w_msk")"),\"value\":$(_doc_jstr "$([ "$_w_val" = "-" ] && printf '' || printf '%s' "$_w_val")"),\"touched\":$(_doc_jstr "$(_doc_hxstr "$_w_touched")"),\"owner\":$(_doc_jstr "$_w_owner"),\"reason\":$(_doc_jstr "$([ "$_w_owner" = "mwan3" ] && printf 'mwan3_own_table' || printf 'isp_split_own')")}" + fi + ;; + *) _c3_third=$((_c3_third + 1)) + # 表达式文本只给第三方写者用(自家写者上百条,别为它们多 fork) + _w_expr=$(_doc_wr_expr "$_w_fld" "$_w_form" "$_w_msk" "$_w_val" "${_w_src:-}") + _w_inmask=$(( _w_touched & _M )) + if [ "$_w_known" = "0" ]; then + _c3_unknown_n=$((_c3_unknown_n + 1)) + [ "$_w_fld" = "ctmark" ] && _c3_ct_unknown=$((_c3_ct_unknown + 1)) + fi + if [ "$_c3_writers_n" -lt 40 ]; then + _c3_writers_n=$((_c3_writers_n + 1)) + _c3_writers="${_c3_writers}${_c3_writers:+,}{\"fam\":$(_doc_jstr "$_w_fam"),\"table\":$(_doc_jstr "$_w_tab"),\"chain\":$(_doc_jstr "$_w_chn"),\"handle\":$(_doc_jstr "$_w_hnd"),\"field\":$(_doc_jstr "$_w_fld"),\"form\":$(_doc_jstr "$_w_form"),\"mask\":$(_doc_jstr "$([ "$_w_msk" = "-" ] && printf '' || printf '%s' "$_w_msk")"),\"value\":$(_doc_jstr "$([ "$_w_val" = "-" ] && printf '' || printf '%s' "$_w_val")"),\"src\":$(_doc_jstr "${_w_src:-}"),\"expr\":$(_doc_jstr "$_w_expr"),\"eval\":$(_doc_jstr "$_w_kind"),\"bits\":$(_doc_jstr "$(_doc_hxstr "$WR_BITS")"),\"known\":$(_doc_jbool "$_w_known"),\"touched\":$(_doc_jstr "$(_doc_hxstr "$_w_touched")"),\"overlap\":$(_doc_jbool "$([ "$_w_inmask" -ne 0 ] && printf 1 || printf 0)"),\"owner\":$(_doc_jstr "$_w_owner"),\"product_guess\":$(_doc_jstr "$_w_prod")}" + fi + # 判定矩阵留痕:形态 -> 覆盖位 -> 是否与 mmx_mask 重叠 + if [ "$_c3_third" -le 40 ]; then + _c3_eval="${_c3_eval}${_c3_eval:+,}{\"fam\":$(_doc_jstr "$_w_fam"),\"table\":$(_doc_jstr "$_w_tab"),\"chain\":$(_doc_jstr "$_w_chn"),\"handle\":$(_doc_jstr "$_w_hnd"),\"field\":$(_doc_jstr "$_w_fld"),\"form\":$(_doc_jstr "$_w_form"),\"src\":$(_doc_jstr "${_w_src:-}"),\"expr\":$(_doc_jstr "$_w_expr"),\"bits\":$(_doc_jstr "$(_doc_hxstr "$WR_BITS")"),\"known\":$(_doc_jbool "$_w_known"),\"kind\":$(_doc_jstr "$_w_kind"),\"overlap\":$(_doc_jbool "$([ "$_w_inmask" -ne 0 ] && printf 1 || printf 0)")}" + fi if [ "$(( _w_touched & _M ))" -ne 0 ]; then _c3_overlap=$((_c3_overlap + 1)) DOC_C3_OVERLAP_NAMES="${DOC_C3_OVERLAP_NAMES}${DOC_C3_OVERLAP_NAMES:+ }${_w_prod:-third_party}" @@ -1292,11 +1512,51 @@ EOF else _c3_overlap_unordered=$((_c3_overlap_unordered + 1)) fi + if [ "$_w_fld" = "ctmark" ]; then + _c3_ct=$((_c3_ct + 1)) + [ "$_c3_ct" -le 3 ] && + _c3_ct_names="${_c3_ct_names}${_c3_ct_names:+, }${_w_fam} ${_w_tab} ${_w_chn}(${_w_expr})" + # 产品名只是 hint:名字级证据 > 值签名(低置信度)> 未识别。 + if [ "$_c3_hint_conf" != "high" ]; then + if [ -n "$_w_prod" ]; then + _c3_hint=$_w_prod + _c3_hint_conf=high + _c3_hint_basis=name + elif _doc_val_in_mask "$_w_val" && [ "$HEX" = "256" ]; then + # 0x100 既可能是 OAF 的默认 ct mark,也是 mwan3 的 wan1 + # 线路值:只作低置信度猜测,绝不参与 verdict。 + _c3_hint=oaf + _c3_hint_conf=low + _c3_hint_basis=value_signature + fi + fi + fi else - _c3_outside="${_c3_outside}${_c3_outside:+,}{\"fam\":$(_doc_jstr "$_w_fam"),\"table\":$(_doc_jstr "$_w_tab"),\"chain\":$(_doc_jstr "$_w_chn"),\"handle\":$(_doc_jstr "$_w_hnd"),\"product\":$(_doc_jstr "${_w_prod:-third_party}"),\"value\":$(_doc_jstr "$_w_val")}" + _c3_outside="${_c3_outside}${_c3_outside:+,}{\"fam\":$(_doc_jstr "$_w_fam"),\"table\":$(_doc_jstr "$_w_tab"),\"chain\":$(_doc_jstr "$_w_chn"),\"handle\":$(_doc_jstr "$_w_hnd"),\"product\":$(_doc_jstr "${_w_prod:-third_party}"),\"form\":$(_doc_jstr "$_w_form"),\"expr\":$(_doc_jstr "$_w_expr"),\"bits\":$(_doc_jstr "$(_doc_hxstr "$WR_BITS")"),\"value\":$(_doc_jstr "$_w_val")}" _c3_outside_n=$((_c3_outside_n + 1)) + # fix39:求值结论 = 无重叠。必须让用户看见"为什么没报", + # 否则一次误报修完只留下"哦现在不报了"的不信任。 + if [ "$_w_kind" = "mask_expr" ]; then + _w_seg=$_w_msk + [ "$_w_val" = "-" ] || _w_seg="${_w_msk} | ${_w_val}" + _w_key="${_w_tab}/${_w_chn}/${_w_seg}" + case "$_c3_disjoint_keys" in + *" $_w_key "*) + ;; + *) + _c3_disjoint_keys="${_c3_disjoint_keys}${_w_key} " + _c3_disjoint_n=$((_c3_disjoint_n + 1)) + if [ "$_c3_disjoint_n" -le 4 ]; then + _c3_disjoint="${_c3_disjoint}${_w_tab} ${_w_chn} 的 fwmark 同步使用 ${_w_seg} 位段,与 mmx_mask($DOC_MMX_MASK) 无重叠(已验证) +" + fi + ;; + esac + elif [ "$_w_kind" = "read_from_ct" ]; then + _c3_readn=$((_c3_readn + 1)) + [ -n "$_c3_read_txt" ] || _c3_read_txt="${_w_tab} ${_w_chn} 的 ${_w_expr}" + fi fi - [ "$_w_fld" = "ctmark" ] && [ "$(( _w_touched & _M ))" -ne 0 ] && _c3_ct=$((_c3_ct + 1)) ;; esac done </):这是 mwan3 自己的读者, + # 0x100/0x200/... 与 OAF 默认 mark 撞值也不改变归属(只做事实登记)。 + _c3_line_n=0 + _c3_line_vals="" while IFS=" " read -r _r_pref _r_val _r_mask _r_lk _r_iif _r_sup _r_not; do [ -n "${_r_pref:-}" ] || continue [ "$_r_val" = "-" ] && continue @@ -1315,6 +1579,11 @@ EOF _r_v=$HEX _doc_hx "$_r_mask" _r_m=$HEX + if [ "$_r_m" -eq "$_M" ] && [ "$_r_v" -ne 0 ]; then + _c3_line_n=$((_c3_line_n + 1)) + [ "$_c3_line_n" -le 8 ] && + _c3_line_vals="${_c3_line_vals}${_c3_line_vals:+,}$(_doc_jstr "$_r_val")" + fi # 精确匹配(无掩码)且值的位段内有 mwan3 的位 -> mwan3 清位后这条规则失配 if [ "$_r_m" -ne "$_M" ] && [ "$(( _r_v & _M ))" -ne 0 ]; then _c3_starved="${_c3_starved}${_c3_starved:+,}{\"where\":\"ip rule\",\"pref\":$(_doc_jstr "$_r_pref"),\"value\":$(_doc_jstr "$_r_val"),\"lookup\":$(_doc_jstr "$_r_lk")}" @@ -1346,23 +1615,30 @@ EOF _c3_route="null" fi - DOC_C3_FACTS="\"mmx_mask\":$(_doc_jstr "$DOC_MMX_MASK"),\"mmx_mask_source\":$(_doc_jstr "$DOC_MMX_SOURCE"),\"writers\":[$_c3_writers],\"readers\":[$_c3_readers],\"mwan3_min_pref\":$DOC_MINPREF,\"third_party_outside_mask\":[$_c3_outside],\"reader_starved\":[$_c3_starved],\"route_get_mark\":$_c3_route" - - _c3_find="" - _doc_find3() { - _c3_find="${_c3_find}${_c3_find:+,}{\"code\":$(_doc_jstr "$1"),\"verdict\":$(_doc_jstr "$2"),\"detail\":$(_doc_jstr "$3"),\"evidence\":$(_doc_jstr "$4")}" - } + _c3_collision="null" + if [ "$_c3_ct" -gt 0 ]; then + _c3_collision="{\"kind\":\"ctmark\",\"count\":$_c3_ct,\"writers\":[$(_doc_jstr "$_c3_ct_names")],\"hint\":$(_doc_jstr "$_c3_hint"),\"hint_confidence\":$(_doc_jstr "$_c3_hint_conf"),\"hint_basis\":$(_doc_jstr "$_c3_hint_basis")}" + fi + DOC_C3_FACTS="\"mmx_mask\":$(_doc_jstr "$DOC_MMX_MASK"),\"mmx_mask_source\":$(_doc_jstr "$DOC_MMX_SOURCE"),\"writer_total\":$_c3_wn,\"writers\":[$_c3_writers],\"excluded_count\":$_c3_excl_n,\"excluded\":{\"mwan3\":$_c3_excl_mw,\"isp_split\":$_c3_excl_own},\"excluded_writers\":[$_c3_excluded],\"write_eval\":{\"rule\":\"覆盖位 = mask | orbits(跨字段);同字段按 mask 内写 + mask 外清;无掩码整值写不可判定\",\"mmx_mask\":$(_doc_jstr "$DOC_MMX_MASK"),\"writers\":[$_c3_eval],\"disjoint_count\":$_c3_disjoint_n,\"read_direction_count\":$_c3_readn,\"unevaluable_count\":$_c3_unknown_n},\"line_mark_rules\":{\"owner\":\"mwan3\",\"mask\":$(_doc_jstr "$DOC_MMX_MASK"),\"count\":$_c3_line_n,\"values\":[$_c3_line_vals]},\"readers\":[$_c3_readers],\"mwan3_min_pref\":$DOC_MINPREF,\"third_party_outside_mask\":[$_c3_outside],\"reader_starved\":[$_c3_starved],\"collision\":$_c3_collision,\"route_get_mark\":$_c3_route" if [ "$DOC_P4B" != "1" ]; then DOC_C3_VERDICT=unknown - _doc_find3 "" unknown "没有 table inet mwan3(mwan3-nft 未运行),无法判定位段占用" "P4b" + _doc_find3 "" unknown "没有 mwan3 的 nft 表(inet/ip/ip6 都不存在,mwan3-nft 未运行),无法判定位段占用" "P4b" DOC_C3_ADVICE="先确认 mwan3(nft 版)在跑;只看 /etc/config/mwan3 无法判断运行态。" elif [ "$_c3_wn" -eq 0 ]; then DOC_C3_VERDICT=ok _doc_find3 "" ok "规则表里没有任何 mark 写者" "P4" elif [ "$_c3_ct" -gt 0 ]; then DOC_C3_VERDICT=conflict - _doc_find3 "CTMARK_COLLISION" conflict "有程序在写 ct mark 的位段(OAF 类 DPI),改道语义会串" "P4 ct mark set" + case "$_c3_hint_basis" in + name) _c3_hint_txt="疑似 $(_doc_product_label "$_c3_hint")(表名/链名匹配,置信度高)" ;; + value_signature) _c3_hint_txt="疑似 $(_doc_product_label "$_c3_hint")(ct mark 0x100 与 mwan3 的 wan1 线路值撞值;仅值签名,置信度低,不作判据)" ;; + *) _c3_hint_txt="产品未识别(不建议按名字臆断)" ;; + esac + _c3_hint_txt_more="" + [ "$_c3_ct_unknown" -gt 0 ] && + _c3_hint_txt_more=";其中 $_c3_ct_unknown 条 ct mark 写入形态无法静态求值(整值写/未加掩码),按保守口径计入" + _doc_find3 "CTMARK_COLLISION" conflict "有第三方程序改写了 ct mark 中与 mmx_mask($DOC_MMX_MASK) 重叠的位:$_c3_ct_names;$_c3_hint_txt${_c3_hint_txt_more}" "P4 ct mark set(已排除 mwan3/isp-split 自家写者 $_c3_excl_n 条)" elif [ "$_c3_overlap_unordered" -gt 0 ]; then DOC_C3_VERDICT=conflict _doc_find3 "MARK_OVERLAP_UNORDERED" conflict "有 $_c3_overlap_unordered 个第三方写者落在 mmx_mask 位段内,且没有排在 mwan3 之前的 rule" "P4 + P5" @@ -1374,7 +1650,18 @@ EOF _doc_find3 "MARK_OUTSIDE" ok "第三方 mark 写者共 $_c3_outside_n 个,全部落在 mmx_mask 之外" "P4" else DOC_C3_VERDICT=ok - _doc_find3 "" ok "标记位段只有 mwan3 自己在用" "P4" + _doc_find3 "" ok "标记位段只有 mwan3/isp-split 自己在用($_c3_excl_n 条自家写者已按归属排除,第三方 0 条)" "P4" + fi + # fix39:求值结论 = 无重叠的写者,逐条记 info。判据是"覆盖位 & mmx_mask == 0", + # 文案必须带上具体位段,否则用户只看到"现在不报了"而不知道为什么。 + while IFS= read -r _c3_note; do + [ -n "${_c3_note:-}" ] || continue + _doc_find3 "MARK_FWMARK_DISJOINT" info "$_c3_note" "P4 表达式求值:覆盖位 = mask | orbits;(mask|orbits) & mmx_mask($DOC_MMX_MASK) = 0" + done < packet)" fi if [ "$_c3_starved_n" -gt 0 ]; then [ "$DOC_C3_VERDICT" = "ok" ] && DOC_C3_VERDICT=warn @@ -1384,9 +1671,15 @@ EOF _doc_find3 "MMX_MASK_CUSTOM" ok "mmx_mask=$(printf '%s' "$DOC_MMX_MASK") 不是默认 0x3F00,本报告的阈值已按它现算" "P11" case "$DOC_C3_VERDICT" in - ok) DOC_C3_ADVICE="路由标记位段只有 mwan3 在用(或第三方全部在位段之外),分流选路正常。" ;; + ok) DOC_C3_ADVICE="标记位段只有 mwan3/isp-split 自己(或位段之外的第三方)在用,分流选路正常。" ;; warn) DOC_C3_ADVICE="无需改动即可用;若要彻底消除歧义,把代理的 fwmark 移到 mmx_mask 之外(如 0x80000 段)。" ;; - conflict) DOC_C3_ADVICE="检测到有程序直接改写与 mwan3 相同的标记位,分流可能选错线;建议把它的标记值改到位段之外,或把它排到 mwan3 之后。" ;; + conflict) + if [ "$_c3_ct" -gt 0 ]; then + DOC_C3_ADVICE="检测到第三方程序改写了 mwan3 用的 ct mark 位段(mmx_mask);分流可能选错线。先把它的 mark 值移到位段之外,或让它排在 mwan3 之后;产品名只是提示,别按名字下结论。" + else + DOC_C3_ADVICE="检测到第三方程序改写了与 mwan3 相同的标记位,分流可能选错线;建议把它的标记值改到位段之外,或把它排到 mwan3 之后。" + fi + ;; unknown) DOC_C3_ADVICE="没能读取当前 nft 规则,无法判断标记位是否被占用。" ;; esac DOC_C3_FIND="$_c3_find" @@ -1471,31 +1764,26 @@ doc_check_writers() { _c5_inmask=0 _c5_out=0 _c5_legacy=0 + _c5_legacy_inmask=0 _c5_third_inmask=0 + # 清单分两段:第三方/legacy 最多 40 条(决策相关,优先展示), + # mwan3/isp-split 自家写者最多 10 条(生产上 mwan3_or_* 有上百条, + # 全列会把真正的第三方挤出清单)。 _c5_list="" - while IFS=" " read -r _w_fam _w_tab _w_chn _w_hnd _w_fld _w_form _w_msk _w_val _w_cm; do + _c5_list_n=0 + _c5_list_mw="" + _c5_list_mw_n=0 + while IFS=" " read -r _w_fam _w_tab _w_chn _w_hnd _w_fld _w_form _w_msk _w_val _w_cm _w_src; do [ -n "${_w_fam:-}" ] || continue _c5_total=$((_c5_total + 1)) _w_owner=$(_doc_owner_of "$_w_fam" "$_w_tab" "$_w_chn" "$_w_cm") - _w_owned=0 - _w_cleared=0 - case "$_w_form" in - set) - _doc_hx "$_w_val" - _w_owned=$(( HEX & DOC_MMX_MASK_DEC )) - ;; - mask_set | mask_or) - _doc_hx "$_w_val" - _w_owned=$(( HEX & DOC_MMX_MASK_DEC )) - _doc_hx "$_w_msk" - _w_cleared=$(( (~HEX) & DOC_MMX_MASK_DEC )) - ;; - mask_clear) - _doc_hx "$_w_msk" - _w_cleared=$(( (~HEX) & DOC_MMX_MASK_DEC )) - ;; - esac - _w_touched=$(( _w_cleared | _w_owned )) + # 与检查三同源求值(fix39):不允许两套"写了哪些位"的算法漂移 + _doc_wr_eval "$_w_fld" "$_w_form" "$_w_msk" "$_w_val" "${_w_src:-}" + if [ "$WR_KNOWN" = "0" ]; then + _w_touched=$DOC_MMX_MASK_DEC + else + _w_touched=$(( WR_CLEAR | WR_BITS )) + fi _w_prod=$(_doc_guess_product "$_w_fam" "$_w_tab" "$_w_chn") case "$_w_owner" in mwan3) _c5_mw=$((_c5_mw + 1)) ;; @@ -1506,20 +1794,34 @@ doc_check_writers() { if [ "$(( _w_touched & DOC_MMX_MASK_DEC ))" -ne 0 ]; then _c5_inmask=$((_c5_inmask + 1)) case "$_w_owner" in - third_party | legacy) _c5_third_inmask=$((_c5_third_inmask + 1)) ;; + legacy) _c5_legacy_inmask=$((_c5_legacy_inmask + 1)) ;; + third_party) _c5_third_inmask=$((_c5_third_inmask + 1)) ;; esac else _c5_out=$((_c5_out + 1)) fi - # JSON 体积上限:清单只列前 40 条(真实机器上写者通常 < 10) - if [ "$_c5_total" -le 40 ]; then - _c5_list="${_c5_list}${_c5_list:+,}{\"owner\":$(_doc_jstr "$_w_owner"),\"product_guess\":$(_doc_jstr "$_w_prod"),\"fam\":$(_doc_jstr "$_w_fam"),\"table\":$(_doc_jstr "$_w_tab"),\"chain\":$(_doc_jstr "$_w_chn"),\"handle\":$(_doc_jstr "$_w_hnd"),\"field\":$(_doc_jstr "$_w_fld"),\"form\":$(_doc_jstr "$_w_form"),\"mask\":$(_doc_jstr "$([ "$_w_msk" = "-" ] && printf '' || printf '%s' "$_w_msk")"),\"value\":$(_doc_jstr "$([ "$_w_val" = "-" ] && printf '' || printf '%s' "$_w_val")"),\"touched\":$(_doc_jstr "$(_doc_hxstr "$_w_touched")")}" - fi + # JSON 体积上限 + 优先级:第三方最多 40 条,自家写者最多 10 条 + case "$_w_owner" in + mwan3 | isp-split) + if [ "$_c5_list_mw_n" -lt 10 ]; then + _c5_list_mw_n=$((_c5_list_mw_n + 1)) + _c5_list_mw="${_c5_list_mw}${_c5_list_mw:+,}{\"owner\":$(_doc_jstr "$_w_owner"),\"product_guess\":$(_doc_jstr "$_w_prod"),\"fam\":$(_doc_jstr "$_w_fam"),\"table\":$(_doc_jstr "$_w_tab"),\"chain\":$(_doc_jstr "$_w_chn"),\"handle\":$(_doc_jstr "$_w_hnd"),\"field\":$(_doc_jstr "$_w_fld"),\"form\":$(_doc_jstr "$_w_form"),\"mask\":$(_doc_jstr "$([ "$_w_msk" = "-" ] && printf '' || printf '%s' "$_w_msk")"),\"value\":$(_doc_jstr "$([ "$_w_val" = "-" ] && printf '' || printf '%s' "$_w_val")"),\"touched\":$(_doc_jstr "$(_doc_hxstr "$_w_touched")")}" + fi + ;; + *) + if [ "$_c5_list_n" -lt 40 ]; then + _c5_list_n=$((_c5_list_n + 1)) + _c5_list="${_c5_list}${_c5_list:+,}{\"owner\":$(_doc_jstr "$_w_owner"),\"product_guess\":$(_doc_jstr "$_w_prod"),\"fam\":$(_doc_jstr "$_w_fam"),\"table\":$(_doc_jstr "$_w_tab"),\"chain\":$(_doc_jstr "$_w_chn"),\"handle\":$(_doc_jstr "$_w_hnd"),\"field\":$(_doc_jstr "$_w_fld"),\"form\":$(_doc_jstr "$_w_form"),\"mask\":$(_doc_jstr "$([ "$_w_msk" = "-" ] && printf '' || printf '%s' "$_w_msk")"),\"value\":$(_doc_jstr "$([ "$_w_val" = "-" ] && printf '' || printf '%s' "$_w_val")"),\"touched\":$(_doc_jstr "$(_doc_hxstr "$_w_touched")")}" + fi + ;; + esac done < { return window.location = window.location.href.split('#')[0] }) .catch((e) => { ui.addNotification(null, E('p', e.message), 'error') }); }; @@ -288,7 +290,7 @@ return view.extend({ if (nattest_result.length) { o = s.option(form.DummyValue, '_nattest_result', ' '); o.rawhtml = true; - o.cfgvalue = function(s) { + o.cfgvalue = function(section_id) { return '
' + _('Expand/Collapse result') + '' + nattest_result + '
'; } }; @@ -308,35 +310,28 @@ return view.extend({ o = s.option(form.Flag, 'enable', _('Enable')); o.default = o.disabled; o.editable = true; - o.rmempty = true; o.modalonly = false; o = s.taboption('general', form.Value, 'interval', _('Keep-alive interval')); o.datatype = "and(uinteger, min(1))"; - o.rmempty = true; o.modalonly = true; o = s.taboption('general', form.Value, 'stun_cycle', _('STUN check cycle (once every n intervals)'), _('For UDP mode')); o.datatype = 'uinteger'; - o.rmempty = true; o.modalonly = true; o = s.taboption('general', form.Value, 'stun_server', _('STUN server')); o.datatype = 'or(hostname, hostport)'; - o.rmempty = true; o.modalonly = true; o = s.taboption('general', form.Value, 'http_server', _('HTTP server'), _('For TCP mode')); o.datatype = 'or(hostname, hostport)'; - o.rmempty = true; o.modalonly = true; o = s.taboption('general', form.Value, 'fwmark_value', _('Fwmark value'), _('Mark fwmark for STUN/HTTP outbound traffic')); - o.rmempty = true; o.modalonly = true; o = s.taboption('general', form.Value, 'comment', _('Comment')); - o.rmempty = true; o = s.taboption('general', form.ListValue, 'udp_mode', _('Protocol')); o.default = '0'; @@ -380,7 +375,6 @@ return view.extend({ o.noaliases = true; o.nobridges = true; o.nocreate = false; - o.rmempty = true; o = s.taboption('general', form.Value, 'port', _('Bind port'), _('Note: After using portrange, the public ports will be opened in rotation
') + @@ -411,11 +405,11 @@ return view.extend({ let cval = this.cfgvalue(section_id) || this.default; let i = this.keylist.indexOf(cval); return [this.vallist[i], cval]; - }.call(s.getOption('forward_mode')); + }.call(this.section.getOption('forward_mode')); let loopback = function() { let cval = this.cfgvalue(section_id) || this.default; return (cval == this.enabled) ? ' L' : ''; - }.call(s.getOption('natloopback')); + }.call(this.section.getOption('natloopback')); return (cval == this.enabled) ? mode[0] + (mode[1] === 'dnat' ? loopback : '') : _('No'); }; @@ -432,7 +426,7 @@ return view.extend({ let E = document.getElementById('widget.' + this.cbid(section_id).match(/.+\./) + 'family'); let i = E ? E.selectedIndex : null; return E ? E.options[i].value : null; - }.call(s.getOption('family')); + }.call(this.section.getOption('family')); if (value == 'dnat' && family == 'ipv6') return _('The DNAT method not support under IPv6'); @@ -442,7 +436,6 @@ return view.extend({ o = s.taboption('forward', form.Flag, 'natloopback', _('NAT loopback')); o.default = o.enabled; - o.rmempty = true; o.retain = true; o.depends('forward_mode', 'dnat'); o.modalonly = true; @@ -452,14 +445,12 @@ return view.extend({ congestions.forEach((res) => { o.value.apply(o, [res]); }) - o.rmempty = true; o.depends('forward_mode', 'via'); o.modalonly = true; o = s.taboption('forward', form.Value, 'forward_timeout', _('Forward timeout'), _('Port forwarding session idle timeout in seconds')); o.datatype = "and(uinteger, min(1))"; o.placeholder = '300000'; - o.rmempty = true; o.depends('forward_mode', 'via'); o.modalonly = true; @@ -491,7 +482,7 @@ return view.extend({ let enforward = function() { let cval = this.cfgvalue(section_id) || this.default; return (cval == this.enabled) ? true : false; - }.call(s.getOption('forward')); + }.call(this.section.getOption('forward')); return enforward ? this.vallist[i] ?? cval : _('No'); }; @@ -505,16 +496,16 @@ return view.extend({ let enforward = function() { let cval = this.cfgvalue(section_id) || this.default; return (cval == this.enabled) ? true : false; - }.call(s.getOption('forward')); + }.call(this.section.getOption('forward')); let refresh = function() { let cval = this.cfgvalue(section_id) || this.default; return (cval == this.enabled) ? true : false; - }.call(s.getOption('refresh')); + }.call(this.section.getOption('refresh')); let cltname = function() { let cval = this.cfgvalue(section_id) || this.default; let i = this.keylist.indexOf(cval); return this.vallist[i]; - }.call(s.getOption('clt_script')); + }.call(this.section.getOption('clt_script')); return enforward ? ((cval == '0' && refresh) ? cltname : cval) : _('No'); }; @@ -555,14 +546,12 @@ return view.extend({ o.modalonly = true; o = s.taboption('forward', form.Value, 'clt_username', _('Username')); - o.rmempty = true; o.retain = true; o.depends('refresh', '1'); o.modalonly = true; o = s.taboption('forward', form.Value, 'clt_password', _('Password')); o.password = true; - o.rmempty = true; o.depends('refresh', '1'); o.modalonly = true; @@ -583,7 +572,6 @@ return view.extend({ o = s.taboption('notify', form.Flag, 'notify_enable', _('EnNotify')); o.default = o.disabled; o.editable = true; - o.rmempty = true; o = s.taboption('notify', form.ListValue, 'notify_script', _('Notify Scripts')); o.datatype = 'file'; @@ -602,24 +590,20 @@ return view.extend({ .format('https://github.com/muink/openwrt-natmapt/tree/master/files/notify/', _('# All external tokens required Field'))); o.datatype = 'list(string)'; o.placeholder = 'KEY=VAL'; - o.rmempty = true; o.modalonly = true; o = s.taboption('notify', form.Value, 'notify_custom_domain', _('Private API Domain')); o.datatype = 'hostname'; o.placeholder = 'api.example.com'; - o.rmempty = true; o.modalonly = true; o = s.taboption('notify', form.Value, 'notify_text', _('Text content')); o.placeholder = 'NATMap: : [] : -> :'; - o.rmempty = true; o.modalonly = true; o = s.taboption('ddns', form.Flag, 'ddns_enable', _('EnDDNS')); o.default = o.disabled; o.editable = true; - o.rmempty = true; o = s.taboption('ddns', form.ListValue, 'ddns_script', _('DDNS Scripts')); o.datatype = 'file'; @@ -638,23 +622,43 @@ return view.extend({ .format('https://github.com/muink/openwrt-natmapt/tree/master/files/ddns/', _('# All external tokens required Field'))); o.datatype = 'list(string)'; o.placeholder = 'KEY=VAL'; - o.rmempty = true; o.modalonly = true; o = s.taboption('ddns', form.Value, 'ddns_a', _('A Record ') + _('FQDN')); o.datatype = 'hostname'; o.placeholder = 'www.example.com'; - o.rmempty = true; o.depends('family', 'ipv4'); o.modalonly = true; o = s.taboption('ddns', form.Value, 'ddns_aaaa', _('AAAA Record ') + _('FQDN')); o.datatype = 'hostname'; o.placeholder = 'ipv6.example.com'; - o.rmempty = true; o.depends('family', 'ipv6'); o.modalonly = true; + o = s.taboption('ddns', form.DummyValue, '_ddns_txt_dump', _('TXT Record')); + o.rawhtml = false; + o.cfgvalue = function(section_id) { + let fqdn = uci.get(conf, section_id, 'ddns_txt'); + let cont = uci.get(conf, section_id, 'ddns_txt_content'); + + if ( fqdn && cont ) + return fqdn + '. IN TXT ' + cont; + }; + o.modalonly = true; + + o = s.taboption('ddns', form.Value, 'ddns_txt', _('FQDN')); + o.datatype = 'hostname'; + o.placeholder = 'txt.example.com'; + o.modalonly = true; + + o = s.taboption('ddns', form.Value, 'ddns_txt_content', _('Content')); + o.placeholder = '"port={{port}}; target={{ip}}"'; + o.default = '"port={{port}}; target={{ip}}"'; + o.rmempty = false; + o.depends({ ddns_txt: "", "!reverse": true }) + o.modalonly = true; + o = s.taboption('ddns', form.DummyValue, '_ddns_srv_dump', _('SRV Record')); o.rawhtml = false; o.cfgvalue = function(section_id) { @@ -673,13 +677,13 @@ return view.extend({ o = s.taboption('ddns', form.Value, 'ddns_srv', _('FQDN')); o.datatype = 'hostname'; o.placeholder = 'mc.example.com'; - o.rmempty = true; o.modalonly = true; o = s.taboption('ddns', form.Value, 'ddns_srv_serv', _('Service'), _('Can refer to RFC8552')); o.value('http'); o.value('minecraft'); o.value('factorio'); + o.value('easytier'); o.default = 'minecraft'; o.rmempty = false; o.depends({ ddns_srv: "", "!reverse": true }) @@ -689,6 +693,7 @@ return view.extend({ o.value('tcp', _('TCP')); o.value('udp', _('UDP')); o.value('tls', _('TLS')); + o.value('wg', _('WireGuard')); o.default = 'tcp'; o.rmempty = false; o.depends({ ddns_srv: "", "!reverse": true }) @@ -697,21 +702,20 @@ return view.extend({ o = s.taboption('ddns', form.Value, 'ddns_srv_target', _('Target')); o.datatype = 'hostname'; o.placeholder = 'cdn.example.com'; - o.rmempty = true; o.depends({ ddns_srv: "", "!reverse": true }) o.modalonly = true; o = s.taboption('ddns', form.Value, 'ddns_srv_priority', _('Priority')); o.datatype = 'range(0, 65535)'; o.default = 0; - o.rmempty = true; + o.rmempty = false; o.depends({ ddns_srv: "", "!reverse": true }) o.modalonly = true; o = s.taboption('ddns', form.Value, 'ddns_srv_weight', _('Weight')); o.datatype = 'range(0, 65535)'; o.default = 65535; - o.rmempty = true; + o.rmempty = false; o.depends({ ddns_srv: "", "!reverse": true }) o.modalonly = true; @@ -731,28 +735,27 @@ return view.extend({ o = s.taboption('ddns', form.Value, 'ddns_https', _('FQDN')); o.datatype = 'hostname'; o.placeholder = 'www.example.com'; - o.rmempty = true; o.modalonly = true; o = s.taboption('ddns', form.Value, 'ddns_https_target', _('Target')); o.datatype = "or('.', hostname)"; o.placeholder = '. or web.example.com'; o.default = '.'; - o.rmempty = true; + o.rmempty = false; o.depends({ ddns_https: "", "!reverse": true }) o.modalonly = true; o = s.taboption('ddns', form.Value, 'ddns_https_svcparams', _('SvcParams')); o.placeholder = 'alpn="h3,h3-29,h2,http/1.1" ipv4hint= ipv6hint= port='; o.default = 'alpn="h2,http/1.1"'; - o.rmempty = true; + o.rmempty = false; o.depends({ ddns_https: "", "!reverse": true }) o.modalonly = true; o = s.taboption('ddns', form.Value, 'ddns_https_priority', _('Priority')); o.datatype = 'range(1, 65535)'; o.default = 1; - o.rmempty = true; + o.rmempty = false; o.depends({ ddns_https: "", "!reverse": true }) o.modalonly = true; diff --git a/luci-app-natmapt/po/cs/natmap.po b/luci-app-natmapt/po/cs/natmap.po index ea23adf9a..8a56f2142 100644 --- a/luci-app-natmapt/po/cs/natmap.po +++ b/luci-app-natmapt/po/cs/natmap.po @@ -42,8 +42,8 @@ msgstr "" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -59,8 +59,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -116,8 +120,9 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -180,7 +185,7 @@ msgstr "" msgid "HTTP server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -277,8 +282,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -287,7 +292,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "" @@ -313,7 +318,7 @@ msgstr "" msgid "Restrict to address family" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -332,7 +337,7 @@ msgstr "" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -340,12 +345,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -357,12 +362,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -420,7 +429,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -444,10 +453,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -469,6 +482,6 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/da/natmap.po b/luci-app-natmapt/po/da/natmap.po index 4370ea568..e80a46755 100644 --- a/luci-app-natmapt/po/da/natmap.po +++ b/luci-app-natmapt/po/da/natmap.po @@ -48,8 +48,8 @@ msgstr "Bind port" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -65,8 +65,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -122,8 +126,9 @@ msgstr "Ekstern port" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -186,7 +191,7 @@ msgstr "" msgid "HTTP server" msgstr "HTTP server" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -283,8 +288,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -293,7 +298,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "Protokol" @@ -319,7 +324,7 @@ msgstr "" msgid "Restrict to address family" msgstr "Begræns til adresse familie" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -338,7 +343,7 @@ msgstr "STUN server" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -346,12 +351,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -363,12 +368,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -426,7 +435,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -450,10 +459,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -475,7 +488,7 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/de/natmap.po b/luci-app-natmapt/po/de/natmap.po index ee6f9e50c..b04963295 100644 --- a/luci-app-natmapt/po/de/natmap.po +++ b/luci-app-natmapt/po/de/natmap.po @@ -48,8 +48,8 @@ msgstr "Bindungsport" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -65,8 +65,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -122,8 +126,9 @@ msgstr "Externer Port" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -186,7 +191,7 @@ msgstr "" msgid "HTTP server" msgstr "HTTP Server" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -283,8 +288,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -293,7 +298,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "Protokoll" @@ -319,7 +324,7 @@ msgstr "" msgid "Restrict to address family" msgstr "Auf Adressfamilie beschränken" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -338,7 +343,7 @@ msgstr "STUN-Server" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -346,12 +351,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -363,12 +368,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -426,7 +435,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -450,10 +459,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -475,7 +488,7 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/es/natmap.po b/luci-app-natmapt/po/es/natmap.po index c612474c9..8c2ca45b4 100644 --- a/luci-app-natmapt/po/es/natmap.po +++ b/luci-app-natmapt/po/es/natmap.po @@ -48,8 +48,8 @@ msgstr "Vincular puerto" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -65,8 +65,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -122,8 +126,9 @@ msgstr "Puerto externo" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -186,7 +191,7 @@ msgstr "" msgid "HTTP server" msgstr "Servidor HTTP" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -283,8 +288,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -293,7 +298,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "Protocolo" @@ -319,7 +324,7 @@ msgstr "" msgid "Restrict to address family" msgstr "Restringir para dirigirse a la familia" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -338,7 +343,7 @@ msgstr "Servidor STUN" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -346,12 +351,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -363,12 +368,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -426,7 +435,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -450,10 +459,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -475,7 +488,7 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/fr/natmap.po b/luci-app-natmapt/po/fr/natmap.po index a4f06ee3c..6c536efb6 100644 --- a/luci-app-natmapt/po/fr/natmap.po +++ b/luci-app-natmapt/po/fr/natmap.po @@ -48,8 +48,8 @@ msgstr "Port de liaison" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -65,8 +65,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -122,8 +126,9 @@ msgstr "Port externe" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -186,7 +191,7 @@ msgstr "" msgid "HTTP server" msgstr "Serveur HTTP" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -283,8 +288,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -293,7 +298,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "Protocole" @@ -319,7 +324,7 @@ msgstr "" msgid "Restrict to address family" msgstr "Restreindre à la famille d’adresses" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -338,7 +343,7 @@ msgstr "Serveur STUN" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -346,12 +351,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -363,12 +368,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -426,7 +435,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -450,10 +459,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -475,7 +488,7 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/it/natmap.po b/luci-app-natmapt/po/it/natmap.po index ad6958cea..763ec735a 100644 --- a/luci-app-natmapt/po/it/natmap.po +++ b/luci-app-natmapt/po/it/natmap.po @@ -48,8 +48,8 @@ msgstr "collega porta" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -65,8 +65,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -122,8 +126,9 @@ msgstr "Porta Esterna" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -186,7 +191,7 @@ msgstr "" msgid "HTTP server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -283,8 +288,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -293,7 +298,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "" @@ -319,7 +324,7 @@ msgstr "" msgid "Restrict to address family" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -338,7 +343,7 @@ msgstr "" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -346,12 +351,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -363,12 +368,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -426,7 +435,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -450,10 +459,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -475,6 +488,6 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/lt/natmap.po b/luci-app-natmapt/po/lt/natmap.po index 01569bfaf..588e47499 100644 --- a/luci-app-natmapt/po/lt/natmap.po +++ b/luci-app-natmapt/po/lt/natmap.po @@ -50,8 +50,8 @@ msgstr "Priskirti prievadą" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -67,8 +67,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -124,8 +128,9 @@ msgstr "Išorinis prievadas" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -188,7 +193,7 @@ msgstr "" msgid "HTTP server" msgstr "„HTTP“ serveris" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -285,8 +290,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -295,7 +300,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "Protokolas" @@ -321,7 +326,7 @@ msgstr "" msgid "Restrict to address family" msgstr "Riboti tik adresų šeimai" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -340,7 +345,7 @@ msgstr "„STUN“ serveris" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -348,12 +353,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -365,12 +370,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -428,7 +437,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -452,10 +461,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -477,7 +490,7 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/nl/natmap.po b/luci-app-natmapt/po/nl/natmap.po index e3abc4a55..33c413cfa 100644 --- a/luci-app-natmapt/po/nl/natmap.po +++ b/luci-app-natmapt/po/nl/natmap.po @@ -48,8 +48,8 @@ msgstr "Bind poort" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -65,8 +65,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -122,8 +126,9 @@ msgstr "Externe poort" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -186,7 +191,7 @@ msgstr "" msgid "HTTP server" msgstr "HTTP-server" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -283,8 +288,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -293,7 +298,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "Protocol" @@ -319,7 +324,7 @@ msgstr "" msgid "Restrict to address family" msgstr "Beperken tot adres familie" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -338,7 +343,7 @@ msgstr "STUN-server" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -346,12 +351,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -363,12 +368,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -426,7 +435,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -450,10 +459,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -475,7 +488,7 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/pl/natmap.po b/luci-app-natmapt/po/pl/natmap.po index 839f2d7c2..0f8cff88e 100644 --- a/luci-app-natmapt/po/pl/natmap.po +++ b/luci-app-natmapt/po/pl/natmap.po @@ -49,8 +49,8 @@ msgstr "Zwiąż port" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -66,8 +66,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -123,8 +127,9 @@ msgstr "Port zewnętrzny" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -187,7 +192,7 @@ msgstr "" msgid "HTTP server" msgstr "Serwer HTTP" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -284,8 +289,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -294,7 +299,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "Protokół" @@ -320,7 +325,7 @@ msgstr "" msgid "Restrict to address family" msgstr "Ogranicz do rodziny adresów" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -339,7 +344,7 @@ msgstr "Serwer STUN" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -347,12 +352,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -364,12 +369,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -427,7 +436,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -451,10 +460,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -476,7 +489,7 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/pt/natmap.po b/luci-app-natmapt/po/pt/natmap.po index a016fa952..2c0974473 100644 --- a/luci-app-natmapt/po/pt/natmap.po +++ b/luci-app-natmapt/po/pt/natmap.po @@ -48,8 +48,8 @@ msgstr "Porta do bind" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -65,8 +65,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -122,8 +126,9 @@ msgstr "Porta externa" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -186,7 +191,7 @@ msgstr "" msgid "HTTP server" msgstr "Servidor HTTP" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -283,8 +288,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -293,7 +298,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "Protocolo" @@ -319,7 +324,7 @@ msgstr "" msgid "Restrict to address family" msgstr "Restringe à uma família de endereços" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -338,7 +343,7 @@ msgstr "Servidor STUN" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -346,12 +351,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -363,12 +368,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -426,7 +435,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -450,10 +459,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -475,7 +488,7 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/pt_BR/natmap.po b/luci-app-natmapt/po/pt_BR/natmap.po index 406905873..85ae3a270 100644 --- a/luci-app-natmapt/po/pt_BR/natmap.po +++ b/luci-app-natmapt/po/pt_BR/natmap.po @@ -48,8 +48,8 @@ msgstr "Porta do bind" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -65,8 +65,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -122,8 +126,9 @@ msgstr "Porta externa" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -186,7 +191,7 @@ msgstr "" msgid "HTTP server" msgstr "Servidor HTTP" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -283,8 +288,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -293,7 +298,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "Protocolo" @@ -319,7 +324,7 @@ msgstr "" msgid "Restrict to address family" msgstr "Restringe à uma família de endereços" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -338,7 +343,7 @@ msgstr "Servidor STUN" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -346,12 +351,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -363,12 +368,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -426,7 +435,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -450,10 +459,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -475,7 +488,7 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/ro/natmap.po b/luci-app-natmapt/po/ro/natmap.po index bc1df61aa..746fc0a63 100644 --- a/luci-app-natmapt/po/ro/natmap.po +++ b/luci-app-natmapt/po/ro/natmap.po @@ -49,8 +49,8 @@ msgstr "Legați portul" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -66,8 +66,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -123,8 +127,9 @@ msgstr "Port extern" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -187,7 +192,7 @@ msgstr "" msgid "HTTP server" msgstr "Server HTTP" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -284,8 +289,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -294,7 +299,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "Protocol" @@ -320,7 +325,7 @@ msgstr "" msgid "Restrict to address family" msgstr "Restricționarea la adresa familiei" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -339,7 +344,7 @@ msgstr "Server STUN" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -347,12 +352,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -364,12 +369,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -427,7 +436,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -451,10 +460,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -476,7 +489,7 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/ru/natmap.po b/luci-app-natmapt/po/ru/natmap.po index 2966945f5..fc3c0fa57 100644 --- a/luci-app-natmapt/po/ru/natmap.po +++ b/luci-app-natmapt/po/ru/natmap.po @@ -49,8 +49,8 @@ msgstr "Порт сервера" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -66,8 +66,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -123,8 +127,9 @@ msgstr "Внешний порт" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -187,7 +192,7 @@ msgstr "" msgid "HTTP server" msgstr "HTTP-сервер" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -284,8 +289,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -294,7 +299,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "Протокол" @@ -320,7 +325,7 @@ msgstr "" msgid "Restrict to address family" msgstr "Использовать протокол" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -339,7 +344,7 @@ msgstr "Сервер STUN" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -347,12 +352,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -364,12 +369,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -427,7 +436,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -451,10 +460,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -476,7 +489,7 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/sv/natmap.po b/luci-app-natmapt/po/sv/natmap.po index d8c4b2a4f..fd0b663c4 100644 --- a/luci-app-natmapt/po/sv/natmap.po +++ b/luci-app-natmapt/po/sv/natmap.po @@ -42,8 +42,8 @@ msgstr "" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -59,8 +59,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -116,8 +120,9 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -180,7 +185,7 @@ msgstr "" msgid "HTTP server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -277,8 +282,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -287,7 +292,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "" @@ -313,7 +318,7 @@ msgstr "" msgid "Restrict to address family" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -332,7 +337,7 @@ msgstr "" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -340,12 +345,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -357,12 +362,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -420,7 +429,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -444,10 +453,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -469,6 +482,6 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/templates/natmap.pot b/luci-app-natmapt/po/templates/natmap.pot index 1d0bb4dd4..245328206 100644 --- a/luci-app-natmapt/po/templates/natmap.pot +++ b/luci-app-natmapt/po/templates/natmap.pot @@ -39,8 +39,8 @@ msgstr "" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -56,8 +56,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -113,8 +117,9 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -177,7 +182,7 @@ msgstr "" msgid "HTTP server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -274,8 +279,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -284,7 +289,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "" @@ -310,7 +315,7 @@ msgstr "" msgid "Restrict to address family" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -329,7 +334,7 @@ msgstr "" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -337,12 +342,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -354,12 +359,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -417,7 +426,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -441,10 +450,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -466,6 +479,6 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/tr/natmap.po b/luci-app-natmapt/po/tr/natmap.po index a52adf7f2..f22d6d027 100644 --- a/luci-app-natmapt/po/tr/natmap.po +++ b/luci-app-natmapt/po/tr/natmap.po @@ -42,8 +42,8 @@ msgstr "" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -59,8 +59,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -116,8 +120,9 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -180,7 +185,7 @@ msgstr "" msgid "HTTP server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -277,8 +282,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -287,7 +292,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "" @@ -313,7 +318,7 @@ msgstr "" msgid "Restrict to address family" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -332,7 +337,7 @@ msgstr "" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -340,12 +345,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -357,12 +362,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -420,7 +429,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -444,10 +453,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -469,6 +482,6 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/vi/natmap.po b/luci-app-natmapt/po/vi/natmap.po index 626c2c90b..f7a29d38b 100644 --- a/luci-app-natmapt/po/vi/natmap.po +++ b/luci-app-natmapt/po/vi/natmap.po @@ -48,8 +48,8 @@ msgstr "Cổng Bind" msgid "Boot delay" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "" @@ -65,8 +65,12 @@ msgstr "" msgid "Comment" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "" @@ -122,8 +126,9 @@ msgstr "Cổng bên ngoài" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -186,7 +191,7 @@ msgstr "" msgid "HTTP server" msgstr "HTTP server" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "" @@ -283,8 +288,8 @@ msgstr "" msgid "Port forwarding session idle timeout in seconds" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "" @@ -293,7 +298,7 @@ msgid "Private API Domain" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "Giao thức" @@ -319,7 +324,7 @@ msgstr "" msgid "Restrict to address family" msgstr "Giới hạn địa chỉ gia đình" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "" @@ -338,7 +343,7 @@ msgstr "Máy chủ STUN" msgid "Server" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "" @@ -346,12 +351,12 @@ msgstr "" msgid "Set 0 will follow Public port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -363,12 +368,16 @@ msgstr "" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "" @@ -426,7 +435,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -450,10 +459,14 @@ msgstr "" msgid "Web UI Port" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -475,7 +488,7 @@ msgstr "" msgid "luci check may not detect all conflicts." msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/zh_Hans/natmap.po b/luci-app-natmapt/po/zh_Hans/natmap.po index 4780ccfd4..de6fe4a5a 100644 --- a/luci-app-natmapt/po/zh_Hans/natmap.po +++ b/luci-app-natmapt/po/zh_Hans/natmap.po @@ -48,8 +48,8 @@ msgstr "绑定端口" msgid "Boot delay" msgstr "启动延迟" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "可以参考 RFC8552" @@ -65,8 +65,12 @@ msgstr "检测 NAT 行为" msgid "Comment" msgstr "备注" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "内容" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "自定义脚本" @@ -122,8 +126,9 @@ msgstr "外部端口" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -186,7 +191,7 @@ msgstr "" msgid "HTTP server" msgstr "HTTP 服务器" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "HTTPS 记录" @@ -283,8 +288,8 @@ msgstr "请检查防火墙规则以避免端口冲突< msgid "Port forwarding session idle timeout in seconds" msgstr "端口转发会话空闲超时 (以秒为单位)" -#: htdocs/luci-static/resources/view/natmap.js:704 -#: htdocs/luci-static/resources/view/natmap.js:752 +#: htdocs/luci-static/resources/view/natmap.js:729 +#: htdocs/luci-static/resources/view/natmap.js:777 msgid "Priority" msgstr "优先权" @@ -293,7 +298,7 @@ msgid "Private API Domain" msgstr "私有 API 域名" #: htdocs/luci-static/resources/view/natmap.js:341 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:712 #: htdocs/luci-static/resources/view/status/include/72_natmap.js:60 msgid "Protocol" msgstr "协议" @@ -319,7 +324,7 @@ msgstr "重新载入" msgid "Restrict to address family" msgstr "地址族限制" -#: htdocs/luci-static/resources/view/natmap.js:658 +#: htdocs/luci-static/resources/view/natmap.js:681 msgid "SRV Record" msgstr "SRV 记录" @@ -338,7 +343,7 @@ msgstr "STUN 服务器" msgid "Server" msgstr "服务器" -#: htdocs/luci-static/resources/view/natmap.js:679 +#: htdocs/luci-static/resources/view/natmap.js:702 msgid "Service" msgstr "服务" @@ -346,12 +351,12 @@ msgstr "服务" msgid "Set 0 will follow Public port" msgstr "设为 0 将跟随公共端口" -#: htdocs/luci-static/resources/view/natmap.js:745 +#: htdocs/luci-static/resources/view/natmap.js:770 msgid "SvcParams" msgstr "服务参数" #: htdocs/luci-static/resources/view/natmap.js:174 -#: htdocs/luci-static/resources/view/natmap.js:689 +#: htdocs/luci-static/resources/view/natmap.js:713 msgid "TCP" msgstr "" @@ -363,12 +368,16 @@ msgstr "TCP 拥塞控制" msgid "TCP STUN" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:691 +#: htdocs/luci-static/resources/view/natmap.js:715 msgid "TLS" msgstr "" -#: htdocs/luci-static/resources/view/natmap.js:697 -#: htdocs/luci-static/resources/view/natmap.js:737 +#: htdocs/luci-static/resources/view/natmap.js:658 +msgid "TXT Record" +msgstr "TXT 记录" + +#: htdocs/luci-static/resources/view/natmap.js:722 +#: htdocs/luci-static/resources/view/natmap.js:762 msgid "Target" msgstr "目标" @@ -428,7 +437,7 @@ msgstr "" #: htdocs/luci-static/resources/view/natmap.js:179 #: htdocs/luci-static/resources/view/natmap.js:184 -#: htdocs/luci-static/resources/view/natmap.js:690 +#: htdocs/luci-static/resources/view/natmap.js:714 msgid "UDP" msgstr "" @@ -452,10 +461,14 @@ msgstr "经由 natmap" msgid "Web UI Port" msgstr "Web UI 端口" -#: htdocs/luci-static/resources/view/natmap.js:711 +#: htdocs/luci-static/resources/view/natmap.js:736 msgid "Weight" msgstr "权重" +#: htdocs/luci-static/resources/view/natmap.js:716 +msgid "WireGuard" +msgstr "" + #: htdocs/luci-static/resources/view/natmap.js:163 msgid "" "https://github.com/muink/rfc5780-stun-server/blob/master/valid_hosts_rfc5780." @@ -477,7 +490,7 @@ msgstr "keep-alive 间隔 (秒)" msgid "luci check may not detect all conflicts." msgstr "luci 检查可能无法检测到所有冲突" -#: htdocs/luci-static/resources/view/natmap.js:764 +#: htdocs/luci-static/resources/view/natmap.js:789 msgid "⭮" msgstr "" diff --git a/luci-app-natmapt/po/zh_Hant/natmap.po b/luci-app-natmapt/po/zh_Hant/natmap.po index 42da038ce..2a42bb8f1 100644 --- a/luci-app-natmapt/po/zh_Hant/natmap.po +++ b/luci-app-natmapt/po/zh_Hant/natmap.po @@ -48,8 +48,8 @@ msgstr "綁定埠" msgid "Boot delay" msgstr "啟動延遲" -#: htdocs/luci-static/resources/view/natmap.js:679 -#: htdocs/luci-static/resources/view/natmap.js:688 +#: htdocs/luci-static/resources/view/natmap.js:702 +#: htdocs/luci-static/resources/view/natmap.js:712 msgid "Can refer to RFC8552" msgstr "可以參考 RFC8552" @@ -65,8 +65,12 @@ msgstr "檢查 NAT 行為" msgid "Comment" msgstr "備註" +#: htdocs/luci-static/resources/view/natmap.js:675 +msgid "Content" +msgstr "內容" + #: htdocs/luci-static/resources/view/natmap.js:306 -#: htdocs/luci-static/resources/view/natmap.js:759 +#: htdocs/luci-static/resources/view/natmap.js:784 msgid "Custom Script" msgstr "自定義腳本" @@ -122,8 +126,9 @@ msgstr "外部通訊埠" #: htdocs/luci-static/resources/view/natmap.js:644 #: htdocs/luci-static/resources/view/natmap.js:651 -#: htdocs/luci-static/resources/view/natmap.js:673 -#: htdocs/luci-static/resources/view/natmap.js:731 +#: htdocs/luci-static/resources/view/natmap.js:669 +#: htdocs/luci-static/resources/view/natmap.js:696 +#: htdocs/luci-static/resources/view/natmap.js:756 msgid "FQDN" msgstr "" @@ -186,7 +191,7 @@ msgstr "" msgid "HTTP server" msgstr "HTTP 伺服器" -#: htdocs/luci-static/resources/view/natmap.js:718 +#: htdocs/luci-static/resources/view/natmap.js:743 msgid "HTTPS Record" msgstr "HTTPS 記錄" @@ -283,8 +288,8 @@ msgstr "請檢查防火牆規則以避免埠衝突
.vt-cell, .vt-app .vt-grid > .vt-drop-ghost { --c: 0; --w: 1; --y: 0px; --vt-cw: calc((100% - (var(--cols) - 1) * var(--vt-gap)) / var(--cols)); @@ -326,17 +377,17 @@ html[data-darkmode="true"] .vt-app { @container vt (max-width: 699px) { .vt-app .vt-layout-btn span { display: none; } } .vt-app .vt-editbar { - position: sticky; top: calc(var(--v-stick-top, 48px) + 8px); z-index: 6; + position: sticky; top: calc(var(--v-stick-top, 48px) + 8px); z-index: var(--vt-z-float); display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; - margin: 0 0 14px; padding: 12px 14px; border-radius: var(--vt-r-lg); + margin: 0 0 var(--vt-sp-4); padding: 12px 14px; border-radius: var(--vt-r-lg); border: 1px solid var(--vt-accent-line); background: var(--vt-surface); box-shadow: var(--vt-shadow); } .vt-app .vt-editbar[hidden] { display: none; } .vt-app .vt-editbar-text { display: flex; flex-direction: column; gap: 2px; flex: 1 1 260px; min-width: 0; } -.vt-app .vt-editbar-text strong { font-size: var(--vt-fs-base); font-weight: 650; } +.vt-app .vt-editbar-text strong { font-size: var(--vt-fs-base); font-weight: var(--vt-fw-semibold); } .vt-app .vt-edit-hidden { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; } .vt-app .vt-edit-hidden:empty { display: none; } -.vt-app .vt-edit-hidden .vt-fchip .vt-ico { width: 13px; height: 13px; } +.vt-app .vt-edit-hidden .vt-fchip .vt-ico { width: 12px; height: 12px; } .vt-app .vt-editbar-actions { display: flex; gap: 8px; margin-left: auto; } /* the chart and network path picks wrap as one group */ .vt-app .vt-edit-picks { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 10px 16px; min-width: 0; } @@ -361,8 +412,8 @@ 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); } -/* focused or open: the ring of the app's other fields (filter, rename) */ -.vt-app .vt-select:focus { outline: none; border-color: var(--vt-accent-line); box-shadow: 0 0 0 3px var(--vt-accent-soft); } +/* focused or open: the theme's field focus, as the app's other fields (filter, rename) */ +.vt-app .vt-select:focus { outline: none; border-color: var(--vt-focus); box-shadow: var(--vt-focus-ring); } /* 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) { @@ -372,15 +423,15 @@ html[data-darkmode="true"] .vt-app { .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; + margin: 4px 0; padding: var(--vt-sp-1); 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); + background: var(--vt-pop); 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; + min-height: calc(var(--vt-ctl) - 4px); padding: 4px 8px; gap: 8px; + border-radius: var(--vt-r-sm); font-size: var(--vt-fs-base); font-weight: var(--vt-fw-regular); cursor: pointer; } - .vt-app .vt-select:open { outline: none; border-color: var(--vt-accent-line); box-shadow: 0 0 0 3px var(--vt-accent-soft); } + .vt-app .vt-select:open { outline: none; border-color: var(--vt-focus); box-shadow: var(--vt-focus-ring); } /* below the field when it fits, as the theme's dropdowns open; the browser's default opens toward the larger space, often upward */ .vt-app .vt-select::picker(select) { position-try-order: normal; } @@ -388,11 +439,11 @@ html[data-darkmode="true"] .vt-app { and the accent bar, as the theme's dropdowns mark them. Opened with the pointer, the chosen option has :focus without :focus-visible: unmarked, so it no longer looks like a second row under the pointer */ - .vt-app .vt-select option:is(:hover, :focus-visible) { background: var(--vt-surface-3); } + .vt-app .vt-select option:checked { color: var(--vt-accent-text); font-weight: var(--vt-fw-semibold); background: var(--vt-accent-soft); } + .vt-app .vt-select option:is(:hover, :focus-visible) { background: var(--vt-pop-hover); color: var(--vt-text); } .vt-app .vt-select option:focus-visible { box-shadow: inset 2px 0 0 var(--vt-accent-text); } .vt-app .vt-select option:focus { outline: none; } - .vt-app .vt-select option:checked { font-weight: 600; } - .vt-app .vt-select option::checkmark { color: var(--vt-accent-text); } + .vt-app .vt-select option::checkmark { display: none; } } @container vt (max-width: 699px) { .vt-app .vt-editbar { padding: 8px 8px 8px 12px; gap: 8px; } @@ -407,7 +458,7 @@ html[data-darkmode="true"] .vt-app { .vt-app.vt-editing .vt-cell { padding-top: calc(var(--vt-ovh, 50px) + 16px); } .vt-app.vt-editing .vt-cell > .vt-tile-head { display: none; } .vt-app.vt-editing .vt-ov { - display: block; position: absolute; inset: 0; z-index: 4; + display: block; position: absolute; inset: 0; z-index: var(--vt-z-over); border: 2px dashed var(--vt-accent-line); border-radius: var(--vt-r-lg); background: color-mix(in oklab, var(--vt-surface) 55%, transparent); } @@ -416,7 +467,7 @@ html[data-darkmode="true"] .vt-app { margin: 8px; padding: 6px; border-radius: var(--vt-r-sm); background: var(--vt-surface); border: 1px solid var(--vt-line-2); box-shadow: var(--vt-shadow); } -.vt-app .vt-ov-name { flex: 1 1 auto; min-width: 0; font-weight: 650; font-size: var(--vt-fs-base); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.vt-app .vt-ov-name { flex: 1 1 auto; min-width: 0; font-weight: var(--vt-fw-semibold); font-size: var(--vt-fs-base); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .vt-app .vt-ov-btns { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; } .vt-app .vt-ov-grip, .vt-app .vt-ov-btn { display: inline-flex; align-items: center; justify-content: center; flex: none; @@ -430,7 +481,7 @@ html[data-darkmode="true"] .vt-app { .vt-app .vt-ov-grip .vt-ico { stroke-width: 3.2; } .vt-app .vt-ov-flip .vt-ico { transform: scaleX(-1); } .vt-app .vt-ov-hide { margin-left: 4px; } -.vt-app .vt-ov-size { min-width: 26px; text-align: center; font-size: var(--vt-fs-micro); font-weight: 650; color: var(--vt-text-2); } +.vt-app .vt-ov-size { min-width: 26px; text-align: center; font-size: var(--vt-fs-micro); font-weight: var(--vt-fw-semibold); color: var(--vt-text-2); } .vt-app.vt-edit-1col .vt-ov-col { display: none; } /* a narrow tile's bar: two rows at most (the name, then the controls), not three; no ‹ ›, drag and the arrow keys on the grip still move it */ @@ -439,7 +490,7 @@ html[data-darkmode="true"] .vt-app { @container vtcell (max-width: 340px) { .vt-app .vt-ov-lr { display: none; } } .vt-app.vt-editing .vt-cell { transition: top .2s ease, left .2s ease; } -.vt-app .vt-cell.vt-dragging { z-index: 8; transition: none; opacity: .92; box-shadow: 0 18px 40px rgba(0, 0, 0, .28); } +.vt-app .vt-cell.vt-dragging { z-index: var(--vt-z-drag); transition: none; opacity: .92; box-shadow: var(--vt-shadow-pop); } .vt-app .vt-dragging .vt-ov-grip { cursor: grabbing; } .vt-app.vt-drag-on { user-select: none; -webkit-user-select: none; } @@ -450,7 +501,7 @@ html[data-darkmode="true"] .vt-app { border: 1px solid var(--vt-line); border-radius: var(--vt-r-lg); box-shadow: var(--vt-shadow); - padding: 16px 18px 18px; + padding: var(--vt-card-py) var(--vt-card-px); } .vt-app .vt-tile-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; @@ -458,10 +509,10 @@ html[data-darkmode="true"] .vt-app { } .vt-app .vt-tile-title { display: inline-flex; align-items: center; gap: 8px; min-width: 0; - font-size: var(--vt-fs-base); font-weight: 650; letter-spacing: .005em; color: var(--vt-text); + font-size: var(--vt-fs-base); font-weight: var(--vt-fw-semibold); letter-spacing: .005em; color: var(--vt-text); white-space: nowrap; } -.vt-app .vt-tile-title .vt-ico { color: var(--vt-text-3); width: 17px; height: 17px; } +.vt-app .vt-tile-title .vt-ico { color: var(--vt-text-3); width: 16px; height: 16px; } .vt-app .vt-tile-extra { display: flex; align-items: center; gap: 8px; min-width: 0; } /* folding: phones only; wider layouts show everything and ignore the state */ @@ -478,8 +529,6 @@ html[data-darkmode="true"] .vt-app { .vt-app .vt-folded > :not(.vt-tile-head):not(.vt-fold-keep) { display: none !important; } .vt-app .vt-folded > .vt-tile-head { margin-bottom: 0; } .vt-app .vt-folded.vt-hero > .vt-tile-head { margin-bottom: 2px; } - .vt-app .vt-folded.vt-hero .vt-kpis { margin-top: 4px; } - .vt-app .vt-hint-wide { display: none; } /* radios become one tile: a head, then condensed rows or flat cards */ .vt-app .vt-radios { @@ -495,11 +544,11 @@ html[data-darkmode="true"] .vt-app { .vt-app .vt-rsum { display: flex; align-items: center; gap: 8px; width: 100%; min-height: 44px; padding: 8px 2px; margin: 0; border: 0; border-top: 1px solid var(--vt-line); border-radius: 0; background: transparent; box-shadow: none; - color: var(--vt-text); text-align: left; cursor: pointer; font-weight: 400; + color: var(--vt-text); text-align: left; cursor: pointer; font-weight: var(--vt-fw-regular); } -.vt-app .vt-rsum:hover { background: var(--vt-surface-2); } +.vt-app .vt-rsum:hover { background: var(--vt-hover); } .vt-app .vt-rsum .vt-status { margin: 0; } -.vt-app .vt-rsum-main { font-weight: 650; font-size: var(--vt-fs-base); white-space: nowrap; } +.vt-app .vt-rsum-main { font-weight: var(--vt-fw-semibold); font-size: var(--vt-fs-base); white-space: nowrap; } .vt-app .vt-rsum-sub { font-size: var(--vt-fs-sm); color: var(--vt-text-3); white-space: nowrap; } .vt-app .vt-rsum-rate { margin-left: auto; font-size: var(--vt-fs-sm); color: var(--vt-text-2); white-space: nowrap; } .vt-app .vt-rsum > .vt-ico { color: var(--vt-text-3); } @@ -508,8 +557,8 @@ html[data-darkmode="true"] .vt-app { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; padding: 32px 16px; text-align: center; color: var(--vt-text-3); } -.vt-app .vt-empty > .vt-ico { width: 28px; height: 28px; stroke-width: 1.4; margin-bottom: 4px; } -.vt-app .vt-empty-title { color: var(--vt-text); font-weight: 620; font-size: var(--vt-fs-md); } +.vt-app .vt-empty > .vt-ico { width: 28px; height: 28px; stroke-width: 1.7; margin-bottom: 4px; } +.vt-app .vt-empty-title { color: var(--vt-text); font-weight: var(--vt-fw-semibold); font-size: var(--vt-fs-md); } .vt-app .vt-empty .vt-btn { margin-top: 8px; } .vt-app .vt-empty-inline { color: var(--vt-text-3); font-size: var(--vt-fs-sm); padding: 4px 0; } @@ -517,7 +566,7 @@ html[data-darkmode="true"] .vt-app { .vt-app .vt-head { display: flex; align-items: center; gap: 14px; - margin: 2px 0 14px; + margin: 2px 0 var(--vt-sp-4); } header::after { height:0 !important; @@ -532,11 +581,12 @@ h2, h3{ --vt-oc: var(--vt-ok); background: color-mix(in oklab, var(--vt-oc) 16%, transparent); } +/* the ring pulses only while something needs attention */ .vt-app .vt-orb::after { content: ""; position: absolute; inset: 0; border-radius: 50%; border: 2px solid var(--vt-oc); opacity: .35; - animation: vt-ring 2.6s ease-out infinite; } +.vt-app .vt-orb-warn::after, .vt-app .vt-orb-err::after { animation: vt-ring 2.6s ease-out infinite; } .vt-app .vt-orb-core { width: 14px; height: 14px; border-radius: 50%; background: var(--vt-oc); box-shadow: 0 0 0 4px color-mix(in oklab, var(--vt-oc) 22%, transparent); } .vt-app .vt-orb-warn { --vt-oc: var(--vt-warn); } .vt-app .vt-orb-err { --vt-oc: var(--vt-err); } @@ -544,7 +594,7 @@ h2, h3{ .vt-app .vt-head-text { min-width: 0; flex: 1; } .vt-app .vt-headline { - font-size: var(--vt-fs-xl); font-weight: 680; letter-spacing: -.015em; line-height: 1.2; color: var(--vt-text); + font-size: var(--vt-fs-xl); font-weight: var(--vt-fw-bold); letter-spacing: -.015em; line-height: 1.2; color: var(--vt-text); margin: 0; padding: 0; border: 0; text-transform: none; } .vt-app .vt-subline { color: var(--vt-text-3); font-size: var(--vt-fs-sm); margin-top: 2px; } @@ -553,26 +603,26 @@ h2, h3{ flex: none; display: inline-flex; align-items: center; gap: 8px; isolation: isolate; height: 30px; padding: 0 12px 0 10px; border-radius: 999px; border: 1px solid var(--vt-line); background: var(--vt-surface); - font-size: var(--vt-fs-sm); font-weight: 560; color: var(--vt-text-2); white-space: nowrap; + font-size: var(--vt-fs-sm); font-weight: var(--vt-fw-medium); color: var(--vt-text-2); white-space: nowrap; } .vt-app .vt-live-beat { position: relative; width: 8px; height: 8px; border-radius: 50%; background: var(--vt-beat-c, var(--vt-ok)); } /* the beat is a ring that scales and fades (compositor only; an animated - box-shadow repainted every frame). It sits behind the dot (z-index -1 in - the pill's stacking context) so the dot keeps its colour, and it is - transparent unless the animation runs: nothing shows without motion. */ + box-shadow repainted every frame), only while reconnecting: a live page + keeps a still dot. It sits behind the dot (z-index -1 in the pill's + stacking context) so the dot keeps its colour, and it is transparent + unless the animation runs: nothing shows without motion. */ .vt-app .vt-live-beat::after { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: 50%; background: color-mix(in oklab, var(--vt-beat-c, var(--vt-ok)) 45%, transparent); opacity: 0; - animation: vt-beat 2s ease-out infinite; } .vt-app .vt-live-paused .vt-live-beat { --vt-beat-c: var(--vt-text-3); } -.vt-app .vt-live-paused .vt-live-beat::after { animation: none; } .vt-app .vt-live-err .vt-live-beat { --vt-beat-c: var(--vt-warn); } +.vt-app .vt-live-err .vt-live-beat::after { animation: vt-beat 2s ease-out infinite; } @keyframes vt-beat { 0% { transform: scale(1); opacity: 1; } 70%, 100% { transform: scale(2.75); opacity: 0; } } .vt-app .vt-health { - display: grid; gap: 10px; margin-bottom: 14px; + display: grid; gap: 10px; margin-bottom: var(--vt-sp-4); grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); } @container vt (min-width: 700px) { .vt-app .vt-health { grid-template-columns: repeat(3, minmax(0, 1fr)); } } @@ -593,16 +643,66 @@ h2, h3{ .vt-app .vt-chip-warn { --vt-cc: var(--vt-warn); background: color-mix(in oklab, var(--vt-warn) 7%, var(--vt-surface)); border-color: color-mix(in oklab, var(--vt-warn) 35%, var(--vt-line)); } .vt-app .vt-chip-err { --vt-cc: var(--vt-err); background: color-mix(in oklab, var(--vt-err) 7%, var(--vt-surface)); border-color: color-mix(in oklab, var(--vt-err) 35%, var(--vt-line)); } .vt-app .vt-chip-info { --vt-cc: var(--vt-text-3); } +/* the check's own icon, in the card's top right corner so the text + runs from its left edge: plain while all is well, in the level's + colour when it needs attention */ .vt-app .vt-chip-ico { - flex: none; width: 26px; height: 26px; border-radius: 8px; + flex: none; width: 26px; height: 26px; border-radius: var(--vt-r); display: inline-flex; align-items: center; justify-content: center; - background: color-mix(in oklab, var(--vt-cc) 15%, transparent); color: var(--vt-cc); + background: var(--vt-surface-2); color: var(--vt-text-3); } -.vt-app .vt-chip-ico .vt-ico { width: 15px; height: 15px; stroke-width: 2.1; } -.vt-app .vt-chip-main { display: flex; flex-direction: column; min-width: 0; flex: 1; } +/* (the health cards only: Firewall -> Overview's warnings share .vt-chip + and keep their icon before the title) */ +.vt-app .vt-health .vt-chip-ico { position: absolute; top: 10px; right: 10px; } +.vt-app .vt-health .vt-chip-top { padding-right: 30px; } +.vt-app :is(.vt-chip-warn, .vt-chip-err) .vt-chip-ico { background: color-mix(in oklab, var(--vt-cc) 15%, transparent); color: var(--vt-cc); } +.vt-app .vt-chip-ico .vt-ico { width: 16px; height: 16px; stroke-width: 1.7; } +.vt-app .vt-health .vt-chip { align-self: stretch; position: relative; overflow: hidden; } +.vt-app .vt-chip-main { display: flex; flex-direction: column; min-width: 0; flex: 1; align-self: stretch; } +/* The picture is part of the card, on its bottom edge from border to + border: an area for what moves (uplink, CPU), under room the card + keeps for it, and a 3 px line for what fills (memory, storage, the + clients' signals). Each radio's airtime stays in the text, labelled. */ +.vt-app .vt-chip-viz { position: absolute; left: 0; right: 0; bottom: 0; display: block; pointer-events: none; } +.vt-app .vt-chip-viz:empty { display: none; } +.vt-app .vt-chip:is(.vt-chip-k-uplink, .vt-chip-k-cpu) { padding-bottom: 40px; } +.vt-app .vt-chip-viz .vt-sk { height: 34px; } +.vt-app .vt-chip-viz .vt-spark { height: 34px; } +.vt-app .vt-chip-viz .vt-spark-line { stroke-width: 1.5; } +.vt-app .vt-chip-viz .vt-sk { --vt-fill-op: .22; } +.vt-app .vt-chip-k-radios .vt-chip-viz:has(.vt-chip-radios) { position: static; margin-top: auto; padding-top: 10px; } +.vt-app .vt-chip-band.vt-band-2g { background: var(--vt-b2); } +.vt-app .vt-chip-band.vt-band-5g { background: var(--vt-b5); } +.vt-app .vt-chip-band.vt-band-6g { background: var(--vt-b6); } +.vt-app .vt-chip-band { background: var(--vt-text-3); } +.vt-app .vt-chip-bar, .vt-app .vt-bar.vt-chip-bar { display: block; height: 3px; border-radius: 0; } +.vt-app .vt-chip-k-radios .vt-chip-bar.vt-bar { height: 4px; border-radius: var(--vt-r-xs); } +.vt-app .vt-chip-k-radios .vt-chip-bar .vt-bar-fill { border-radius: var(--vt-r-xs); } +.vt-app :is(.vt-chip-k-memory, .vt-chip-k-storage) .vt-chip-bar { background: color-mix(in oklab, var(--vt-line) 70%, transparent); } +.vt-app :is(.vt-chip-k-memory, .vt-chip-k-storage) .vt-chip-bar .vt-bar-fill { border-radius: 0; } +.vt-app .vt-chip-mem { display: flex; gap: 1px; overflow: hidden; } +.vt-app .vt-chip-mem > span { display: block; height: 100%; } +.vt-app .vt-chip-mem-used { background: var(--vt-meter); } +.vt-app .vt-chip-mem-cache { background: color-mix(in oklab, var(--vt-meter) 35%, var(--vt-surface-3)); } +.vt-app .vt-chip-mem-warn .vt-chip-mem-used { background: var(--vt-warn); } +.vt-app .vt-chip-mem-err .vt-chip-mem-used { background: var(--vt-err); } +/* two to a row: up to two radios stay one line, four make two */ +.vt-app .vt-chip-radios { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 5px 8px; } +.vt-app .vt-chip-radio { min-width: 0; display: flex; flex-direction: column; gap: 3px; } +.vt-app .vt-chip-radio-top { display: flex; flex-wrap: wrap; justify-content: space-between; column-gap: 4px; font-size: var(--vt-fs-micro); line-height: 1.2; color: var(--vt-text-3); white-space: nowrap; } +.vt-app .vt-chip-radio-top b { color: var(--vt-text-2); font-weight: var(--vt-fw-semibold); } +.vt-app .vt-chip-radio.vt-band-2g .vt-bar-fill { background: var(--vt-b2); } +.vt-app .vt-chip-radio.vt-band-5g .vt-bar-fill { background: var(--vt-b5); } +.vt-app .vt-chip-radio.vt-band-6g .vt-bar-fill { background: var(--vt-b6); } +.vt-app .vt-chip-dist { display: flex; gap: 2px; height: 3px; } +.vt-app .vt-chip-dist > span { flex: 0 1 auto; min-width: 4px; } +.vt-app .vt-dist-4 { background: var(--vt-ok); } +.vt-app .vt-dist-3 { background: color-mix(in oklab, var(--vt-ok) 55%, var(--vt-surface-3)); } +.vt-app .vt-dist-2 { background: var(--vt-warn); } +.vt-app .vt-dist-1 { background: var(--vt-err); } .vt-app .vt-chip-top { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; } -.vt-app .vt-chip-title { font-size: var(--vt-fs-micro); line-height: 1.3; font-weight: 650; color: var(--vt-text-3); text-transform: uppercase; letter-spacing: .05em; } -.vt-app .vt-chip-value { font-size: var(--vt-fs-md); font-weight: 700; letter-spacing: -.01em; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; } +.vt-app .vt-chip-title { font-size: var(--vt-fs-micro); line-height: 1.3; font-weight: var(--vt-fw-semibold); color: var(--vt-text-3); text-transform: uppercase; letter-spacing: .08em; } +.vt-app .vt-chip-value { font-size: var(--vt-fs-md); font-weight: var(--vt-fw-bold); letter-spacing: -.01em; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; } .vt-app .vt-chip-reason { font-size: var(--vt-fs-sm); color: var(--vt-text-2); margin-top: 2px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; @@ -612,27 +712,6 @@ h2, h3{ .vt-app .vt-hero { container: vthero vtcell / inline-size; overflow: hidden; display: flex; flex-direction: column; } -.vt-app .vt-kpis { - position: relative; z-index: 1; - display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; - margin-top: 10px; padding-top: 14px; border-top: 1px solid var(--vt-line); -} -.vt-app .vt-kpi { - display: flex; flex-direction: column; align-items: flex-start; gap: 1px; min-width: 0; - padding: 6px 10px; margin: 0; border: 0; border-radius: var(--vt-r-sm); - background: transparent; color: var(--vt-text); text-align: left; box-shadow: none; height: auto; text-transform: none; font-weight: 400; -} -.vt-app button.vt-kpi { cursor: pointer; } -.vt-app button.vt-kpi:hover { background: var(--vt-surface-2); } -.vt-app .vt-kpi + .vt-kpi { box-shadow: -1px 0 0 var(--vt-line); border-radius: 0 var(--vt-r-sm) var(--vt-r-sm) 0; } -.vt-app .vt-kpi-label { font-size: var(--vt-fs-micro); font-weight: 650; color: var(--vt-text-3); text-transform: uppercase; letter-spacing: .05em; } -.vt-app .vt-kpi-value { font-size: var(--vt-fs-xl); font-weight: 700; letter-spacing: -.02em; line-height: 1.2; white-space: nowrap; } -.vt-app .vt-kpi-sub { max-width: 100%; font-size: var(--vt-fs-sm); color: var(--vt-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.vt-app .vt-kpi-warn .vt-kpi-value { color: var(--vt-warn); } -@container vthero (max-width: 700px) { - .vt-app .vt-kpis { grid-template-columns: 1fr 1fr; } - .vt-app .vt-kpi:nth-child(3) { box-shadow: none; } -} .vt-app .vt-hero::before { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; background: @@ -673,51 +752,54 @@ h2, h3{ .vt-app .vt-fwire-3 .vt-fdot { left: -2.25px; top: -1.5px; width: 4.5px; height: 3px; border-radius: 1.5px; } .vt-app .vt-node { - position: relative; z-index: 1; + position: relative; z-index: var(--vt-z-raised); display: flex; align-items: center; gap: 10px; min-width: 0; - padding: 9px 11px; margin: 0; + padding: 8px 12px; margin: 0; border: 1px solid var(--vt-line); border-radius: var(--vt-r); background: var(--vt-surface); color: var(--vt-text); box-shadow: var(--vt-shadow); - text-align: left; cursor: pointer; height: auto; line-height: 1.3; text-transform: none; font-weight: 400; + text-align: left; cursor: pointer; height: auto; line-height: 1.3; text-transform: none; font-weight: var(--vt-fw-regular); transition: border-color .15s, transform .15s, box-shadow .15s; } -.vt-app .vt-node:hover { border-color: color-mix(in oklab, var(--vt-accent-line) 60%, var(--vt-line)); transform: translateY(-1px); box-shadow: 0 6px 16px rgba(12, 14, 17, .08); background: var(--vt-surface); } +.vt-app .vt-node:hover { border-color: color-mix(in oklab, var(--vt-accent-line) 60%, var(--vt-line)); transform: translateY(-1px); box-shadow: var(--vt-shadow-raise); background: var(--vt-surface); } .vt-app .vt-node-body { display: flex; flex-direction: column; min-width: 0; gap: 1px; } -.vt-app .vt-node-kicker { display: flex; align-items: center; gap: 6px; font-size: var(--vt-fs-micro); font-weight: 600; color: var(--vt-text-3); text-transform: uppercase; letter-spacing: .05em; white-space: nowrap; } -.vt-app .vt-node-title { font-size: var(--vt-fs-base); font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.vt-app .vt-node-kicker { display: flex; align-items: center; gap: 6px; font-size: var(--vt-fs-micro); font-weight: var(--vt-fw-semibold); color: var(--vt-text-3); text-transform: uppercase; letter-spacing: .08em; white-space: nowrap; } +.vt-app .vt-node-title { font-size: var(--vt-fs-base); font-weight: var(--vt-fw-semibold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .vt-app .vt-node-sub { display: flex; align-items: center; gap: 6px; font-size: var(--vt-fs-sm); color: var(--vt-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* text alone (the gateway's DNS): a block, so the ellipsis can show */ .vt-app .vt-node-sub:not(:has(> *)) { display: block; } .vt-app .vt-node-ico { - flex: none; width: 32px; height: 32px; border-radius: 9px; + flex: none; width: 32px; height: 32px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; background: var(--vt-surface-3); color: var(--vt-text-2); } .vt-app .vt-node-ico .vt-ico { width: 20px; height: 20px; } .vt-app .vt-node-gw { justify-self: stretch; align-self: center; } -.vt-app .vt-node-ap { justify-self: stretch; align-self: center; padding: 12px 13px; border-color: color-mix(in oklab, var(--vt-accent-line) 40%, var(--vt-line)); } -.vt-app .vt-node-ap .vt-node-ico { background: var(--vt-accent); color: var(--vt-accent-ink); } +.vt-app .vt-node-ap { justify-self: stretch; align-self: center; padding: 12px; border-color: color-mix(in oklab, var(--vt-accent-line) 40%, var(--vt-line)); } +.vt-app .vt-node-ap .vt-node-ico { background: var(--vt-accent-fill); color: var(--vt-accent-fill-ink); } .vt-app .vt-node-ap .vt-node-title { font-size: var(--vt-fs-md); } -.vt-app .vt-node-gen { text-transform: none; letter-spacing: 0; font-weight: 560; } -.vt-app .vt-node-radio { padding: 8px 11px; } +.vt-app .vt-node-gen { text-transform: none; letter-spacing: 0; font-weight: var(--vt-fw-medium); } +.vt-app .vt-node-radio { padding: 8px 12px; } .vt-app .vt-node-net, .vt-app .vt-node-net:hover { text-decoration: none; color: var(--vt-text); } -.vt-app .vt-node-ssid { padding: 7px 10px; } +.vt-app .vt-node-ssid { padding: 6px 10px; } .vt-app .vt-node-ssid .vt-node-title { display: flex; align-items: center; gap: 6px; font-size: var(--vt-fs-base); } -.vt-app .vt-node-ssid .vt-node-title .vt-ico { color: var(--vt-text-3); } +/* only an open or weak network carries a lock */ +.vt-app .vt-node-ssid .vt-node-title .vt-ico { color: var(--vt-warn); } .vt-app .vt-ssid-name span { overflow: hidden; text-overflow: ellipsis; } .vt-app .vt-node-idle { background: var(--vt-surface-2); box-shadow: none; } -.vt-app .vt-node-idle .vt-node-title { color: var(--vt-text-2); font-weight: 600; } +.vt-app .vt-node-idle .vt-node-title { color: var(--vt-text-2); font-weight: var(--vt-fw-semibold); } .vt-app .vt-node-off { opacity: .6; border-style: dashed; } .vt-app .vt-dots { display: inline-flex; gap: 3px; } +/* no clients, no dots: the count starts where the name does */ +.vt-app .vt-dots:empty { display: none; } .vt-app .vt-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--vt-text-3); } .vt-app .vt-dot.vt-lvl-ok { background: var(--vt-ok); } .vt-app .vt-dot.vt-lvl-warn { background: var(--vt-warn); } .vt-app .vt-dot.vt-lvl-crit { background: var(--vt-err); } .vt-app .vt-link-label { - position: relative; z-index: 1; + position: relative; z-index: var(--vt-z-raised); display: grid; grid-template-rows: minmax(0, 1fr) 14px minmax(0, 1fr); justify-items: center; align-self: stretch; padding: 0 6px; text-align: center; } @@ -726,13 +808,13 @@ h2, h3{ display: inline-flex; align-items: baseline; gap: 3px; white-space: nowrap; padding: 0 6px; border-radius: 6px; background: var(--vt-surface); } -.vt-app .vt-link-rate .vt-ico { width: 13px; height: 13px; align-self: center; stroke-width: 2.2; } -.vt-app .vt-link-rate b { font-size: var(--vt-fs-lg); font-weight: 700; letter-spacing: -.01em; } -.vt-app .vt-link-rate small { font-size: var(--vt-fs-micro); color: var(--vt-text-3); font-weight: 600; } +.vt-app .vt-link-rate .vt-ico { width: 12px; height: 12px; align-self: center; stroke-width: 2; } +.vt-app .vt-link-rate b { font-size: var(--vt-fs-lg); font-weight: var(--vt-fw-bold); letter-spacing: -.01em; } +.vt-app .vt-link-rate small { font-size: var(--vt-fs-micro); color: var(--vt-text-3); font-weight: var(--vt-fw-semibold); } .vt-app .vt-link-down { grid-row: 1; align-self: end; } .vt-app .vt-link-down .vt-ico { color: var(--vt-accent-text); } .vt-app .vt-link-up { font-size: var(--vt-fs-sm); } -.vt-app .vt-link-up b { font-size: var(--vt-fs-base); font-weight: 650; color: var(--vt-text-2); } +.vt-app .vt-link-up b { font-size: var(--vt-fs-base); font-weight: var(--vt-fw-semibold); color: var(--vt-text-2); } .vt-app .vt-link-up .vt-ico { color: var(--vt-text-3); } .vt-app .vt-link-meta { font-size: var(--vt-fs-micro); color: var(--vt-text-3); font-family: var(--vt-mono); white-space: nowrap; margin-top: 2px; padding: 0 6px; border-radius: 6px; background: var(--vt-surface); } @@ -741,7 +823,7 @@ h2, h3{ tall neighbour leaves no empty band above or below the diagram */ .vt-app .vt-branches { display: flex; flex-direction: column; justify-content: space-between; gap: 18px; padding: 2px 0 2px 34px; min-width: 0; } .vt-app .vt-branch { display: grid; grid-template-columns: minmax(136px, 172px) minmax(0, 1fr); column-gap: 34px; align-items: center; min-width: 0; } -.vt-app .vt-branch-ssids { display: flex; flex-direction: column; gap: 7px; min-width: 0; } +.vt-app .vt-branch-ssids { display: flex; flex-direction: column; gap: var(--vt-sp-2); min-width: 0; } .vt-app .vt-branch-ssids .vt-node { max-width: 260px; } @container vthero (max-width: 700px) { @@ -770,41 +852,47 @@ h2, h3{ .vt-app .vt-spark-box .vt-spark { height: 38px; } .vt-app .vt-cores-box { display: flex; flex-direction: column; align-items: center; flex: none; cursor: help; } .vt-app .vt-cores { display: flex; gap: 3px; height: 38px; align-items: flex-end; } -.vt-app .vt-core { position: relative; width: 6px; height: 100%; border-radius: 3px; background: var(--vt-surface-3); overflow: hidden; } -.vt-app .vt-core-fill { position: absolute; left: 0; right: 0; bottom: 0; border-radius: 3px; background: var(--vt-chart-5); } +.vt-app .vt-core { position: relative; width: 6px; height: 100%; border-radius: var(--vt-r-xs); background: var(--vt-surface-3); overflow: hidden; } +.vt-app .vt-core-fill { position: absolute; left: 0; right: 0; bottom: 0; border-radius: var(--vt-r-xs); background: var(--vt-chart-5); } .vt-app .vt-sys-mem { display: flex; flex-direction: column; gap: 7px; } .vt-app .vt-mem-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; flex-wrap: wrap; } -.vt-app .vt-mem-avail { font-size: var(--vt-fs-lg); font-weight: 680; } -.vt-app .vt-mem-of { font-size: var(--vt-fs-sm); color: var(--vt-text-3); } -.vt-app .vt-seg { display: flex; height: 12px; border-radius: 6px; overflow: hidden; background: var(--vt-surface-3); gap: 2px; } +/* the meters as the theme's (Status -> Overview): a squared bar with a + hairline ring, segments split by a line of the card, blue fills; the + share in tabular sans, the amounts in monospace */ +.vt-app .vt-mem-avail { font-size: var(--vt-fs-lg); font-weight: var(--vt-fw-bold); } +.vt-app .vt-mem-of { font-family: var(--vt-mono); font-size: var(--vt-fs-sm); color: var(--vt-text-2); white-space: nowrap; } +.vt-app .vt-seg { display: flex; height: 12px; border-radius: var(--vt-r-xs); overflow: hidden; background: var(--vt-surface-3); box-shadow: inset 0 0 0 1px var(--vt-line); } /* width animates only for a visible change (the view sets .vt-seg-move): a width transition lays out every frame, and memory moves by fractions of a percent on most polls */ .vt-app .vt-seg-part { height: 100%; min-width: 0; } +.vt-app .vt-seg-part + .vt-seg-part { box-shadow: inset 1px 0 0 var(--vt-surface); } .vt-app .vt-seg-move .vt-seg-part { transition: width .7s cubic-bezier(.2, .7, .2, 1); } -.vt-app .vt-seg-used { background: var(--vt-mem); border-radius: 6px 2px 2px 6px; } +.vt-app .vt-seg-used { background: var(--vt-meter); } .vt-app .vt-seg-cache { background: - repeating-linear-gradient(135deg, color-mix(in oklab, var(--vt-mem) 42%, transparent) 0 3px, color-mix(in oklab, var(--vt-mem) 24%, transparent) 3px 6px); - border-radius: 2px; + repeating-linear-gradient(-45deg, color-mix(in srgb, var(--vt-meter) 55%, transparent) 0 3px, color-mix(in srgb, var(--vt-meter) 25%, transparent) 3px 6px); } .vt-app .vt-seg-free { background: transparent; } .vt-app .vt-legend { display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: var(--vt-fs-sm); color: var(--vt-text-2); } .vt-app .vt-legend-item { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; } -.vt-app .vt-legend-item b { font-weight: 650; color: var(--vt-text); } -.vt-app .vt-key { width: 10px; height: 10px; border-radius: 3px; flex: none; } +.vt-app .vt-legend-item b { font-family: var(--vt-mono); font-weight: var(--vt-fw-semibold); color: var(--vt-text); } +.vt-app .vt-key { width: 10px; height: 10px; border-radius: var(--vt-r-xs); flex: none; } .vt-app .vt-key.vt-seg-free { background: var(--vt-surface-3); box-shadow: inset 0 0 0 1px var(--vt-line-2); } .vt-app .vt-swap { display: flex; align-items: center; gap: 8px; font-size: var(--vt-fs-sm); } .vt-app .vt-swap:empty { display: none; } -.vt-app .vt-thin { flex: 1; height: 4px; border-radius: 2px; background: var(--vt-surface-3); overflow: hidden; } -.vt-app .vt-thin-fill { display: block; height: 100%; background: var(--vt-mem); } +.vt-app .vt-thin { flex: 1; height: 4px; border-radius: var(--vt-r-xs); background: var(--vt-surface-3); overflow: hidden; box-shadow: inset 0 0 0 1px var(--vt-line); } +.vt-app .vt-thin-fill { display: block; height: 100%; background: var(--vt-meter); } .vt-app .vt-sys-store { display: flex; flex-direction: column; gap: 8px; } .vt-app .vt-storage { display: flex; flex-direction: column; gap: 8px; } -.vt-app .vt-mount-top { display: flex; justify-content: space-between; gap: 8px; font-size: var(--vt-fs-sm); margin-bottom: 4px; } -.vt-app .vt-bar { height: 6px; border-radius: 3px; background: var(--vt-surface-3); overflow: hidden; } -.vt-app .vt-bar-fill { display: block; height: 100%; border-radius: 3px; background: var(--vt-mem); } +/* a narrow tile puts the amounts on a line of their own, whole */ +.vt-app .vt-mount-top { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 2px 8px; font-size: var(--vt-fs-sm); margin-bottom: 4px; } +.vt-app .vt-mount-top .vt-hint { margin-left: auto; font-family: var(--vt-mono); color: var(--vt-text-2); white-space: nowrap; } +.vt-app .vt-bar { height: 6px; border-radius: var(--vt-r-xs); background: var(--vt-surface-3); overflow: hidden; } +.vt-app .vt-storage .vt-bar { box-shadow: inset 0 0 0 1px var(--vt-line); } +.vt-app .vt-bar-fill { display: block; height: 100%; background: var(--vt-meter); } .vt-app .vt-bg-warn { background: var(--vt-warn); } .vt-app .vt-bg-err { background: var(--vt-err); } .vt-app .vt-fw { display: flex; flex-direction: column; gap: 1px; margin-top: auto; padding-top: 10px; border-top: 1px dashed var(--vt-line); font-size: var(--vt-fs-sm); color: var(--vt-text-2); } @@ -815,13 +903,13 @@ h2, h3{ a shared time axis and one crosshair across all rows */ .vt-app .vt-chart { display: flex; flex-direction: column; --vt-mh: 136px; --vt-mg: 16px; } .vt-app .vt-chart .vt-tile-title { flex-wrap: wrap; row-gap: 0; } -.vt-app .vt-chart-sub { font-size: var(--vt-fs-sm); font-weight: 500; color: var(--vt-text-3); } +.vt-app .vt-chart-sub { font-size: var(--vt-fs-sm); font-weight: var(--vt-fw-medium); color: var(--vt-text-3); } .vt-app .vt-chart-sub::before { content: "·"; margin: 0 6px 0 0; } -.vt-app .vt-lg-key { width: 12px; height: 3px; border-radius: 2px; background: var(--vt-sc); flex: none; } +.vt-app .vt-lg-key { width: 12px; height: 3px; border-radius: var(--vt-r-xs); background: var(--vt-sc); flex: none; } /* one colour per direction in every row (series, gradients, dots, keys) */ .vt-app .vt-chart, .vt-app .vt-chart .vt-k-dn { --vt-sc: var(--vt-dir-dn); } .vt-app .vt-chart .vt-dir-up, .vt-app .vt-chart .vt-k-up { --vt-sc: var(--vt-dir-up); } -.vt-app .vt-arr { font-weight: 700; } +.vt-app .vt-arr { font-weight: var(--vt-fw-bold); } .vt-app .vt-arr-dn { color: color-mix(in oklab, var(--vt-dir-dn) 70%, var(--vt-text)); } .vt-app .vt-arr-up { color: color-mix(in oklab, var(--vt-dir-up) 70%, var(--vt-text)); } .vt-app .vt-dir-legend { font-size: var(--vt-fs-micro); gap: 4px 12px; } @@ -834,12 +922,12 @@ h2, h3{ } .vt-app .vt-mult:first-child { border-top: 0; padding-top: 2px; } .vt-app .vt-mult-head { display: flex; flex-direction: column; justify-content: center; gap: 1px; min-width: 0; } -.vt-app .vt-mult-name { font-size: var(--vt-fs-micro); font-weight: 600; color: var(--vt-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.vt-app .vt-mult-now { display: flex; align-items: center; gap: 6px; font-size: var(--vt-fs-lg); font-weight: 700; letter-spacing: -.01em; line-height: 1.25; white-space: nowrap; } +.vt-app .vt-mult-name { font-size: var(--vt-fs-micro); font-weight: var(--vt-fw-semibold); color: var(--vt-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.vt-app .vt-mult-now { display: flex; align-items: center; gap: 6px; font-size: var(--vt-fs-lg); font-weight: var(--vt-fw-bold); letter-spacing: -.01em; line-height: 1.25; white-space: nowrap; } .vt-app .vt-mult-now b { font-weight: inherit; } -.vt-app .vt-mult-now-up { font-size: var(--vt-fs-base); font-weight: 650; line-height: 1.3; color: var(--vt-text-2); } +.vt-app .vt-mult-now-up { font-size: var(--vt-fs-base); font-weight: var(--vt-fw-semibold); line-height: 1.3; color: var(--vt-text-2); } .vt-app .vt-mult-stats { display: flex; flex-wrap: wrap; gap: 0 8px; font-size: var(--vt-fs-micro); color: var(--vt-text-3); white-space: nowrap; } -.vt-app .vt-mult-stats b { font-weight: 600; color: var(--vt-text-2); } +.vt-app .vt-mult-stats b { font-weight: var(--vt-fw-semibold); color: var(--vt-text-2); } .vt-app .vt-mult-plot { position: relative; min-height: 72px; margin: 12px 0; --vt-sc: inherit; } .vt-app .vt-mult-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; } .vt-app .vt-chart-grid { fill: none; stroke: var(--vt-chart-grid); stroke-width: 1; vector-effect: non-scaling-stroke; } @@ -857,11 +945,11 @@ h2, h3{ /* a stretch without samples: hatched, named when there's room */ .vt-app .vt-mult-gap { position: absolute; top: 0; bottom: 0; display: flex; align-items: center; justify-content: center; overflow: hidden; - border-radius: 3px; pointer-events: none; + border-radius: var(--vt-r-xs); pointer-events: none; background: repeating-linear-gradient(135deg, var(--vt-chart-grid) 0 2px, transparent 2px 6px); font-size: var(--vt-fs-micro); line-height: 1; color: var(--vt-chart-axis); white-space: nowrap; } -.vt-app .vt-mult-gap span { padding: 2px 4px; border-radius: 3px; background: var(--vt-surface); } +.vt-app .vt-mult-gap span { padding: 2px 4px; border-radius: var(--vt-r-xs); background: var(--vt-surface); } /* a band too narrow for its label shows the hatching alone */ .vt-app .vt-mult-gap { container-type: inline-size; } @container (max-width: 60px) { .vt-app .vt-mult-gap span { display: none; } } @@ -877,17 +965,17 @@ h2, h3{ .vt-app .vt-mult-wrap { cursor: crosshair; touch-action: pan-y; } .vt-app .vt-cursor { position: absolute; top: 0; bottom: 0; width: 0; border-left: 1px solid color-mix(in oklab, var(--vt-text) 45%, transparent); pointer-events: none; } .vt-app .vt-tip { - position: absolute; top: 4px; z-index: 4; - width: max-content; min-width: 180px; padding: 8px 10px 7px; border-radius: var(--vt-r); - background: var(--vt-surface); border: 1px solid var(--vt-line-2); - box-shadow: 0 10px 28px rgba(12, 14, 17, .16), 0 2px 6px rgba(12, 14, 17, .06); + position: absolute; top: 4px; z-index: var(--vt-z-over); + width: max-content; min-width: 180px; padding: 8px 10px; border-radius: var(--vt-r); + background: var(--vt-pop); border: 1px solid var(--vt-line-2); + box-shadow: var(--vt-shadow-pop); font-size: var(--vt-fs-sm); pointer-events: none; } .vt-app .vt-tip-time { display: flex; justify-content: space-between; gap: 12px; color: var(--vt-text-3); font-size: var(--vt-fs-micro); margin-bottom: 5px; padding-bottom: 5px; border-bottom: 1px solid var(--vt-line); } .vt-app .vt-tip-link + .vt-tip-link { margin-top: 5px; } .vt-app .vt-tip-label { color: var(--vt-text-3); font-size: var(--vt-fs-micro); white-space: nowrap; } .vt-app .vt-tip-row { display: grid; grid-template-columns: 12px auto minmax(0, 1fr); align-items: center; column-gap: 8px; line-height: 1.6; color: var(--vt-text-2); } -.vt-app .vt-tip-row b { font-weight: 700; color: var(--vt-text); white-space: nowrap; text-align: right; } +.vt-app .vt-tip-row b { font-weight: var(--vt-fw-bold); color: var(--vt-text); white-space: nowrap; text-align: right; } /* ------------------------------------------------------------ 8. radios */ @@ -900,8 +988,8 @@ h2, h3{ .vt-app .vt-radio::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px; background: var(--vt-bc); opacity: .85; } .vt-app .vt-radio-off { opacity: .75; } .vt-app .vt-radio-head { display: flex; align-items: center; gap: 8px; } -.vt-app .vt-radio-name { font-weight: 650; font-size: var(--vt-fs-base); } -.vt-app .vt-status { margin-left: auto; display: inline-flex; align-items: center; gap: 5px; font-size: var(--vt-fs-micro); font-weight: 600; color: var(--vt-text-2); } +.vt-app .vt-radio-name { font-weight: var(--vt-fw-semibold); font-size: var(--vt-fs-base); } +.vt-app .vt-status { margin-left: auto; display: inline-flex; align-items: center; gap: 5px; font-size: var(--vt-fs-micro); font-weight: var(--vt-fw-semibold); color: var(--vt-text-2); } .vt-app .vt-status::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--vt-ok); } .vt-app .vt-status-warn::before { background: var(--vt-warn); } .vt-app .vt-status-err::before { background: var(--vt-err); } @@ -912,22 +1000,22 @@ h2, h3{ } .vt-app .vt-icon-action:hover { background: var(--vt-surface-3); color: var(--vt-text); } .vt-app .vt-radio-chan { display: flex; align-items: baseline; gap: 8px; } -.vt-app .vt-radio-width { font-size: var(--vt-fs-md); font-weight: 600; color: var(--vt-text-2); } +.vt-app .vt-radio-width { font-size: var(--vt-fs-md); font-weight: var(--vt-fw-semibold); color: var(--vt-text-2); } .vt-app .vt-spectrum { position: relative; height: 8px; border-radius: 4px; background: var(--vt-surface-3); margin-bottom: 12px; } -.vt-app .vt-spectrum-blk { position: absolute; top: -2px; bottom: -2px; border-radius: 3px; background: var(--vt-bc); box-shadow: 0 0 0 2px var(--vt-surface); } +.vt-app .vt-spectrum-blk { position: absolute; top: -2px; bottom: -2px; border-radius: var(--vt-r-xs); background: var(--vt-bc); box-shadow: 0 0 0 2px var(--vt-surface); } .vt-app .vt-spectrum-lo, .vt-app .vt-spectrum-hi { position: absolute; top: 11px; font-size: var(--vt-fs-micro); color: var(--vt-text-3); } .vt-app .vt-spectrum-lo { left: 0; } .vt-app .vt-spectrum-hi { right: 0; } .vt-app .vt-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 12px; } -.vt-app .vt-kv dt { font-size: var(--vt-fs-micro); color: var(--vt-text-3); font-weight: 600; text-transform: uppercase; letter-spacing: .04em; } -.vt-app .vt-kv dd { font-size: var(--vt-fs-base); font-weight: 600; margin: 1px 0 0; } -.vt-app .vt-kv dd .vt-muted { font-weight: 500; font-size: var(--vt-fs-sm); } +.vt-app .vt-kv dt { font-size: var(--vt-fs-micro); color: var(--vt-text-3); font-weight: var(--vt-fw-semibold); text-transform: uppercase; letter-spacing: .08em; } +.vt-app .vt-kv dd { font-size: var(--vt-fs-base); font-weight: var(--vt-fw-semibold); margin: 1px 0 0; } +.vt-app .vt-kv dd .vt-muted { font-weight: var(--vt-fw-medium); font-size: var(--vt-fs-sm); } .vt-app .vt-radio-live { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 10px; align-items: center; padding: 8px 10px; border-radius: var(--vt-r-sm); background: var(--vt-surface-2); } .vt-app .vt-radio-live .vt-spark { height: 30px; } .vt-app .vt-rates { display: flex; flex-direction: column; gap: 1px; } -.vt-app .vt-rate { display: inline-flex; align-items: center; gap: 4px; font-size: var(--vt-fs-sm); font-weight: 650; white-space: nowrap; } -.vt-app .vt-rate .vt-ico { width: 12px; height: 12px; stroke-width: 2.3; color: var(--vt-text-3); } -.vt-app .vt-rate-up { font-weight: 500; color: var(--vt-text-2); } +.vt-app .vt-rate { display: inline-flex; align-items: center; gap: 4px; font-size: var(--vt-fs-sm); font-weight: var(--vt-fw-semibold); white-space: nowrap; } +.vt-app .vt-rate .vt-ico { width: 12px; height: 12px; stroke-width: 2; color: var(--vt-text-3); } +.vt-app .vt-rate-up { font-weight: var(--vt-fw-medium); color: var(--vt-text-2); } .vt-app .vt-notes { display: flex; flex-direction: column; gap: 4px; } .vt-app .vt-note { display: flex; align-items: flex-start; gap: 6px; font-size: var(--vt-fs-sm); color: var(--vt-text-2); } .vt-app .vt-note .vt-ico { margin-top: 2px; color: var(--vt-text-3); } @@ -946,7 +1034,7 @@ h2, h3{ /* a jump to a tile (the path's SSID, Wired and port nodes) stops below the sticky top bar */ .vt-app .vt-tile { scroll-margin-top: calc(var(--v-stick-top, 48px) + 12px); } -.vt-app .vt-count { font-size: var(--vt-fs-sm); color: var(--vt-text-3); font-weight: 560; } +.vt-app .vt-count { font-size: var(--vt-fs-sm); color: var(--vt-text-3); font-weight: var(--vt-fw-medium); } .vt-app .vt-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 10px; } .vt-app .vt-filter { position: relative; display: flex; align-items: center; flex: 1 1 260px; max-width: 380px; @@ -954,7 +1042,7 @@ h2, h3{ border: 1px solid var(--vt-line-2); border-radius: var(--vt-r-ctl); background: var(--vt-surface); color: var(--vt-text-3); cursor: text; } -.vt-app .vt-filter:focus-within { border-color: var(--vt-accent-line); box-shadow: 0 0 0 3px var(--vt-accent-soft); } +.vt-app .vt-filter:focus-within { border-color: var(--vt-focus); box-shadow: var(--vt-focus-ring); } .vt-app .vt-filter .vt-ico { width: 16px; height: 16px; } .vt-app .vt-filter .vt-filter-input { flex: 1; min-width: 0; width: auto; height: calc(var(--vt-ctl) - 2px); padding: 0; margin: 0; @@ -962,7 +1050,13 @@ h2, h3{ color: var(--vt-text); font: inherit; font-size: var(--vt-fs-base); } .vt-app .vt-filter .vt-filter-input::placeholder { color: var(--vt-text-3); opacity: 1; } -.vt-app .vt-key-hint { font: 600 var(--vt-fs-micro)/1 var(--vt-mono); padding: 3px 5px; border-radius: 4px; border: 1px solid var(--vt-line-2); color: var(--vt-text-3); background: var(--vt-surface-2); } +/* the theme's keycap (.vt-kbd), as by its search box */ +.vt-app .vt-key-hint { + display: inline-flex; align-items: center; flex: none; height: 20px; padding: 0 6px; + border: 1px solid var(--vt-line-2); border-bottom-width: 2px; border-radius: 4px; + background: var(--vt-surface-3); color: var(--vt-text-2); + font: var(--vt-fw-medium) var(--vt-fs-micro)/1 var(--vt-mono); letter-spacing: .02em; +} .vt-app .vt-filter:focus-within .vt-key-hint { display: none; } .vt-app .vt-filter-clear { display: inline-flex; align-items: center; justify-content: center; width: calc(var(--vt-ctl) - 10px); height: calc(var(--vt-ctl) - 10px); padding: 0; margin: 0; @@ -970,18 +1064,27 @@ h2, h3{ } .vt-app .vt-filter-clear:hover { background: var(--vt-surface-3); color: var(--vt-text); } .vt-app .vt-filter-clear .vt-ico { width: 14px; height: 14px; } -/* Wi-Fi or wired, in the tile head */ -.vt-app .vt-kinds { display: inline-flex; padding: 2px; gap: 2px; border: 1px solid var(--vt-line); border-radius: 999px; background: var(--vt-surface-2); } +/* Wi-Fi or wired, in the tile head: the theme's segmented control (its + tabs). Each segment is a control high; the 3px between the track's edge + and the drawn segment is the segment's own transparent border */ +.vt-app .vt-kinds { + display: inline-flex; padding: 0; gap: 0; border: 0; + border-radius: var(--vt-r-lg); background: var(--vt-seg-bg); box-shadow: inset 0 0 0 1px var(--vt-line); +} .vt-app .vt-kind { - display: inline-flex; align-items: center; gap: 6px; height: 26px; padding: 0 11px; margin: 0; min-width: 0; - border: 0; border-radius: 999px; background: transparent; box-shadow: none; text-transform: none; - color: var(--vt-text-2); font-size: var(--vt-fs-sm); font-weight: 600; cursor: pointer; + display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: var(--vt-ctl); padding: 0 10px; margin: 0; min-width: 0; + border: 3px solid transparent; background-clip: padding-box; border-radius: calc(var(--vt-r-ctl) + 3px); + background-color: transparent; box-shadow: none; text-transform: none; + color: var(--vt-text-2); font-size: var(--vt-fs-base); font-weight: var(--vt-fw-medium); cursor: pointer; } .vt-app .vt-kind:hover { color: var(--vt-text); } -.vt-app .vt-kind.vt-kind-on { background: var(--vt-surface); color: var(--vt-text); box-shadow: var(--vt-shadow); } -.vt-app .vt-kind-n { font-size: var(--vt-fs-micro); color: var(--vt-text-3); } -/* quick filters: a button at the end of the search box, a menu under it, - and the filter in force as a tag in the box */ +.vt-app .vt-kind:focus-visible { outline-offset: -1px; } +.vt-app .vt-kind.vt-kind-on, .vt-app .vt-kind.vt-kind-on:hover { background-color: var(--vt-seg-on); color: var(--vt-accent-text); font-weight: var(--vt-fw-semibold); box-shadow: var(--vt-seg-on-ring); } +.vt-app .vt-kind-n { font-size: var(--vt-fs-micro); font-weight: var(--vt-fw-medium); color: var(--vt-text-3); } +/* quick filters: a button at the end of the search box, a menu under it + (the theme's dropdown list: items on --vt-pop-hover under the pointer, + the keyboard's with the accent bar too), and the filter in force as a + tag in the box */ .vt-app .vt-filter-wrap { position: relative; display: flex; flex: 1 1 260px; max-width: 380px; min-width: 0; } .vt-app .vt-filter-wrap > .vt-filter { flex: 1 1 auto; max-width: none; min-width: 0; } .vt-app .vt-filter-btn { @@ -990,65 +1093,67 @@ h2, h3{ border: 0; border-radius: var(--vt-r-ctl); background: transparent; box-shadow: none; color: var(--vt-text-3); cursor: pointer; } .vt-app .vt-filter-btn:hover, .vt-app .vt-filter-btn[aria-expanded="true"] { background: var(--vt-surface-3); color: var(--vt-text); } -.vt-app .vt-filter-btn.vt-filter-btn-on { color: var(--vt-accent); } +.vt-app .vt-filter-btn.vt-filter-btn-on { color: var(--vt-accent-text); } .vt-app .vt-filter-btn .vt-ico { width: 16px; height: 16px; } .vt-app .vt-ftag { display: inline-flex; align-items: center; gap: 4px; flex: none; max-width: 45%; height: 24px; padding: 0 6px 0 9px; margin: 0; min-width: 0; border: 0; border-radius: 999px; background: var(--vt-accent-soft); box-shadow: none; text-transform: none; - color: var(--vt-text); font-size: var(--vt-fs-sm); font-weight: 600; cursor: pointer; + color: var(--vt-text); font-size: var(--vt-fs-sm); font-weight: var(--vt-fw-semibold); cursor: pointer; } .vt-app .vt-ftag span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .vt-app .vt-ftag .vt-ico { width: 12px; height: 12px; flex: none; color: var(--vt-text-3); } .vt-app .vt-ftag:hover .vt-ico { color: var(--vt-text); } .vt-app .vt-fmenu { - position: absolute; top: calc(100% + 6px); right: 0; z-index: 6; - display: flex; flex-direction: column; min-width: 210px; padding: 5px; - border: 1px solid var(--vt-line-2); border-radius: var(--vt-r); background: var(--vt-surface); box-shadow: var(--vt-shadow-pop); + position: absolute; top: calc(100% + 4px); right: 0; z-index: var(--vt-z-float); + display: flex; flex-direction: column; min-width: 210px; padding: var(--vt-sp-1); + border: 1px solid var(--vt-line-2); border-radius: var(--vt-r-ctl); background: var(--vt-pop); box-shadow: var(--vt-shadow-pop); } .vt-app .vt-fmenu[hidden] { display: none; } .vt-app .vt-fmenu-item { display: grid; grid-template-columns: 18px minmax(0, 1fr) auto; align-items: center; gap: 8px; - height: 34px; padding: 0 10px 0 8px; margin: 0; min-width: 0; width: 100%; - border: 0; border-radius: var(--vt-r-ctl); background: transparent; box-shadow: none; text-align: left; text-transform: none; - color: var(--vt-text); font-size: var(--vt-fs-sm); font-weight: 560; cursor: pointer; + min-height: calc(var(--vt-ctl) - 4px); padding: 4px 8px; margin: 0; min-width: 0; width: 100%; + border: 0; border-radius: var(--vt-r-sm); background: transparent; box-shadow: none; text-align: left; text-transform: none; + color: var(--vt-text); font-size: var(--vt-fs-base); font-weight: var(--vt-fw-regular); cursor: pointer; } -.vt-app .vt-fmenu-item:hover, .vt-app .vt-fmenu-item:focus-visible { background: var(--vt-surface-2); outline: none; } -.vt-app .vt-fmenu-check { display: inline-flex; color: var(--vt-accent); } +.vt-app .vt-fmenu-item:hover, .vt-app .vt-fmenu-item:focus-visible { background: var(--vt-pop-hover); outline: none; } +.vt-app .vt-fmenu-item:focus-visible { box-shadow: inset 2px 0 0 var(--vt-accent-text); } +.vt-app .vt-fmenu-check { display: inline-flex; color: var(--vt-accent-text); } .vt-app .vt-fmenu-check .vt-ico { width: 14px; height: 14px; } .vt-app .vt-fmenu-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.vt-app .vt-fmenu-n { color: var(--vt-text-3); font-size: var(--vt-fs-micro); font-weight: 600; } +.vt-app .vt-fmenu-n { color: var(--vt-text-3); font-size: var(--vt-fs-micro); font-weight: var(--vt-fw-semibold); } .vt-app .vt-fmenu-warn .vt-fmenu-n { color: var(--vt-warn); } .vt-app .vt-fchip { display: inline-flex; align-items: center; gap: 6px; height: var(--vt-ctl); padding: 0 12px; margin: 0; border: 1px solid var(--vt-line); border-radius: 999px; background: var(--vt-surface); - color: var(--vt-text-2); font-size: var(--vt-fs-sm); font-weight: 600; cursor: pointer; box-shadow: none; min-width: 0; text-transform: none; + color: var(--vt-text-2); font-size: var(--vt-fs-sm); font-weight: var(--vt-fw-semibold); cursor: pointer; box-shadow: none; min-width: 0; text-transform: none; } .vt-app .vt-fchip:hover { border-color: var(--vt-line-2); color: var(--vt-text); background: var(--vt-surface-2); } -.vt-app .vt-table-wrap { overflow-x: auto; margin: 0 -18px; padding: 0 18px; } +.vt-app .vt-table-wrap { overflow-x: auto; margin: 0 calc(-1 * var(--vt-card-px)); padding: 0 var(--vt-card-px); } .vt-app .vt-ctable { width: 100%; border-collapse: separate; border-spacing: 0; table-layout: auto; min-width: 800px; } .vt-app .vt-ctable th { position: sticky; top: 0; z-index: 1; padding: 0 10px; height: var(--vt-ctl); text-align: left; white-space: nowrap; letter-spacing: normal; text-transform: none; - background: var(--vt-surface); border-bottom: 1px solid var(--vt-line); - font-weight: 400; + background: var(--vt-surface); border-bottom: 1px solid var(--vt-line-2); + font-weight: var(--vt-fw-regular); } .vt-app .vt-sort { display: inline-flex; align-items: center; gap: 4px; height: var(--vt-ctl); padding: 0 4px; margin: 0 -4px; border: 0; border-radius: var(--vt-r-ctl); background: transparent; box-shadow: none; min-width: 0; - color: var(--vt-text-3); font-size: var(--vt-fs-micro); font-weight: 650; letter-spacing: .05em; text-transform: uppercase; cursor: pointer; + color: var(--vt-text-3); font-size: var(--vt-fs-micro); font-weight: var(--vt-fw-semibold); letter-spacing: .08em; text-transform: uppercase; cursor: pointer; } -.vt-app .vt-sort:hover { color: var(--vt-text); background: var(--vt-surface-2); } -.vt-app .vt-sort-on { color: var(--vt-text); } -.vt-app .vt-sort-ind { font-size: var(--vt-fs-micro); width: 8px; } +/* as the theme's sortable headers: the label lights up under the pointer, + the sorted one shows its arrow in the accent */ +.vt-app .vt-sort:hover { color: var(--vt-text); } +.vt-app .vt-sort-ind { font-size: var(--vt-fs-micro); width: 8px; color: var(--vt-accent-text); } .vt-app .vt-ctable td { height: auto; line-height: 1.4; overflow-wrap: normal; text-align: left; - padding: 9px 8px; vertical-align: middle; + padding: 9px 10px; vertical-align: middle; border-bottom: 1px solid var(--vt-line); } .vt-app .vt-ctable tr:last-child td { border-bottom: 0; } .vt-app .vt-row { cursor: pointer; transition: background .15s; } -.vt-app .vt-row:hover td { background: var(--vt-surface-2); } +.vt-app .vt-row:hover td { background: var(--vt-hover); } .vt-app .vt-row:focus-visible { outline: none; } .vt-app .vt-row:focus-visible td { background: var(--vt-accent-soft); } .vt-app .vt-row-sel td { background: var(--vt-accent-soft); } @@ -1062,34 +1167,34 @@ h2, h3{ .vt-app .vt-who-text { min-width: 0; } /* names get two lines before they are cut; the full name is the title */ .vt-app .vt-who-label { - font-weight: 640; font-size: var(--vt-fs-base); line-height: 1.3; max-width: 280px; overflow-wrap: anywhere; + font-weight: var(--vt-fw-semibold); font-size: var(--vt-fs-base); line-height: 1.3; max-width: 280px; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .vt-app .vt-who-sub { display: flex; flex-wrap: wrap; align-items: center; gap: 3px 6px; margin-top: 3px; color: var(--vt-text-3); font-size: var(--vt-fs-micro); } .vt-app .vt-who-id { white-space: nowrap; } .vt-app .vt-td-name { min-width: 250px; } .vt-app .vt-net { display: flex; flex-direction: column; gap: 3px; } -.vt-app .vt-net-ssid { font-weight: 560; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 150px; } +.vt-app .vt-net-ssid { font-weight: var(--vt-fw-medium); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 150px; } .vt-app .vt-net-badges { display: flex; align-items: center; gap: 6px; } .vt-app .vt-phy { display: flex; align-items: center; gap: 4px; font-size: var(--vt-fs-sm); white-space: nowrap; } -.vt-app .vt-phy b { font-weight: 620; } -.vt-app .vt-phy .vt-ico { color: var(--vt-text-3); stroke-width: 2.2; width: 12px; height: 12px; } +.vt-app .vt-phy b { font-weight: var(--vt-fw-semibold); } +.vt-app .vt-phy .vt-ico { color: var(--vt-text-3); stroke-width: 2; width: 12px; height: 12px; } .vt-app .vt-phy-up { color: var(--vt-text-3); font-size: var(--vt-fs-micro); padding-left: 16px; } .vt-app .vt-live-cell { display: grid; grid-template-columns: auto; gap: 3px; min-width: 96px; } -.vt-app .vt-live-total { font-weight: 650; } -.vt-app .vt-mini { display: block; height: 4px; border-radius: 2px; background: var(--vt-surface-3); overflow: hidden; } -.vt-app .vt-mini-fill { display: block; height: 100%; background: var(--vt-info); border-radius: 2px; } +.vt-app .vt-live-total { font-weight: var(--vt-fw-semibold); } +.vt-app .vt-mini { display: block; height: 4px; border-radius: var(--vt-r-xs); background: var(--vt-surface-3); overflow: hidden; } +.vt-app .vt-mini-fill { display: block; height: 100%; background: var(--vt-meter); } .vt-app .vt-live-split { font-size: var(--vt-fs-micro); color: var(--vt-text-3); white-space: nowrap; } .vt-app .vt-exp { display: flex; align-items: center; gap: 9px; min-width: 0; } .vt-app .vt-score { flex: none; display: inline-flex; align-items: center; justify-content: center; - width: 32px; height: 26px; border-radius: 7px; font-size: var(--vt-fs-sm); font-weight: 700; - --vt-xc: var(--vt-ok); background: color-mix(in oklab, var(--vt-xc) 15%, transparent); color: color-mix(in oklab, var(--vt-xc) 85%, var(--vt-text)); + width: 32px; height: 26px; border-radius: 8px; font-size: var(--vt-fs-sm); font-weight: var(--vt-fw-bold); + --vt-xc: var(--vt-ok); --vt-xt: var(--vt-ok-text); background: color-mix(in oklab, var(--vt-xc) 15%, transparent); color: var(--vt-xt); } -.vt-app .vt-score-warn { --vt-xc: var(--vt-warn); } -.vt-app .vt-score-err { --vt-xc: var(--vt-err); } +.vt-app .vt-score-warn { --vt-xc: var(--vt-warn); --vt-xt: var(--vt-warn-text); } +.vt-app .vt-score-err { --vt-xc: var(--vt-err); --vt-xt: var(--vt-err-text); } .vt-app .vt-exp-text { display: flex; flex-direction: column; min-width: 0; } -.vt-app .vt-exp-text b { font-size: var(--vt-fs-sm); font-weight: 650; } +.vt-app .vt-exp-text b { font-size: var(--vt-fs-sm); font-weight: var(--vt-fw-semibold); } .vt-app .vt-exp-text span { font-size: var(--vt-fs-micro); line-height: 1.35; color: var(--vt-text-3); max-width: 170px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; @@ -1112,40 +1217,39 @@ h2, h3{ display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px; border: 0; border-radius: var(--vt-r-sm); background: transparent; box-shadow: none; - text-align: left; cursor: pointer; color: var(--vt-text); height: auto; min-width: 0; text-transform: none; font-weight: 400; + text-align: left; cursor: pointer; color: var(--vt-text); height: auto; min-width: 0; text-transform: none; font-weight: var(--vt-fw-regular); } -.vt-app .vt-talk-row:hover, .vt-app .vt-ssid:hover, .vt-app .vt-dlist-row:hover { background: var(--vt-surface-2); } -.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-row:hover, .vt-app .vt-ssid:hover, .vt-app .vt-dlist-row:hover { background: var(--vt-hover); } +.vt-app .vt-talk-rank { width: 14px; font-size: var(--vt-fs-sm); color: var(--vt-text-3); font-weight: var(--vt-fw-semibold); 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; 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; } -.vt-app .vt-talk-fill { display: block; height: 100%; border-radius: 3px; background: var(--vt-info); } -.vt-app .vt-talk-sub { display: flex; gap: 8px; align-items: baseline; font-size: var(--vt-fs-micro); color: var(--vt-text-3); white-space: nowrap; overflow: hidden; } +.vt-app .vt-talk-name { font-weight: var(--vt-fw-semibold); 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: var(--vt-fw-semibold); color: var(--vt-text-2); white-space: nowrap; } +.vt-app .vt-talk-sub b { color: var(--vt-text); font-weight: var(--vt-fw-semibold); } +.vt-app .vt-talk-bar { height: 5px; border-radius: var(--vt-r-xs); background: var(--vt-surface-3); overflow: hidden; } +.vt-app .vt-talk-fill { display: block; height: 100%; background: var(--vt-meter); } +.vt-app .vt-talk-sub { display: flex; flex-wrap: wrap; gap: 0 8px; align-items: baseline; font-size: var(--vt-fs-micro); color: var(--vt-text-3); white-space: nowrap; min-width: 0; } .vt-app .vt-ssids { display: flex; flex-direction: column; gap: 2px; } -.vt-app .vt-ssid-ico { flex: none; width: 30px; height: 30px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; background: var(--vt-surface-3); color: var(--vt-text-2); } -.vt-app .vt-ssid-ico .vt-ico { width: 16px; height: 16px; } -.vt-app .vt-ssid-ico.vt-t-warn { background: var(--vt-warn-soft); color: var(--vt-warn); } .vt-app .vt-ssid-main { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; } .vt-app .vt-ssid-top { display: flex; align-items: center; gap: 6px; min-width: 0; } -.vt-app .vt-ssid-name { font-weight: 640; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.vt-app .vt-ssid-name { font-weight: var(--vt-fw-semibold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .vt-app .vt-ssid-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; } -.vt-app .vt-sec { font-size: var(--vt-fs-micro); font-weight: 600; color: var(--vt-text-2); } +.vt-app .vt-sec { display: inline-flex; align-items: center; gap: 3px; font-size: var(--vt-fs-micro); font-weight: var(--vt-fw-semibold); color: var(--vt-text-2); } +.vt-app .vt-sec.vt-t-warn { color: var(--vt-warn-text); } +.vt-app .vt-sec .vt-ico { width: 12px; height: 12px; stroke-width: 2; } .vt-app .vt-ssid-side { display: flex; flex-direction: column; align-items: flex-end; flex: none; } -.vt-app .vt-ssid-n { font-size: var(--vt-fs-lg); font-weight: 700; line-height: 1.1; } +.vt-app .vt-ssid-n { font-size: var(--vt-fs-lg); font-weight: var(--vt-fw-bold); line-height: 1.1; } .vt-app .vt-ssid-idle .vt-ssid-n { color: var(--vt-text-3); } /* ------------------------------------------------------------ 11. drawer */ .vt-app .vt-drawer-back { - position: fixed; inset: 0; z-index: 880; + position: fixed; inset: 0; z-index: calc(var(--vt-z-drawer) - 1); background: var(--vt-scrim); opacity: 0; transition: opacity .25s ease; } .vt-app .vt-drawer { - position: fixed; z-index: 890; top: 0; right: 0; bottom: 0; + position: fixed; z-index: var(--vt-z-drawer); top: 0; right: 0; bottom: 0; width: min(460px, 100vw); display: flex; flex-direction: column; background: var(--vt-surface); color: var(--vt-text); @@ -1163,12 +1267,12 @@ h2, h3{ padding: 16px 16px 14px 20px; border-bottom: 1px solid var(--vt-line); } .vt-app .vt-drawer-title { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0; } -.vt-app .vt-drawer-title .vt-av { width: 44px; height: 44px; border-radius: 12px; } +.vt-app .vt-drawer-title .vt-av { width: 44px; height: 44px; border-radius: var(--vt-r-xl); } .vt-app .vt-drawer-title .vt-av .vt-ico { width: 24px; height: 24px; } -.vt-app .vt-drawer-ico { width: 44px; height: 44px; border-radius: 12px; display: inline-flex; align-items: center; justify-content: center; background: var(--vt-surface-3); color: var(--vt-text-2); flex: none; } -.vt-app .vt-drawer-ico .vt-ico { width: 22px; height: 22px; } +.vt-app .vt-drawer-ico { width: 44px; height: 44px; border-radius: var(--vt-r-xl); display: inline-flex; align-items: center; justify-content: center; background: var(--vt-surface-3); color: var(--vt-text-2); flex: none; } +.vt-app .vt-drawer-ico .vt-ico { width: 24px; height: 24px; } .vt-app .vt-drawer-titles { min-width: 0; } -.vt-app .vt-drawer-name { font-size: var(--vt-fs-lg); font-weight: 680; letter-spacing: -.01em; line-height: 1.25; overflow-wrap: anywhere; } +.vt-app .vt-drawer-name { font-size: var(--vt-fs-lg); font-weight: var(--vt-fw-bold); letter-spacing: -.01em; line-height: 1.25; overflow-wrap: anywhere; } .vt-app .vt-drawer-sub { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; color: var(--vt-text-3); font-size: var(--vt-fs-sm); margin-top: 3px; } .vt-app .vt-drawer-close { display: inline-flex; align-items: center; justify-content: center; flex: none; @@ -1195,41 +1299,41 @@ h2, h3{ .vt-app .vt-ring-svg { width: 58px; height: 58px; transform: rotate(-90deg); } .vt-app .vt-ring-track { fill: none; stroke: color-mix(in oklab, var(--vt-xc) 18%, transparent); stroke-width: 3.5; } .vt-app .vt-ring-arc { fill: none; stroke: var(--vt-xc); stroke-width: 3.5; stroke-linecap: round; } -.vt-app .vt-ring-n { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: var(--vt-fs-lg); font-weight: 720; } -.vt-app .vt-expcard-grade { font-weight: 680; font-size: var(--vt-fs-md); } +.vt-app .vt-ring-n { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: var(--vt-fs-lg); font-weight: var(--vt-fw-bold); } +.vt-app .vt-expcard-grade { font-weight: var(--vt-fw-bold); font-size: var(--vt-fs-md); } .vt-app .vt-expcard-reason { font-size: var(--vt-fs-sm); color: var(--vt-text-2); margin-top: 1px; } .vt-app .vt-factors { margin-top: 6px; display: flex; flex-direction: column; gap: 2px; font-size: var(--vt-fs-micro); color: var(--vt-text-3); } .vt-app .vt-factors li { display: flex; gap: 6px; } -.vt-app .vt-factors li .vt-tn { width: 26px; flex: none; color: var(--vt-text-2); font-weight: 650; } +.vt-app .vt-factors li .vt-tn { width: 26px; flex: none; color: var(--vt-text-2); font-weight: var(--vt-fw-semibold); } .vt-app .vt-dgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } .vt-app .vt-dcard { display: flex; flex-direction: column; gap: 1px; padding: 12px; border-radius: var(--vt-r); background: var(--vt-surface-2); border: 1px solid var(--vt-line); min-width: 0; } -.vt-app .vt-dcard-label { font-size: var(--vt-fs-micro); font-weight: 650; text-transform: uppercase; letter-spacing: .05em; color: var(--vt-text-3); } -.vt-app .vt-dcard-value { font-size: var(--vt-fs-xl); font-weight: 700; letter-spacing: -.01em; white-space: nowrap; } +.vt-app .vt-dcard-label { font-size: var(--vt-fs-micro); font-weight: var(--vt-fw-semibold); text-transform: uppercase; letter-spacing: .08em; color: var(--vt-text-3); } +.vt-app .vt-dcard-value { font-size: var(--vt-fs-xl); font-weight: var(--vt-fw-bold); letter-spacing: -.01em; white-space: nowrap; } .vt-app .vt-dcard-sub { font-size: var(--vt-fs-micro); line-height: 1.35; color: var(--vt-text-3); min-height: 16px; } .vt-app .vt-dcard .vt-sk { margin-top: auto; padding-top: 18px; } .vt-app .vt-dcard .vt-sk-max { top: 16px; } .vt-app .vt-dcard .vt-spark { height: 36px; } .vt-app .vt-dspark { padding-top: 14px; } .vt-app .vt-dspark .vt-spark { height: 48px; } -.vt-app .vt-dsec-title { font-size: var(--vt-fs-micro); font-weight: 650; text-transform: uppercase; letter-spacing: .06em; color: var(--vt-text-3); margin: 0 0 6px; padding: 0; border: 0; } +.vt-app .vt-dsec-title { font-size: var(--vt-fs-micro); font-weight: var(--vt-fw-semibold); text-transform: uppercase; letter-spacing: .08em; color: var(--vt-text-3); margin: 0 0 6px; padding: 0; border: 0; } .vt-app .vt-kvs { display: flex; flex-direction: column; } .vt-app .vt-kvs .vt-kv { display: grid; grid-template-columns: 132px minmax(0, 1fr); gap: 12px; padding: 7px 0; border-bottom: 1px solid var(--vt-line); } .vt-app .vt-kvs .vt-kv:last-child { border-bottom: 0; } -.vt-app .vt-kvs .vt-kv dt { font-size: var(--vt-fs-sm); text-transform: none; letter-spacing: 0; font-weight: 500; color: var(--vt-text-3); } -.vt-app .vt-kvs .vt-kv dd { font-size: var(--vt-fs-base); font-weight: 520; margin: 0; white-space: pre-line; overflow-wrap: anywhere; display: flex; flex-direction: column; align-items: flex-start; gap: 1px; } -.vt-app .vt-kvs .vt-kv dd small { font-size: var(--vt-fs-micro); color: var(--vt-text-3); font-weight: 400; } +.vt-app .vt-kvs .vt-kv dt { font-size: var(--vt-fs-sm); text-transform: none; letter-spacing: 0; font-weight: var(--vt-fw-medium); color: var(--vt-text-3); } +.vt-app .vt-kvs .vt-kv dd { font-size: var(--vt-fs-base); font-weight: var(--vt-fw-medium); margin: 0; white-space: pre-line; overflow-wrap: anywhere; display: flex; flex-direction: column; align-items: flex-start; gap: 1px; } +.vt-app .vt-kvs .vt-kv dd small { font-size: var(--vt-fs-micro); color: var(--vt-text-3); font-weight: var(--vt-fw-regular); } .vt-app .vt-dlist { display: flex; flex-direction: column; } -.vt-app .vt-dlist-name { flex: 1; min-width: 0; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.vt-app .vt-dlist-name { flex: 1; min-width: 0; font-weight: var(--vt-fw-semibold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .vt-app .vt-rename { display: flex; flex-direction: column; gap: 10px; padding: 12px; border-radius: var(--vt-r); background: var(--vt-surface-2); border: 1px solid var(--vt-line); } -.vt-app .vt-rename-label { display: flex; flex-direction: column; gap: 5px; font-size: var(--vt-fs-sm); font-weight: 600; color: var(--vt-text-2); } +.vt-app .vt-rename-label { display: flex; flex-direction: column; gap: 5px; font-size: var(--vt-fs-sm); font-weight: var(--vt-fw-semibold); color: var(--vt-text-2); } .vt-app .vt-rename .vt-rename-input { height: var(--vt-ctl); width: 100%; padding: 0 10px; margin: 0; border: 1px solid var(--vt-line-2); border-radius: var(--vt-r-ctl); background: var(--vt-surface); - color: var(--vt-text); font: inherit; font-size: var(--vt-fs-md); font-weight: 400; box-shadow: none; /* the label around it is semibold */ + color: var(--vt-text); font: inherit; font-size: var(--vt-fs-md); font-weight: var(--vt-fw-regular); box-shadow: none; /* the label around it is semibold */ } -.vt-app .vt-rename .vt-rename-input:focus { outline: none; border-color: var(--vt-accent-line); box-shadow: 0 0 0 3px var(--vt-accent-soft); } +.vt-app .vt-rename .vt-rename-input:focus { outline: none; border-color: var(--vt-focus); box-shadow: var(--vt-focus-ring); } .vt-app .vt-icon-picks { display: flex; flex-wrap: wrap; gap: 4px; } .vt-app .vt-icon-pick { display: inline-flex; align-items: center; justify-content: center; width: var(--vt-ctl); height: var(--vt-ctl); padding: 0; margin: 0; @@ -1237,7 +1341,7 @@ h2, h3{ cursor: pointer; box-shadow: none; min-width: 0; } .vt-app .vt-icon-pick:hover { border-color: var(--vt-line-2); color: var(--vt-text); } -.vt-app .vt-icon-pick[aria-pressed="true"] { background: var(--vt-accent); border-color: var(--vt-accent); color: var(--vt-accent-ink); } +.vt-app .vt-icon-pick[aria-pressed="true"] { background: var(--vt-accent-fill); border-color: var(--vt-accent-line); color: var(--vt-accent-fill-ink); } .vt-app .vt-rename-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; } .vt-app .vt-rename-actions .vt-hint { flex-basis: 100%; font-size: var(--vt-fs-micro); } .vt-app .vt-form-err { color: var(--vt-err); font-size: var(--vt-fs-sm); } @@ -1247,14 +1351,14 @@ h2, h3{ the internet, the zones and what is switched off */ /* no internet-facing zone: the page cannot tell, neither green nor a warning */ .vt-app .vt-orb-unknown { --vt-oc: var(--vt-text-3); } -.vt-app .vt-fg-warns { display: grid; gap: 10px; margin-bottom: 14px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); } +.vt-app .vt-fg-warns { display: grid; gap: 10px; margin-bottom: var(--vt-sp-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); } /* a warning's title is a sentence, not the dashboard's small caps label */ -.vt-app .vt-fg-warns .vt-chip-title { text-transform: none; letter-spacing: 0; font-size: var(--vt-fs-base); font-weight: 650; color: var(--vt-text); } -.vt-app .vt-fg-warns .vt-chip-reason { margin-top: 2px; } -.vt-app .vt-fg-grid { display: grid; gap: 14px; align-items: start; grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr)); } +.vt-app .vt-fg-warns .vt-chip-title { text-transform: none; letter-spacing: 0; font-size: var(--vt-fs-base); font-weight: var(--vt-fw-semibold); color: var(--vt-text); } +.vt-app .vt-fg-warns .vt-chip-reason { margin-top: 2px; display: block; -webkit-line-clamp: unset; overflow: visible; } +.vt-app .vt-fg-grid { display: grid; gap: var(--vt-sp-4); align-items: start; grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr)); } .vt-app .vt-fg-group { margin: 2px 0 4px; color: var(--vt-text-3); - font-size: var(--vt-fs-micro); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; + font-size: var(--vt-fs-micro); font-weight: var(--vt-fw-semibold); letter-spacing: .08em; text-transform: uppercase; } .vt-app .vt-fg-rows + .vt-fg-group { margin-top: 14px; } .vt-app .vt-fg-rows { display: flex; flex-direction: column; } @@ -1264,14 +1368,15 @@ h2, h3{ border-radius: var(--vt-r-sm); color: var(--vt-text); text-decoration: none; } .vt-app .vt-fg-row + .vt-fg-row { box-shadow: inset 0 1px 0 var(--vt-line); } -.vt-app .vt-fg-row:hover { background: var(--vt-surface-2); text-decoration: none; } +.vt-app .vt-fg-row:hover { background: var(--vt-hover); text-decoration: none; } .vt-app .vt-fg-row-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; } -.vt-app .vt-fg-row-name { font-size: var(--vt-fs-base); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.vt-app .vt-fg-row-name { font-size: var(--vt-fs-base); font-weight: var(--vt-fw-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .vt-app .vt-fg-row-sub { color: var(--vt-text-3); font-size: var(--vt-fs-sm); } .vt-app .vt-fg-anywhere { color: var(--vt-text-2); } .vt-app .vt-fg-to { flex: none; display: inline-flex; align-items: center; gap: 6px; max-width: 45%; color: var(--vt-text-2); font-size: var(--vt-fs-sm); } -.vt-app .vt-fg-to > .vt-mono { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.vt-app .vt-fg-to .vt-ico, .vt-app .vt-fg-zone-to > .vt-ico { flex: none; width: 15px; height: 15px; color: var(--vt-text-3); } +/* a long address breaks rather than hide its port at the end */ +.vt-app .vt-fg-to > .vt-mono { min-width: 0; overflow-wrap: anywhere; } +.vt-app .vt-fg-to .vt-ico, .vt-app .vt-fg-zone-to > .vt-ico { flex: none; width: 16px; height: 16px; color: var(--vt-text-3); } .vt-app .vt-fg-std { margin-top: 12px; } .vt-app .vt-fg-std > summary { cursor: pointer; padding: 4px 0; color: var(--vt-text-2); font-size: var(--vt-fs-sm); } .vt-app .vt-fg-std > .vt-hint { margin: 2px 0 6px; } @@ -1280,20 +1385,21 @@ h2, h3{ .vt-app .vt-fg-zone:first-child { padding-top: 0; } .vt-app .vt-fg-zone + .vt-fg-zone { border-top: 1px solid var(--vt-line); } .vt-app .vt-fg-zone-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; } -.vt-app .vt-fg-zone-name { font-size: var(--vt-fs-md); font-weight: 650; } +.vt-app .vt-fg-zone-name { font-size: var(--vt-fs-md); font-weight: var(--vt-fw-semibold); } .vt-app .vt-fg-tag { padding: 1px 7px; border-radius: 999px; - background: var(--vt-info-soft); color: color-mix(in oklab, var(--vt-info) 80%, var(--vt-text)); - font-size: var(--vt-fs-micro); font-weight: 600; + background: var(--vt-info-soft); color: var(--vt-info-text); + font-size: var(--vt-fs-micro); font-weight: var(--vt-fw-semibold); } .vt-app .vt-fg-zone-in { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; color: var(--vt-text-3); font-size: var(--vt-fs-sm); } -.vt-app .vt-fg-pol { padding: 1px 8px; border-radius: var(--vt-r-sm); font-size: var(--vt-fs-sm); font-weight: 600; } -.vt-app .vt-fg-pol.is-accept { background: var(--vt-ok-soft); color: color-mix(in oklab, var(--vt-ok) 72%, var(--vt-text)); } -.vt-app .vt-fg-pol.is-stop { background: var(--vt-err-soft); color: color-mix(in oklab, var(--vt-err) 80%, var(--vt-text)); } -.vt-app .vt-fg-pol.is-risk { background: var(--vt-warn-soft); color: color-mix(in oklab, var(--vt-warn) 65%, var(--vt-text)); box-shadow: inset 0 0 0 1px var(--vt-warn); } +/* an input policy is neutral (reject and drop are the safe values); + only an internet zone that accepts is an error, in the status colours + the theme's verdict badges use on the other Firewall tabs */ +.vt-app .vt-fg-pol { padding: 1px 8px; border-radius: var(--vt-r-sm); font-size: var(--vt-fs-sm); font-weight: var(--vt-fw-semibold); background: var(--vt-surface-3); color: var(--vt-text-2); } +.vt-app .vt-fg-pol.is-risk { background: var(--vt-err-soft); color: var(--vt-err-text); box-shadow: inset 0 0 0 1px var(--vt-err); } .vt-app .vt-fg-zone-to { display: flex; align-items: center; gap: 8px; margin-top: 6px; } .vt-app .vt-fg-dests { display: flex; flex-wrap: wrap; gap: 6px; } -.vt-app .vt-fg-dest { padding: 1px 8px; border: 1px solid var(--vt-line-2); border-radius: var(--vt-r-sm); font-size: var(--vt-fs-sm); font-weight: 600; } +.vt-app .vt-fg-dest { padding: 1px 8px; border: 1px solid var(--vt-line-2); border-radius: var(--vt-r-sm); font-size: var(--vt-fs-sm); font-weight: var(--vt-fw-semibold); } .vt-app .vt-fg-dest.is-risk { border-color: var(--vt-warn); background: var(--vt-warn-soft); } .vt-app .vt-fg-nets { margin-top: 4px; } .vt-app .vt-fg-note { @@ -1302,7 +1408,7 @@ h2, h3{ font-size: var(--vt-fs-sm); text-decoration: none; } .vt-app a.vt-fg-note:hover { color: var(--vt-text); text-decoration: none; } -.vt-app .vt-fg-note > .vt-ico { flex: none; width: 15px; height: 15px; margin-top: 1px; color: var(--vt-info); } +.vt-app .vt-fg-note > .vt-ico { flex: none; width: 16px; height: 16px; margin-top: 1px; color: var(--vt-info); } .vt-app .vt-fg-foot { margin: 12px 0 0; } /* ------------------------------------------------ 12. small screens, motion */ @@ -1315,7 +1421,7 @@ h2, h3{ .vt-app .vt-head { gap: 10px; } .vt-app .vt-headline { font-size: var(--vt-fs-lg); } .vt-app .vt-orb { width: 32px; height: 32px; } - /* phones: a live connection is just the pulsing dot; paused or + /* phones: a live connection is just the dot; paused or reconnecting still says so in words */ .vt-app .vt-live-ok { padding: 0 11px; } .vt-app .vt-live-ok .vt-live-text { display: none; } @@ -1334,6 +1440,9 @@ h2, h3{ .vt-app .vt-mult-now { font-size: var(--vt-fs-md); } .vt-app .vt-mx-odd { display: none; } .vt-app .vt-tip { min-width: 160px; } + /* firewall rows: where it goes sits under the description, whole */ + .vt-app .vt-fg-row { flex-wrap: wrap; row-gap: 2px; } + .vt-app .vt-fg-to { max-width: 100%; flex-basis: 100%; } } /* clients as cards when the tile is too narrow for the table: one @@ -1347,11 +1456,11 @@ h2, h3{ .vt-app .vt-ctable tbody { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 10px; } .vt-app .vt-ctable tr.vt-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 7px 10px; align-content: start; - padding: 11px 12px; border: 1px solid var(--vt-line); border-radius: var(--vt-r); + padding: 12px; border: 1px solid var(--vt-line); border-radius: var(--vt-r); background: var(--vt-surface); } .vt-app .vt-ctable td { display: block; padding: 0; border: 0; background: transparent !important; } - .vt-app .vt-row:hover { background: var(--vt-surface-2); } + .vt-app .vt-row:hover { background: var(--vt-hover); } .vt-app .vt-ctable tr.vt-row-sel { background: var(--vt-accent-soft); border-color: var(--vt-accent-line); } .vt-app .vt-ctable td.vt-td-name { grid-column: 1; grid-row: 1; min-width: 0; box-shadow: none !important; } .vt-app .vt-ctable td.vt-td-signal, .vt-app .vt-ctable td.vt-td-link { grid-column: 2; grid-row: 1; justify-self: end; align-self: start; padding-top: 2px; text-align: right; } @@ -1373,16 +1482,19 @@ h2, h3{ .vt-app .vt-net-ssid { font-size: var(--vt-fs-base); max-width: none; } } -@media (max-width: 640px) { +/* phones: a bottom sheet, where the theme turns its flyouts into sheets + and with their metrics (corners, grip, timing) */ +@media (max-width: 720px) { .vt-app .vt-drawer { top: auto; left: 0; right: 0; bottom: 0; width: auto; max-height: 88vh; max-height: 88dvh; height: 88vh; height: 88dvh; - border-left: 0; border-top: 1px solid var(--vt-line); - border-radius: 18px 18px 0 0; + border-left: 0; border-top: 1px solid var(--vt-line-2); + border-radius: var(--vt-r-lg) var(--vt-r-lg) 0 0; transform: translateY(104%); - box-shadow: 0 -18px 48px rgba(12, 14, 17, .22); + transition: transform .18s ease-out; + box-shadow: var(--vt-shadow-pop); } - .vt-app .vt-drawer-grip { display: block; width: 38px; height: 4px; border-radius: 2px; background: var(--vt-line-2); margin: 8px auto 0; flex: none; } + .vt-app .vt-drawer-grip { display: block; width: 36px; height: 4px; border-radius: var(--vt-r-xs); background: var(--vt-line-2); margin: 6px auto 0; flex: none; } .vt-app .vt-drawer-head { padding: 10px 12px 12px 16px; } .vt-app .vt-drawer-body { padding: 12px 16px calc(24px + env(safe-area-inset-bottom)); } .vt-app .vt-kvs .vt-kv { grid-template-columns: 112px minmax(0, 1fr); } @@ -1391,6 +1503,8 @@ h2, h3{ /* touch: 16px text in fields (iOS zooms into anything smaller) */ @media (pointer: coarse) { .vt-app .vt-filter .vt-filter-input, .vt-app .vt-rename .vt-rename-input { font-size: 16px; } + /* menu items are touch targets, as the theme's dropdown choices */ + .vt-app .vt-fmenu-item, .vt-app .vt-select option { min-height: var(--vt-ctl); } } @media (prefers-reduced-motion: reduce) { diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js b/luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js index e8dfaa275..5f0643b03 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js @@ -23,6 +23,16 @@ var UNSAFE_TEXT = /[\u0000-\u001f\u007f-\u009f\u00ad\u034f\u061c\u115f\u1160\u17 return baseclass.extend({ DASH: DASH, + /* N_() with English's rule where no catalogue has the string: LuCI + picks the form by the language's rule even then, and a one-form + language (Japanese, Korean...) would show "2 radio up" */ + N_: function(n, singular, plural, ctx) { + var t = N_(n, singular, plural, ctx); + if (n !== 1 && t === singular) return plural; + if (n === 1 && t === plural) return singular; + return t; + }, + /* bits per second -> { v: '372', u: 'Mbit/s' } */ bitsParts: function(bps) { bps = num(bps); @@ -37,13 +47,31 @@ return baseclass.extend({ return p.u ? p.v + ' ' + p.u : p.v; }, - /* compact axis label: 400M, 1.5G, 20k */ - bitsShort: function(bps) { - bps = num(bps); - if (bps == null || bps <= 0) return '0'; - var u = [ '', 'k', 'M', 'G', 'T' ], i = 0; - while (bps >= 1000 && i < u.length - 1) { bps /= 1000; i++; } - return (bps >= 10 ? bps.toFixed(0) : String(+bps.toFixed(1))) + u[i]; + /* a download and upload rate for a row, as { dn, up, unit }: one + unit for both when they read in the same one ('376', '3.4', + 'Mbit/s'), else each with its own and unit '' */ + rateParts: function(down, up) { + var a = this.bitsParts(down), b = this.bitsParts(up); + if (a.u && a.u === b.u) return { dn: a.v, up: b.v, unit: a.u }; + return { dn: a.u ? a.v + ' ' + a.u : a.v, up: b.u ? b.v + ' ' + b.u : b.v, unit: '' }; + }, + + /* '↓ 376 ↑ 3.4 Mbit/s', '↓ 12.3 Mbit/s ↑ 800 bit/s'; 'idle' when + nothing moves */ + rates: function(down, up) { + if (num(down) === 0 && num(up) === 0) return _('idle'); + var p = this.rateParts(down, up); + return '↓ ' + p.dn + ' ↑ ' + p.up + (p.unit ? ' ' + p.unit : ''); + }, + + /* a count, its thousands set apart by a narrow no-break space (as SI + writes them) from five digits on: 20224239 -> '20 224 239' */ + count: function(n) { + n = num(n); + if (n == null) return DASH; + var s = String(Math.round(Math.abs(n))); + if (s.length > 4) s = s.replace(/\B(?=(\d{3})+$)/g, '\u202f'); + return (n < 0 ? '−' : '') + s; }, /* binary units for memory/storage */ @@ -115,10 +143,11 @@ return baseclass.extend({ return /^([0-9a-f]{2}[:-]){5}[0-9a-f]{2}$/i.test(s) ? s.replace(/-/g, ':').toUpperCase() : s; }, - /* last three octets: '…00:53:C1' (the distinguishing part of a MAC) */ + /* last two octets: '53:C1', what tells devices apart in a one-line + name; '' for anything but a MAC */ macTail: function(mac) { var m = this.mac(mac); - return /^([0-9A-F]{2}:){5}[0-9A-F]{2}$/.test(m) ? '…' + m.slice(9) : m; + return /^([0-9A-F]{2}:){5}[0-9A-F]{2}$/.test(m) ? m.slice(12) : ''; }, /* Client- or radio-supplied text for display: invisible/reordering diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/fwglance.js b/luci-app-vantage/htdocs/luci-static/resources/vantage/fwglance.js index 2fab6b37f..4ae7465c3 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/vantage/fwglance.js +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/fwglance.js @@ -245,11 +245,6 @@ function ipBytes(a) { return out.concat(tail); } -function ipFamily(a) { - var b = ipBytes(a); - return b ? (b.length === 4 ? 4 : 6) : 0; -} - /* the leading one bits of a mask, -1 when they are not contiguous */ function maskBits(m) { var bits = 0, zero = false; @@ -782,9 +777,10 @@ return baseclass.extend({ families: fams }; }; + /* the admin ports (ADMIN_PORTS) it opens to any address, [] for none */ var admin = function(item, ports) { - return item.from.anywhere && (item.proto[0] === 'all' || item.proto.indexOf('tcp') >= 0) && - ADMIN_PORTS.some(function(p) { return hasPort(ports, p); }); + if (!item.from.anywhere || !(item.proto[0] === 'all' || item.proto.indexOf('tcp') >= 0)) return []; + return ADMIN_PORTS.filter(function(p) { return hasPort(ports, p); }); }; /* standard housekeeping: ping and other control messages, multicast membership, DHCP client replies, IPsec passed on to a host */ @@ -848,8 +844,9 @@ return baseclass.extend({ return; } open.push(item); - if (admin(item, item.ports)) - warnFor(s, { level: 'warn', code: 'admin-open', kind: 'rule', name: item.name, ports: item.portText }); + var a = admin(item, item.ports); + if (a.length) + warnFor(s, { level: 'warn', code: 'admin-open', kind: 'rule', name: item.name, ports: item.portText, admin: a }); }); of('redirect').forEach(function(s) { @@ -881,16 +878,17 @@ return baseclass.extend({ var first = function(f) { return r.dest_ip.addrs.filter(function(a) { return a.family === f; })[0]; }; item.local = !r.dest_ip ? true : (!own || !r.dest_ip.addrs) ? null : item.families.some(function(f) { var a = first(f); return !a || isOwn(a); }); + var a = admin(item, inner); if (item.local === null) { fwd.push(item); - if (admin(item, inner)) - warnFor(s, { level: 'warn', code: 'admin-unsure', kind: 'redirect', name: item.name, host: item.host, ports: item.portText }); + if (a.length) + warnFor(s, { level: 'warn', code: 'admin-unsure', kind: 'redirect', name: item.name, host: item.host, ports: item.portText, admin: a }); return; } if (!item.local) { fwd.push(item); return; } open.push(item); - if (admin(item, inner)) - warnFor(s, { level: 'warn', code: 'admin-open', kind: 'redirect', name: item.name, ports: item.portText }); + if (a.length) + warnFor(s, { level: 'warn', code: 'admin-open', kind: 'redirect', name: item.name, ports: item.portText, admin: a }); }); /* custom rules: files the firewall config names, whose rules this diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js b/luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js index 286d079ef..c891b6c43 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js @@ -21,7 +21,6 @@ var WEAK_DBM = -75; function num(v) { v = +v; return isFinite(v) ? v : 0; } function finite(v) { return typeof v === 'number' && isFinite(v); } function own(o, k) { return o != null && Object.prototype.hasOwnProperty.call(o, k); } -function speedShort(mbps) { return mbps >= 1000 ? (mbps / 1000) + 'G' : mbps + 'M'; } function speedLong(mbps) { return mbps >= 1000 ? _('%s Gbit/s').format(mbps / 1000) : _('%s Mbit/s').format(mbps); } function rank(level) { return { err: 3, warn: 2, info: 1, ok: 0 }[level] || 0; } @@ -53,10 +52,11 @@ return baseclass.extend({ detail: _('%s negotiated only %d Mbit/s; a cable pair or port may be faulty').format(up.dev, up.speed.mbps), page: PAGES.network }); else { var rate = live.uplinkRate && finite(live.uplinkRate.rx) && finite(live.uplinkRate.tx) ? live.uplinkRate : null; - /* no-break spaces keep '↑ 2.9 Mbit/s' and '2.5G link' whole when the chip wraps */ - var link = up.speed ? _('%s link').format(speedShort(up.speed.mbps)).replace(/ /g, '\u00a0') : null; + /* no-break spaces keep '↑ 2.9 Mbit/s' and '2.5 Gbit/s link' whole when the chip wraps */ + var link = up.speed ? _('%s link').format(speedLong(up.speed.mbps)).replace(/ /g, '\u00a0') : null; out.push({ id: 'uplink', level: 'ok', title: _('Uplink', 'vantage'), value: rate ? '↓ ' + fmt.bits(rate.rx) : _('Up', 'vantage'), - reason: [ rate ? ('↑ ' + fmt.bits(rate.tx)).replace(/ /g, '\u00a0') : null, up.dev, link ].filter(Boolean).join(' · '), + /* the device name only until there is a rate (the path names it) */ + reason: [ rate ? ('↑ ' + fmt.bits(rate.tx)).replace(/ /g, '\u00a0') : up.dev, link ].filter(Boolean).join(' · '), detail: (up.speed ? _('%s up at %s').format(up.dev, speedLong(up.speed.mbps)) : _('%s up').format(up.dev)) + (up.gateway ? ', ' + _('gateway %s').format(up.gateway) : '') + (rate ? '; ' + _('now %s down, %s up').format(fmt.bits(rate.rx), fmt.bits(rate.tx)) : ''), @@ -70,8 +70,9 @@ return baseclass.extend({ var hot = live.temps && live.temps[0] ? fmt.celsius(live.temps[0].celsius) : null; if (cpu == null) out.push({ id: 'cpu', level: 'info', title: _('CPU', 'vantage'), value: fmt.DASH, reason: _('Measuring…'), detail: _('Measuring over the next poll'), page: PAGES.processes }); else out.push({ id: 'cpu', level: cpu >= 90 ? 'err' : cpu >= 70 ? 'warn' : 'ok', title: _('CPU', 'vantage'), value: fmt.pct(cpu), - reason: (cpu >= 70 ? _('Busy · load %s').format(fmt.load(load)) : _('Load %s · %d cores').format(fmt.load(load), cores)) + (hot ? ' · ' + hot : ''), - detail: (cpu >= 70 ? _('Busy; load %s on %d cores; see the busiest processes').format(fmt.load(load), cores) : _('Load %s on %d cores').format(fmt.load(load), cores)) + + reason: (cpu >= 70 ? _('Busy · load %s').format(fmt.load(load)) : fmt.N_(cores, 'Load %s · %d core', 'Load %s · %d cores').format(fmt.load(load), cores)) + (hot ? ' · ' + hot : ''), + detail: (cpu >= 70 ? fmt.N_(cores, 'Busy; load %s on %d core; see the busiest processes', 'Busy; load %s on %d cores; see the busiest processes').format(fmt.load(load), cores) + : fmt.N_(cores, 'Load %s on %d core', 'Load %s on %d cores').format(fmt.load(load), cores)) + (hot ? ' · ' + _('Temperature %s').format(hot) : ''), page: PAGES.processes }); @@ -96,33 +97,40 @@ return baseclass.extend({ }, /* the Wi-Fi and Signal checks, appended to out; an SSID without - clients is normal, not a fault */ + clients is idle, not a fault */ wifiHealth: function(model, out) { var radios = model.radios || [], nSsid = (model.ssids || []).length; var off = radios.filter(function(r) { return r.disabled; }), down = radios.filter(function(r) { return !r.disabled && !r.up; }); var idle = (model.ssids || []).filter(function(s) { return s.up && !s.clients; }); if (!radios.length) out.push({ id: 'radios', level: 'info', title: _('Wi-Fi'), value: _('None'), reason: _('No radios reported'), detail: _('This device reports no radios'), page: PAGES.wireless }); - else if (down.length) out.push({ id: 'radios', level: 'err', title: _('Wi-Fi'), value: _('%d down').format(down.length), reason: _('%s is not up').format(down[0].bandLabel), + else if (down.length) out.push({ id: 'radios', level: 'err', title: _('Wi-Fi'), value: fmt.N_(down.length, '%d radio down', '%d radios down').format(down.length), reason: _('%s is not up').format(down[0].bandLabel), detail: _('%s (%s) is enabled but not up').format(down[0].id, down[0].bandLabel), page: PAGES.wireless }); - else if (off.length) out.push({ id: 'radios', level: 'warn', title: _('Wi-Fi'), value: _('%d off').format(off.length), reason: _('%s is disabled').format(off[0].bandLabel), + else if (off.length) out.push({ id: 'radios', level: 'warn', title: _('Wi-Fi'), value: fmt.N_(off.length, '%d radio off', '%d radios off').format(off.length), reason: _('%s is disabled').format(off[0].bandLabel), detail: _('%s (%s) is disabled').format(off[0].id, off[0].bandLabel), page: PAGES.wireless }); - else out.push({ id: 'radios', level: 'ok', title: _('Wi-Fi'), value: _('%d up').format(radios.length), - reason: idle.length ? _('%d SSIDs · %d idle').format(nSsid, idle.length) : _('%d SSIDs on air').format(nSsid), - detail: idle.length ? _('%d SSIDs broadcasting; %d without clients, which is fine').format(nSsid, idle.length) : _('%d SSIDs broadcasting').format(nSsid), + else out.push({ id: 'radios', level: 'ok', title: _('Wi-Fi'), value: fmt.N_(radios.length, '%d radio up', '%d radios up').format(radios.length), + reason: idle.length ? fmt.N_(nSsid, '%d SSID · %d idle', '%d SSIDs · %d idle').format(nSsid, idle.length) : fmt.N_(nSsid, '%d SSID on air', '%d SSIDs on air').format(nSsid), + detail: idle.length ? fmt.N_(nSsid, '%d SSID broadcasting, %d idle', '%d SSIDs broadcasting, %d idle').format(nSsid, idle.length) : fmt.N_(nSsid, '%d SSID broadcasting', '%d SSIDs broadcasting').format(nSsid), page: PAGES.wireless }); /* signal */ var clients = model.clients || []; var weak = clients.filter(function(c) { return c.signal != null && c.signal < WEAK_DBM; }).sort(function(a, b) { return a.signal - b.signal; }); - if (!clients.length) out.push({ id: 'signal', level: 'info', title: _('Signal'), value: _('No clients'), reason: _('Nobody associated'), detail: _('No stations are associated right now'), page: PAGES.wireless }); + var heard = clients.filter(function(c) { return c.signal != null; }).sort(function(a, b) { return a.signal - b.signal; }); + if (!clients.length) out.push({ id: 'signal', level: 'info', title: _('Signal'), value: _('No clients'), reason: '', detail: _('No stations are associated right now'), page: PAGES.wireless }); else if (weak.length) out.push({ id: 'signal', level: 'warn', title: _('Signal'), value: _('%d weak').format(weak.length), - reason: _('%s · %s').format(weak[0].name, fmt.dbm(weak[0].signal)), + /* the level stays in one piece when the line wraps */ + reason: _('%s · %s').format(weak[0].name, fmt.dbm(weak[0].signal).replace(/ /g, '\u00a0')), detail: _('%s at %s; below %s roaming and throughput suffer').format(weak[0].name, fmt.dbm(weak[0].signal), fmt.dbm(WEAK_DBM)), page: PAGES.wireless, /* one weak client opens its details, several the list of them (the weakest's details where the layout hides that list) */ client: weak[0].mac, list: weak.length > 1 ? 'weak' : null }); - else out.push({ id: 'signal', level: 'ok', title: _('Signal'), value: _('All good'), reason: _('All above %s').format(fmt.dbm(WEAK_DBM)), - detail: _('All %d clients above %s').format(clients.length, fmt.dbm(WEAK_DBM)), page: PAGES.wireless }); + /* all fine: the weakest, which is how close the network is to a problem */ + else out.push({ id: 'signal', level: 'ok', title: _('Signal'), value: heard.length ? fmt.dbm(heard[0].signal) : fmt.DASH, + reason: !heard.length ? _('Not reported by the driver') : heard.length === 1 ? _('The only measured client') + : fmt.N_(heard.length, 'Weakest of %d client', 'Weakest of %d clients').format(heard.length), + detail: !heard.length ? _('The driver reports no signal levels') + : heard.length === 1 ? _('The one measured client is above %s').format(fmt.dbm(WEAK_DBM)) + : fmt.N_(heard.length, '%d measured client is above %s', '%d measured clients are above %s').format(heard.length, fmt.dbm(WEAK_DBM)), page: PAGES.wireless }); }, /* -> { level, count (warn+err), headline } */ @@ -248,8 +256,6 @@ return baseclass.extend({ else if (!r.up) notes.push({ level: 'err', text: _('Radio is enabled but not up') }); if (top === r.id && sum > 0 && (radios.length > 1)) notes.push({ level: 'info', text: _('Busiest radio: %s of Wi-Fi traffic').format(fmt.pct(v / sum * 100)) }); if (r.legacy) notes.push({ level: 'info', text: r.legacy === 1 ? _('1 older device (Wi-Fi 4 or earlier) slows airtime') : _('%d older devices (Wi-Fi 4 or earlier) slow airtime').format(r.legacy) }); - if (r.noise == null && r.noiseRaw != null) notes.push({ level: 'muted', text: _('Noise floor not reported by the driver') }); - if (r.up && !r.clients) notes.push({ level: 'muted', text: _('No clients; idle radios are fine') }); out[r.id] = { busiest: top === r.id && sum > 0, share: sum > 0 ? v / sum : 0, notes: notes }; }); return out; diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/layout.js b/luci-app-vantage/htdocs/luci-static/resources/vantage/layout.js index 2b6fb6d2b..074739dae 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/vantage/layout.js +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/layout.js @@ -25,7 +25,7 @@ var MIN = { }; /* tiles whose content grows to fill a taller slot */ -var FLEX = { chart: true }; +var FLEX = { chart: true, radios: true }; /* how far a tile stretches to line up with the tile below it */ var SNAP = 48; diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/model.js b/luci-app-vantage/htdocs/luci-static/resources/vantage/model.js index fef3cb15d..c1b924e2b 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/vantage/model.js +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/model.js @@ -564,6 +564,7 @@ return baseclass.extend({ mac: mac, macLabel: fmt.mac(mac), name: nm.name, + plainName: nm.plain, nameSource: nm.source, nameSourceLabel: nm.sourceLabel, icon: nm.icon, @@ -625,6 +626,7 @@ return baseclass.extend({ mac: mac, macLabel: fmt.mac(mac), name: nm.name, + plainName: nm.plain, nameSource: nm.source, nameSourceLabel: nm.sourceLabel, icon: nm.icon, diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/names.js b/luci-app-vantage/htdocs/luci-static/resources/vantage/names.js index 8f888ee0d..ff0c10ab2 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/vantage/names.js +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/names.js @@ -20,7 +20,7 @@ wps the device name the station sends in its WPS element vendor manufacturer from the OUI of a globally unique MAC private "Private device" for a locally administered MAC - mac "Device" as the last resort + mac "Unknown device" as the last resort Pure functions; names are untrusted and only ever rendered as text. */ @@ -238,7 +238,11 @@ return baseclass.extend({ /* Resolve the display name of one station. s: { mac, alias: { name, icon }, ips: [..], rdns: { ip: name }, mdns: { ip: name }, hint: { name }, wps, vendor } - -> { name, source, sourceLabel, icon, secondary, isPrivate } */ + -> { name, plain, source, sourceLabel, icon, secondary, isPrivate } + Without a name (vendor, private, mac) name is the one-line label, + which carries the MAC's last two octets ("Private device 53:0F"), + and plain the same without them, for where the MAC sits beside + it; otherwise both are the name. */ resolve: function(s) { s = s || {}; var self = this, mac = this.normMac(s.mac) || str(s.mac); @@ -261,16 +265,18 @@ return baseclass.extend({ if (!name && (name = fromIps(s.mdns))) source = 'mdns'; if (!name && s.wps && (name = fmt.safeText(str(s.wps).trim(), NAME_MAX) || null)) source = 'wps'; - var tail = fmt.macTail(mac); + var plain = name, tail = fmt.macTail(mac); if (!name) { - if (priv) { name = _('Private device') + ' · ' + tail; source = 'private'; } - else if (s.vendor) { name = _('%s device').format(fmt.safeText(s.vendor, 32)) + ' · ' + tail; source = 'vendor'; } - else { name = _('Device') + ' · ' + tail; source = 'mac'; } + if (priv) { plain = _('Private device'); source = 'private'; } + else if (s.vendor) { plain = _('%s device').format(fmt.safeText(s.vendor, 32)); source = 'vendor'; } + else { plain = _('Unknown device', 'vantage'); source = 'mac'; } + name = tail ? plain + ' ' + tail : plain; } var icon = (s.alias && this.validIcon(s.alias.icon)) || this.guessIcon(source === 'vendor' ? s.vendor : name) || 'device'; return { name: name, + plain: plain, source: source, sourceLabel: SOURCES[source], icon: icon, diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/series.js b/luci-app-vantage/htdocs/luci-static/resources/vantage/series.js index b49ea5a1d..af8b65c8f 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/vantage/series.js +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/series.js @@ -37,14 +37,6 @@ return baseclass.extend({ return out.length > maxLen ? out.slice(out.length - maxLen) : out; }, - /* a round axis maximum >= v: 1, 2, 2.5, 5 x 10^n */ - niceMax: function(v) { - if (!finite(v) || v <= 0) return 1; - var e = Math.pow(10, Math.floor(Math.log10(v))), f = v / e; - var n = f <= 1 ? 1 : f <= 2 ? 2 : f <= 2.5 ? 2.5 : f <= 5 ? 5 : 10; - return n * e; - }, - /* a round axis maximum >= v with finer steps (1, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10 x 10^n), so a 374 Mbit/s peak gets a 400 axis, not 500 */ niceCeil: function(v) { diff --git a/luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js b/luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js index 711b19f9f..edae09f7a 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js +++ b/luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js @@ -45,7 +45,6 @@ var ICONS = { globe: [ 'M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18Z', 'M3.4 9.2h17.2M3.4 14.8h17.2', 'M12 3c2.4 2.5 3.6 5.5 3.6 9s-1.2 6.5-3.6 9c-2.4-2.5-3.6-5.5-3.6-9s1.2-6.5 3.6-9Z' ], zones: [ 'M4 5.5h6.5v6.5H4zM13.5 5.5H20v6.5h-6.5zM8.75 15.5h6.5V22h-6.5z', 'M7.25 12v1.75h9.5V12M12 13.75v1.75' ], off: [ 'M12 3.5a8.5 8.5 0 1 0 0 17a8.5 8.5 0 1 0 0-17Z', 'M6 6l12 12' ], - check: [ 'M5 12.5l4.5 4.5L19 7.5' ], warn: [ 'M10.3 4.6 3 17.5A2 2 0 0 0 4.7 20.5h14.6A2 2 0 0 0 21 17.5L13.7 4.6a2 2 0 0 0-3.4 0Z', 'M12 9.5v4.5', 'M12 17h.01' ], err: [ 'M12 3.5a8.5 8.5 0 1 0 0 17a8.5 8.5 0 1 0 0-17Z', 'M9 9l6 6M15 9l-6 6' ], chevron: [ 'M9.5 6l6 6-6 6' ], @@ -116,9 +115,16 @@ function named(item) { return item.kind === 'redirect' ? _('Unnamed port forward') : _('Unnamed rule', 'vantage'); } +/* a zone's input policy: neutral, whatever it is, except an internet + zone that accepts */ function polBadge(p, risky) { - var cls = risky ? 'is-risk' : p === 'ACCEPT' ? 'is-accept' : 'is-stop'; - return E('span', { 'class': 'vt-fg-pol ' + cls }, [ p === 'ACCEPT' ? _('accept', 'vantage') : p === 'DROP' ? _('drop', 'vantage') : _('reject', 'vantage') ]); + return E('span', { 'class': 'vt-fg-pol' + (risky ? ' is-risk' : '') }, [ p === 'ACCEPT' ? _('accept', 'vantage') : p === 'DROP' ? _('drop', 'vantage') : _('reject', 'vantage') ]); +} + +/* the admin ports a warning names (fwglance ADMIN_PORTS), by service */ +function adminServices(ports) { + var names = { 22: _('SSH (port 22)'), 23: _('Telnet (port 23)'), 80: _('HTTP (port 80)'), 443: _('HTTPS (port 443)') }; + return (ports || []).map(function(p) { return names[p] || String(p); }).join(', '); } /* a setup fwglance does not follow (its complex) */ @@ -139,6 +145,17 @@ function ignoredWhy(i) { return _('ignored: option %s has a value firewall4 refuses').format(i.bad); } +/* N_() with English's rule where no catalogue has the string (as + vantage.fmt's, which this view doesn't load) */ +var tr = { + N_: function(n, singular, plural, ctx) { + var t = N_(n, singular, plural, ctx); + if (n !== 1 && t === singular) return plural; + if (n === 1 && t === plural) return singular; + return t; + } +}; + return view.extend({ handleSave: null, handleSaveApply: null, @@ -219,7 +236,7 @@ return view.extend({ } else { head = _('Nothing is open in your firewall rules'); - sub = fw.standard.length ? N_(fw.standard.length, 'Only standard housekeeping (ping, DHCP renewals and the like): %d rule', 'Only standard housekeeping (ping, DHCP renewals and the like): %d rules').format(fw.standard.length) : _('Internet-facing: %s').format(facing); + sub = fw.standard.length ? tr.N_(fw.standard.length, 'Only standard housekeeping (ping, DHCP renewals and the like): %d rule', 'Only standard housekeeping (ping, DHCP renewals and the like): %d rules').format(fw.standard.length) : _('Internet-facing: %s').format(facing); } return this.head(fw.level, head, sub); }, @@ -257,12 +274,12 @@ return view.extend({ } else if (w.code === 'admin-unsure') { title = _('%s may open the router\'s admin').format(w.name || w.ports); - reason = _('It forwards SSH or web ports from any address on the internet to %s. The interface list could not be read, so this page cannot tell whether that is the router itself.').format(w.host); + reason = _('It forwards %s from any address on the internet to %s. The interface list could not be read, so this page cannot tell whether that is the router itself.').format(adminServices(w.admin), w.host); tab = 'forwards'; } else { title = _('Router admin open: %s').format(w.name || w.ports); - reason = _('SSH or the web interface answers any address on the internet. Limit the rule to the addresses you use.'); + reason = _('The firewall lets any address on the internet reach %s. Limit the rule to the addresses you use.').format(adminServices(w.admin)); tab = w.kind === 'redirect' ? 'forwards' : 'rules'; } return E('a', { 'class': 'vt-chip vt-chip-' + w.level, 'role': 'listitem', 'href': page(tab) }, [ @@ -316,7 +333,7 @@ return view.extend({ : _('Nothing is open in your firewall rules.') ])); if (fw.standard.length) body.push(E('details', { 'class': 'vt-fg-std' }, [ - E('summary', {}, [ N_(fw.standard.length, 'Standard housekeeping: %d rule', 'Standard housekeeping: %d rules').format(fw.standard.length) ]), + E('summary', {}, [ tr.N_(fw.standard.length, 'Standard housekeeping: %d rule', 'Standard housekeeping: %d rules').format(fw.standard.length) ]), E('p', { 'class': 'vt-hint' }, [ _('Ping and other control messages, multicast, DHCP renewals and IPsec passed on to your network: what every router lets in.') ]), E('div', { 'class': 'vt-fg-rows' }, fw.standard.map(function(i) { return self.row(page('rules'), named(i), [ what(i) ]); 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 7277f5152..f078ca458 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 @@ -20,8 +20,13 @@ text nodes; no string is ever parsed as markup. */ var POLL_S = 5; +/* uplink traffic and CPU are sampled every FAST_S on their own: two + small reads (/proc/stat, the uplink device's counters), where the full + poll makes eight */ +var FAST_S = 2; var WINDOW_MS = 5 * 60 * 1000; /* throughput history shown */ var HIST_MAX = 90; +var HIST_FAST = 160; /* five minutes at FAST_S, and some */ var GONE_KEEP_MS = 5 * 60 * 1000; /* disconnected stations stay listed */ var TALKERS = 3; /* top talkers shown; the tile keeps room for all */ var SWITCH_MS = 30 * 1000; /* LuCI runs swconfig for each switch's link state: at most this often */ @@ -34,6 +39,7 @@ var callInfo = rpc.declare({ object: 'system', method: 'info' }); var callRead = rpc.declare({ object: 'file', method: 'read', params: [ 'path' ], expect: { data: '' } }); var callIfDump = rpc.declare({ object: 'network.interface', method: 'dump', expect: { 'interface': [] } }); var callDevs = rpc.declare({ object: 'network.device', method: 'status', expect: { '': {} } }); +var callDev = rpc.declare({ object: 'network.device', method: 'status', params: [ 'name' ], expect: { '': {} } }); /* luci.vantage is the app's own rpcd ucode plugin: network.wireless status without keys or RADIUS secrets, and the validated alias write */ var callWifi = rpc.declare({ object: 'luci.vantage', method: 'wireless', expect: { '': {} } }); @@ -81,6 +87,16 @@ function reducedMotion() { return !!(window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches); } +/* is the page rendered by the Vantage theme (L.env.media '/luci-static/vantage')? */ +/* the media path of the Vantage theme ('/luci-static/vantage'). Not a + literal after `return`, and no slash-star in it: LuCI's jsmin takes + both for a division and a comment, and the minified view stops parsing */ +var VANTAGE_MEDIA = /(^|[/])vantage[/]*$/; +function vantageTheme() { + var media = L.env.media || ''; + return VANTAGE_MEDIA.test(media); +} + /* ------------------------------------------------------------- SVG kit */ var ICONS = { @@ -92,13 +108,14 @@ var ICONS = { cpu: [ 'M7.5 6h9A1.5 1.5 0 0 1 18 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 6 16.5v-9A1.5 1.5 0 0 1 7.5 6Z', 'M10 10h4v4h-4z', 'M9.5 3v3M14.5 3v3M9.5 18v3M14.5 18v3M3 9.5h3M3 14.5h3M18 9.5h3M18 14.5h3' ], memory: [ 'M4 7.5h16a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7a1 1 0 0 1 1-1Z', 'M7 16.5v2.5M11 16.5v2.5M15 16.5v2.5M19 16.5v2.5', 'M6.5 10.5h3v3h-3zM10.5 10.5h3v3h-3zM14.5 10.5h3v3h-3z' ], disk: [ 'M4.5 6.5c0-1.4 3.4-2.5 7.5-2.5s7.5 1.1 7.5 2.5v11c0 1.4-3.4 2.5-7.5 2.5s-7.5-1.1-7.5-2.5z', 'M4.5 6.5c0 1.4 3.4 2.5 7.5 2.5s7.5-1.1 7.5-2.5', 'M4.5 12c0 1.4 3.4 2.5 7.5 2.5s7.5-1.1 7.5-2.5' ], - clock: [ 'M12 3.5a8.5 8.5 0 1 0 0 17a8.5 8.5 0 1 0 0-17Z', 'M12 7.5V12l3 2' ], + /* an Ethernet jack, front on */ + port: [ 'M5 5.5h14a1.5 1.5 0 0 1 1.5 1.5v8a1.5 1.5 0 0 1-1.5 1.5h-3v2.5h-8V16.5H5A1.5 1.5 0 0 1 3.5 15V7A1.5 1.5 0 0 1 5 5.5Z', 'M8 9v2.5M10.67 9v2.5M13.33 9v2.5M16 9v2.5' ], + signal: [ 'M5 19.5v-3', 'M9.5 19.5v-6.5', 'M14 19.5v-10', 'M18.5 19.5v-14' ], down: [ 'M12 5v14', 'M6.5 13.5 12 19l5.5-5.5' ], up: [ 'M12 19V5', 'M6.5 10.5 12 5l5.5 5.5' ], close: [ 'M6.5 6.5l11 11M17.5 6.5l-11 11' ], search: [ 'M10.5 4.5a6 6 0 1 0 0 12a6 6 0 1 0 0-12Z', 'M15 15l4.5 4.5' ], chevron: [ 'M9.5 6l6 6-6 6' ], - out: [ 'M9 15 16.5 7.5', 'M10 7.5h6.5V14', 'M13 4.5H6A1.5 1.5 0 0 0 4.5 6v12A1.5 1.5 0 0 0 6 19.5h12a1.5 1.5 0 0 0 1.5-1.5v-7' ], check: [ 'M5 12.5l4.5 4.5L19 7.5' ], warn: [ 'M10.3 4.6 3 17.5A2 2 0 0 0 4.7 20.5h14.6A2 2 0 0 0 21 17.5L13.7 4.6a2 2 0 0 0-3.4 0Z', 'M12 9.5v4.5', 'M12 17h.01' ], err: [ 'M12 3.5a8.5 8.5 0 1 0 0 17a8.5 8.5 0 1 0 0-17Z', 'M9 9l6 6M15 9l-6 6' ], @@ -107,7 +124,6 @@ var ICONS = { lock: [ 'M6.5 11h11a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1v-7a1 1 0 0 1 1-1Z', 'M8.5 11V8a3.5 3.5 0 0 1 7 0v3' ], unlock: [ 'M6.5 11h11a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1v-7a1 1 0 0 1 1-1Z', 'M8.5 11V8a3.5 3.5 0 0 1 6.8-1.2' ], users: [ 'M9 11a3.5 3.5 0 1 0 0-7a3.5 3.5 0 1 0 0 7Z', 'M2.5 20c.8-3.4 3.3-5.5 6.5-5.5s5.7 2.1 6.5 5.5', 'M16 4.3a3.5 3.5 0 0 1 0 6.4', 'M18 14.8c1.8.8 3 2.6 3.5 5.2' ], - spark: [ 'M12 3.5v4M12 16.5v4M3.5 12h4M16.5 12h4M6 6l2.6 2.6M15.4 15.4 18 18M6 18l2.6-2.6M15.4 8.6 18 6' ], pulse: [ 'M3 12h4l2.5-6 5 12 2.5-6H21' ], phone: [ 'M8 3h8a1.5 1.5 0 0 1 1.5 1.5v15A1.5 1.5 0 0 1 16 21H8a1.5 1.5 0 0 1-1.5-1.5v-15A1.5 1.5 0 0 1 8 3Z', 'M11 18h2' ], laptop: [ 'M5.5 5.5h13a1 1 0 0 1 1 1v8.5h-15V6.5a1 1 0 0 1 1-1Z', 'M2.5 18.5h19l-1.5-3.5h-16z' ], @@ -213,7 +229,9 @@ function pos(el, xPct, yPct) { marker on the newest value, a faint top grid line and (opts.scale) the axis maximum with its unit. Before a minute of history the data is drawn from the right edge. opts: { min: axis floor, scale: fn(max), - thresh: value for a dashed reference line, threshLabel } */ + thresh: value for a dashed reference line, threshLabel, quiet: no + 'collecting…' note before there is a line, bare: the line and its + area only (no grid, baseline or end marker) } */ function sparkline(data, cols, vmax, cls, opts) { opts = opts || {}; var W = 100, H = 26; @@ -221,15 +239,20 @@ function sparkline(data, cols, vmax, cls, opts) { var s = svgRoot('vt-spark', '0 0 ' + W + ' ' + H); s.setAttribute('preserveAspectRatio', 'none'); wrap.appendChild(s); - s.appendChild(svgPath('M0 0H' + W, 'vt-spark-grid')); - s.appendChild(svgPath('M0 ' + H + 'H' + W, 'vt-spark-base')); + if (!opts.bare) { + s.appendChild(svgPath('M0 0H' + W, 'vt-spark-grid')); + s.appendChild(svgPath('M0 ' + H + 'H' + W, 'vt-spark-base')); + } if (!data || data.length < 2) { wrap.classList.add('vt-sk-empty'); - wrap.appendChild(E('span', { 'class': 'vt-sk-note' }, [ _('collecting…') ])); + if (!opts.quiet) wrap.appendChild(E('span', { 'class': 'vt-sk-note' }, [ _('collecting…') ])); return wrap; } - var t1 = data[data.length - 1][0], t0 = Math.min(data[0][0], t1 - 60000); - var max = vmax > 0 ? vmax : series.niceCeil(Math.max(series.max(data, cols) * 1.05, opts.min || 0)); + /* bare (a card's edge): whatever history there is, across the width, + with headroom so a steady rate doesn't run along the top */ + var t1 = data[data.length - 1][0], t0 = opts.bare ? data[0][0] : Math.min(data[0][0], t1 - 60000); + var max = vmax > 0 ? vmax : opts.bare ? Math.max(series.max(data, cols) * 1.35, opts.min || 0) + : series.niceCeil(Math.max(series.max(data, cols) * 1.05, opts.min || 0)); if (opts.thresh != null) { var ty = H - Math.max(0, Math.min(1, opts.thresh / max)) * H; s.appendChild(svgPath('M0 ' + ty.toFixed(1) + 'H' + W, 'vt-spark-thresh')); @@ -249,13 +272,23 @@ function sparkline(data, cols, vmax, cls, opts) { s.appendChild(g); if (k === 0) { var last = segs.length ? segs[segs.length - 1] : null, pt = last && last[last.length - 1]; - if (pt) wrap.appendChild(pos(E('span', { 'class': 'vt-sk-dot' }), pt[0] / W * 100, pt[1] / H * 100)); + if (pt && !opts.bare) wrap.appendChild(pos(E('span', { 'class': 'vt-sk-dot' }), pt[0] / W * 100, pt[1] / H * 100)); } }); if (opts.scale) wrap.appendChild(E('span', { 'class': 'vt-sk-max vt-tn' }, [ opts.scale(max) ])); return wrap; } +/* a thin bar filled to pct, in the warning colours at warn and err */ +function fillBar(pct, level) { + var f = E('span', { 'class': 'vt-bar-fill' + (level === 'err' ? ' vt-bg-err' : level === 'warn' ? ' vt-bg-warn' : '') }); + setW(f, Math.max(+pct || 0, 0.8)); + return E('span', { 'class': 'vt-bar vt-chip-bar' }, [ f ]); +} + +/* each health check's own icon (insight.health ids) */ +var CHECK_ICONS = { uplink: 'port', cpu: 'cpu', memory: 'memory', radios: 'wifi', signal: 'signal', storage: 'disk' }; + /* -------------------------------------------------------------- helpers */ /* text writes only when the text changes: an unchanged poll leaves the @@ -316,6 +349,10 @@ function avatar(c, small) { return el; } +/* a client named after its address (vendor, private or MAC fallback, + names.resolve): plainName is the name without the MAC's octets */ +function madeName(c) { return !!c.plainName && c.plainName !== c.name; } + function bandBadge(band, label) { return E('span', { 'class': 'vt-band vt-band-' + (band || 'x') }, [ label || wifi.bandLabel(band) ]); } @@ -378,6 +415,22 @@ function pageLink(page, label) { return E('a', { 'class': 'vt-link', 'href': L.url.apply(L, page) }, [ E('span', {}, [ label ]), icon('chevron') ]); } +/* LuCI's own landing pages: luci-mod-dashboard's, where the app's menu.d + file moves it, and Status -> Overview */ +var LUCI_DASHBOARD = [ 'admin', 'status', 'dashboard' ]; +var LUCI_OVERVIEW = [ 'admin', 'status', 'overview' ]; + +/* Is luci-theme-vantage installed? A HEAD for its menu script, a static + file from the server this view came from: no ACL, nothing new on the + device. The menu.d depends can't tell: LuCI caches the menu tree and a + theme switch doesn't renew it. Anything but a script (a 404, an error + page, no answer) reads as not installed, which keeps the dashboard */ +function themeInstalled() { + return fetch(L.resource('menu-vantage.js'), { method: 'HEAD', cache: 'no-store' }).then(function(r) { + return r.ok && /javascript/i.test(r.headers.get('Content-Type') || ''); + }).catch(function() { return false; }); +} + /* axis labels: round numbers without a trailing '.0' ('15 Mbit/s') */ function bitsLabel(v) { var p = fmt.bitsParts(v); @@ -405,16 +458,22 @@ function writeStore(v) { } /* Sections that fold on narrow screens; the choice is remembered per - browser. Defaults keep the phone page short: radios and the network - path start condensed. */ -var FOLD_KEY = 'vantage.fold.v1'; -var FOLD_DEFAULT = { radios: true, hero: true, ssids: false, chart: false, sys: false }; + browser. The radios start condensed; the network path starts open + (since 1.0.15: v1 kept it folded, so its other + choices carry over without that one). */ +var FOLD_KEY = 'vantage.fold.v2'; +var FOLD_KEY_V1 = 'vantage.fold.v1'; +var FOLD_DEFAULT = { radios: true, hero: false, ssids: false, chart: false, sys: false }; function readFolds() { - var out = Object.assign({}, FOLD_DEFAULT), v = null; + var out = Object.assign({}, FOLD_DEFAULT), v = null, old = false; try { v = JSON.parse(window.localStorage.getItem(FOLD_KEY) || 'null'); } catch (e) { v = null; } + if (!v || typeof v !== 'object') { + try { v = JSON.parse(window.localStorage.getItem(FOLD_KEY_V1) || 'null'); } catch (e) { v = null; } + old = true; + } if (v && typeof v === 'object') - Object.keys(FOLD_DEFAULT).forEach(function(k) { if (typeof v[k] === 'boolean') out[k] = v[k]; }); + Object.keys(FOLD_DEFAULT).forEach(function(k) { if (typeof v[k] === 'boolean' && !(old && k === 'hero')) out[k] = v[k]; }); return out; } @@ -486,22 +545,56 @@ return view.extend({ /* ---------------------------------------------------------- loading */ load: function() { - return Promise.all([ - loadCss(), - L.resolveDefault(callBoard(), {}), - L.resolveDefault(callAccess('access-group', 'luci-app-vantage-names', 'write'), false), - this.loadAliases(), - L.resolveDefault(callMdns(), null), - this.fetch(), - /* reverse DNS is an optional grant: without it, skip it quietly */ - L.resolveDefault(callAccess('access-group', 'luci-app-vantage-rdns', 'read'), false), - L.resolveDefault(ui.menu.load(), null) - ]).then(function(r) { + var self = this; + return this.stepAside().then(function() { + return Promise.all([ + loadCss(), + L.resolveDefault(callBoard(), {}), + L.resolveDefault(callAccess('access-group', 'luci-app-vantage-names', 'write'), false), + self.loadAliases(), + L.resolveDefault(callMdns(), null), + self.fetch(), + /* reverse DNS is an optional grant: without it, skip it quietly */ + L.resolveDefault(callAccess('access-group', 'luci-app-vantage-rdns', 'read'), false), + L.resolveDefault(ui.menu.load(), null) + ]); + }).then(function(r) { menuTree = r[7] || null; return { board: r[1] || {}, canWrite: r[2] === true, mdns: r[4], raw: r[5], canRdns: r[6] === true }; }); }, + /* #83: the page to open instead of the dashboard, or null to stay. + media is L.env.media, the theme LuCI renders with + ('/luci-static/argon'). Only when luci-theme-vantage is installed + but another theme is in use: the app installed alone works under + any theme. Then LuCI's own landing page, luci-mod-dashboard's or + Status -> Overview; a user who may see neither keeps the dashboard + rather than reach an access error */ + asidePage: function(media, themeHere, hasLuciDashboard, hasOverview) { + var theme = (typeof media === 'string') ? media.replace(/\/+$/, '').replace(/^.*\//, '') : ''; + if (!theme || theme === 'vantage' || themeHere !== true) return null; + if (hasLuciDashboard === true) return LUCI_DASHBOARD.slice(); + return hasOverview === false ? null : LUCI_OVERVIEW.slice(); + }, + + /* before load() asks for anything. Under Vantage (or an unnamed theme) + at once; under another, once the theme's file and the menu + answered. Stepping aside replaces the location and never resolves, + so nothing of the dashboard renders or loads */ + stepAside: function() { + var self = this, media = L.env.media; + if (!this.asidePage(media, true, false, true)) return Promise.resolve(); + return Promise.all([ themeInstalled(), L.resolveDefault(ui.menu.load(), null) ]).then(function(r) { + /* without a menu hasPage says yes: Status -> Overview, which every LuCI has */ + menuTree = r[1] || null; + var to = self.asidePage(media, r[0], !!menuTree && hasPage(LUCI_DASHBOARD), hasPage(LUCI_OVERVIEW)); + if (!to) return; + window.location.replace(L.url.apply(L, to)); + return new Promise(function() {}); + }); + }, + loadAliases: function() { var self = this; return L.resolveDefault(callUciGet('vantage'), {}).then(function(values) { @@ -589,7 +682,7 @@ return view.extend({ var net = Object.create(null); if (stored.net && typeof stored.net === 'object') Object.keys(stored.net).forEach(function(k) { - if (/^[A-Za-z0-9_.:-]{1,40}$/.test(k)) net[k] = series.valid(stored.net[k], 3, HIST_MAX, now, model.MAX_BPS); + if (/^[A-Za-z0-9_.:-]{1,40}$/.test(k)) net[k] = series.valid(stored.net[k], 3, k === 'uplink' ? HIST_FAST : HIST_MAX, now, model.MAX_BPS); }); var clientHist = Object.create(null); if (stored.clients && typeof stored.clients === 'object') @@ -602,7 +695,7 @@ return view.extend({ this.st = { clock: null, stat: null, cpu: null, devPrev: null, staPrev: null, devRates: Object.create(null), staRates: Object.create(null), radioRates: Object.create(null), ssidRates: Object.create(null), - hist: { net: net, cpu: series.valid(stored.cpu, 2, HIST_MAX, now), mem: series.valid(stored.mem, 2, HIST_MAX, now) }, + hist: { net: net, cpu: series.valid(stored.cpu, 2, HIST_FAST, now), mem: series.valid(stored.mem, 2, HIST_MAX, now) }, clientHist: clientHist, bestStd: Object.create(null), presence: null, isNew: Object.create(null), gone: [], rdns: Object.create(null), rdnsBusy: false, rdnsOff: !data.canRdns, @@ -618,6 +711,13 @@ return view.extend({ this.layouts = readLayouts(); this.chartStyle = readChartStyle(); this.backdropStyle = readBackdrop(); + /* picked under the theme's Appearance (menu-vantage.js), here or + in another tab */ + var self = this, follow = function() { self.setBackdrop(readBackdrop()); }; + if (window.addEventListener) { + window.addEventListener('vantage:backdrop', follow); + window.addEventListener('storage', function(ev) { if (ev.key === BACKDROP_KEY) follow(); }); + } this.editing = false; this.drag = null; this.applyMdns(data.mdns); @@ -637,12 +737,19 @@ return view.extend({ var now = raw.at || Date.now(); st.clock = model.sampleClock(st.clock, now, raw.info && raw.info.localtime); var at = st.clock.at; + /* how far the device's timeline runs from the browser's: the fast + lane stamps its samples on the same timeline (a clock step on + the device moves every row of the chart together) */ + st.skew = at - Date.now(); - /* CPU */ + /* CPU, unless the fast lane samples it (refreshFast); the times + are kept either way, so a reading after the lane stops covers + the last poll, not the time since the page opened */ + var fast = this.fastLive(); var stat = model.parseStat(raw.stat); if (stat) { - var cpu = model.cpuUsage(st.stat, stat); - if (cpu) { st.cpu = cpu; series.push(st.hist.cpu, [ at, cpu.pct ], WINDOW_MS, HIST_MAX); } + var cpu = fast ? null : model.cpuUsage(st.stat, stat); + if (cpu) { st.cpu = cpu; series.push(st.hist.cpu, [ at, cpu.pct ], WINDOW_MS, HIST_FAST); } if (!st.stat || stat.all.total !== st.stat.all.total) st.stat = stat; } st.temps = model.temps(raw.thermal); @@ -676,11 +783,14 @@ return view.extend({ m.radios.forEach(function(r) { var v = sum(r.ifnames); if (v) st.radioRates[r.id] = v; }); st.ssidRates = Object.create(null); m.ssids.forEach(function(s) { var v = s.ifname ? sum([ s.ifname ]) : null; if (v) st.ssidRates[s.id] = v; }); - var upRate = m.uplink ? st.devRates[m.uplink.statsDev] : null; + /* the uplink: the fast lane's own while it samples this uplink's + device; else (no uplink, a new device, the lane stopped) this poll's */ + var upFast = fast && !!m.uplink && st.fastDev === m.uplink.statsDev; + var upRate = upFast ? st.uplinkRate : (m.uplink ? st.devRates[m.uplink.statsDev] : null); st.uplinkRate = upRate || null; /* throughput history (only for ticks that produced a rate) */ - if (upRate) this.pushNet('uplink', at, upRate); + if (upRate && !upFast) this.pushNet('uplink', at, upRate); m.radios.forEach(function(r) { if (st.radioRates[r.id]) self.pushNet(r.id, at, st.radioRates[r.id]); }); /* station counters, per-station history */ @@ -753,7 +863,63 @@ return view.extend({ pushNet: function(key, at, r) { var h = this.st.hist.net[key] || (this.st.hist.net[key] = []); - series.push(h, [ at, r.rx, r.tx ], WINDOW_MS, HIST_MAX); + series.push(h, [ at, r.rx, r.tx ], WINDOW_MS, key === 'uplink' ? HIST_FAST : HIST_MAX); + }, + + /* ------------------------------------------------------- fast lane */ + + /* the fast lane answered within the last three of its periods: until + then (or if it stops) the full poll samples CPU and the uplink */ + fastLive: function() { + return !!(this.st.fastAt && Date.now() - this.st.fastAt < FAST_S * 3000); + }, + + /* every FAST_S: CPU from /proc/stat and the uplink device's counters, + with their own previous samples, so the two lanes never mix */ + refreshFast: function() { + var self = this, st = this.st, up = this.m && this.m.uplink, dev = up && up.statsDev; + if (document.hidden || !this.el) return Promise.resolve(); + return Promise.all([ + L.resolveDefault(callRead('/proc/stat'), ''), + dev ? L.resolveDefault(callDev(dev), null) : Promise.resolve(null) + ]).then(function(r) { + /* rates from the browser's clock, samples on the device's timeline */ + var now = Date.now(), at = now + (st.skew || 0), changed = false; + /* back after a pause (a hidden tab) or on another device: start + over, so the first reading isn't an average over the gap */ + if (!self.fastLive() || st.fastDev !== dev) { st.fastStat = null; st.fastPrev = null; } + /* no uplink, or another device: no rate until this one has two samples */ + if (st.fastDev !== (dev || null) && st.uplinkRate) { st.uplinkRate = null; changed = true; } + st.fastDev = dev || null; + var stat = model.parseStat(r[0]); + if (stat) { + var cpu = model.cpuUsage(st.fastStat, stat); + if (cpu) { st.cpu = cpu; series.push(st.hist.cpu, [ at, cpu.pct ], WINDOW_MS, HIST_FAST); changed = true; } + if (!st.fastStat || stat.all.total !== st.fastStat.all.total) st.fastStat = stat; + } + var s = r[1] && r[1].statistics, counters = Object.create(null); + if (dev && s) counters[dev] = { rx: s.rx_bytes, tx: s.tx_bytes }; + var dr = model.rates(st.fastPrev, counters, now); + st.fastPrev = dr.next; + if (dev && dr.rates[dev]) { st.uplinkRate = dr.rates[dev]; self.pushNet('uplink', at, st.uplinkRate); changed = true; } + /* both answered: the full poll leaves CPU and the uplink to this lane */ + if (stat && (!dev || s)) st.fastAt = now; + if (changed) self.paintFast(); + }); + }, + + /* what a fast sample moves: the cards, the verdict, the path's uplink + wire and backdrop, the System tile's CPU, the throughput chart */ + paintFast: function() { + var st = this.st; + if (!this.m || !this.el || !this.el.root) return; + st.health = insight.health(this.m, { cpu: st.cpu, uplinkRate: st.uplinkRate, temps: st.temps }); + st.summary = insight.summary(st.health); + this.paintHead(); + this.paintHealth(); + if (this.hero) this.updateHero(); + this.paintSystem(); + this.paintChart(); }, /* names beyond what one poll carries: reverse DNS once per new @@ -823,6 +989,9 @@ return view.extend({ refresh: function() { var self = this; if (document.hidden) { this.st.paused = true; this.paintLive(); return Promise.resolve(); } + /* back from a hidden tab: CPU starts over, rather than read as the + average over the time nobody was looking */ + if (this.st.paused) this.st.stat = null; this.st.paused = false; return this.fetch().then(function(raw) { self.ingest(raw); @@ -864,6 +1033,7 @@ return view.extend({ this.paint(); poll.add(L.bind(this.refresh, this), POLL_S); + poll.add(L.bind(this.refreshFast, this), FAST_S); document.addEventListener('visibilitychange', function() { if (!document.hidden && self.st.paused) self.refresh(); else self.paintLive(); @@ -1116,12 +1286,15 @@ return view.extend({ return E('div', { 'class': 'vt-edit-field' }, [ E('label', { 'for': 'vt-chart-style' }, [ _('Throughput chart') ]), pick ]); }, - /* the network path's backdrop, picked under Customize */ + /* the network path's backdrop, picked under Customize; under the + Vantage theme it is in Appearance instead (menu-vantage.js) */ buildBackdropPick: function() { + if (vantageTheme()) return ''; var self = this, names = { 'grid': _('Grid packets'), 'stars': _('Starfield'), 'none': _('None') }; var pick = E('select', { 'class': 'vt-select', 'id': 'vt-backdrop-style', 'change': function(ev) { self.setBackdrop(ev.target.value); } }, backdrop.STYLES.map(function(k) { return E('option', { 'value': k }, [ names[k] ]); })); pick.value = this.backdropStyle; + this.backdropPick = pick; return E('div', { 'class': 'vt-edit-field' }, [ E('label', { 'for': 'vt-backdrop-style' }, [ _('Network path background') ]), pick ]); }, @@ -1130,6 +1303,7 @@ return view.extend({ this.backdropStyle = v; writeBackdrop(v); if (this.backdrop) this.backdrop.style(v); + if (this.backdropPick && this.backdropPick.value !== v) this.backdropPick.value = v; }, setChartStyle: function(v) { @@ -1340,13 +1514,25 @@ return view.extend({ ]); }, + /* the device and its clients; the firmware is in the System tile */ paintHead: function() { - var s = this.st.summary, d = this.m.device; + var s = this.st.summary, clients = this.m.clients.length; this.el.orb.className = 'vt-orb vt-orb-' + s.level; txt(this.el.headline, s.headline); - var clients = this.m.clients.length; - txt(this.el.subline, [ d.model, d.hostname, d.firmware ? d.firmware.replace(/\s+r\d+-[0-9a-f]+$/, '') : null, - this.m.wired ? null : clients === 1 ? _('1 client') : _('%d clients').format(clients) ].filter(Boolean).join(' · ')); + txt(this.el.subline, this.identity(this.m.device).concat( + this.m.wired ? [] : [ clients === 1 ? _('1 client') : _('%d clients').format(clients) ]).join(' · ')); + }, + + /* model and hostname, or the one of them that holds the other + ("Example AX3000", "example-ax3000"), compared in lower case on + letters and digits only */ + identity: function(d) { + /* letters and digits of any script, as the theme's host chip compares them */ + var key = function(v) { return String(v || '').toLowerCase().replace(/[^\p{L}\p{N}]+/gu, ''); }; + var a = key(d.model), b = key(d.hostname); + if (a && b && a.indexOf(b) >= 0) return [ d.model ]; + if (a && b && b.indexOf(a) >= 0) return [ d.hostname ]; + return [ d.model, d.hostname ].filter(Boolean); }, paintLive: function() { @@ -1356,34 +1542,136 @@ return view.extend({ else if (st.lastErr) { state = 'err'; label = _('Reconnecting…', 'vantage'); } else { state = 'ok'; label = _('Live') + ' · ' + fmt.ago(Date.now() - st.lastOk); } this.el.live.className = 'vt-livepill vt-live-' + state; + /* the Vantage theme's poll indicator already says the page is + live: then this pill shows only when it is not */ + this.el.live.hidden = state === 'ok' && vantageTheme(); this.el.live.setAttribute('title', label); txt(this.el.liveText, label); }, /* ----------------------------------------------------------- health */ + /* The health cards: each check with its own icon, tinted only when it + needs attention, its value and reason, and a small picture of the + last minutes or of how full it is. A change of shape (which checks, + a level, where one leads) rebuilds them; otherwise the text and the + pictures update in place, so a focused card keeps its focus. */ paintHealth: function() { - var self = this; - /* the same checks as last poll: leave the chips alone */ - var sig = JSON.stringify(this.st.health.map(function(c) { return [ c.level, c.title, c.value, c.reason, c.detail, c.client, c.list, c.page ]; })); - if (sig === this.healthSig) return; - this.healthSig = sig; - dom.content(this.el.health, this.st.health.map(function(c) { - var ic = c.level === 'ok' ? 'check' : c.level === 'err' ? 'err' : c.level === 'warn' ? 'warn' : 'info'; - var body = [ - E('span', { 'class': 'vt-chip-ico' }, [ icon(ic) ]), - E('span', { 'class': 'vt-chip-main' }, [ - E('span', { 'class': 'vt-chip-top' }, [ E('span', { 'class': 'vt-chip-title' }, [ c.title ]), E('span', { 'class': 'vt-chip-value' }, [ c.value ]) ]), - E('span', { 'class': 'vt-chip-reason' }, [ c.reason ]) - ]) - ]; - if (c.client || c.list) - return E('button', { 'type': 'button', 'class': 'vt-chip vt-chip-' + c.level, 'role': 'listitem', 'title': c.detail || c.reason, - 'click': function() { self.openCheck(c); } }, body); - /* without its page (no block-mount), a check links to the status overview */ - var to = hasPage(c.page) ? c.page : [ 'admin', 'status', 'overview' ]; - return E('a', { 'class': 'vt-chip vt-chip-' + c.level, 'role': 'listitem', 'title': c.detail || c.reason, 'href': L.url.apply(L, to) }, body); - })); + var self = this, checks = this.st.health; + var shape = JSON.stringify(checks.map(function(c) { return [ c.id, c.level, !!(c.client || c.list), c.page ]; })); + if (shape !== this.healthShape) { + this.healthShape = shape; + this.healthCells = checks.map(function(c) { + var cell = { + title: E('span', { 'class': 'vt-chip-title' }), + value: E('span', { 'class': 'vt-chip-value vt-tn' }), + reason: E('span', { 'class': 'vt-chip-reason' }), + viz: E('span', { 'class': 'vt-chip-viz', 'aria-hidden': 'true' }) + }; + var body = [ + E('span', { 'class': 'vt-chip-ico' }, [ icon(CHECK_ICONS[c.id] || 'info') ]), + /* the level in words too, for screen readers (the card says it in colour) */ + E('span', { 'class': 'vt-chip-main' }, [ E('span', { 'class': 'vt-chip-top' }, [ + c.level === 'err' || c.level === 'warn' ? E('span', { 'class': 'vt-sr' }, [ c.level === 'err' ? _('Error') : _('Warning') ]) : '', + cell.title, cell.value ]), cell.reason, cell.viz ]) + ]; + if (c.client || c.list) + cell.el = E('button', { 'type': 'button', 'class': 'vt-chip vt-chip-' + c.level + ' vt-chip-k-' + c.id, 'role': 'listitem', + 'click': function() { self.openCheck(cell.check); } }, body); + else { + /* without its page (no block-mount), a check links to the status overview */ + var to = hasPage(c.page) ? c.page : [ 'admin', 'status', 'overview' ]; + cell.el = E('a', { 'class': 'vt-chip vt-chip-' + c.level + ' vt-chip-k-' + c.id, 'role': 'listitem', 'href': L.url.apply(L, to) }, body); + } + return cell; + }); + dom.content(this.el.health, this.healthCells.map(function(cell) { return cell.el; })); + } + this.healthCells.forEach(function(cell, i) { + var c = checks[i]; + cell.check = c; + txt(cell.title, c.title); + txt(cell.value, c.value); + txt(cell.reason, c.reason); + setTitle(cell.el, c.detail || c.reason); + patch(cell.viz, self.checkPicture(c)); + }); + }, + + /* the small picture under a health card: the last five minutes for + what moves (uplink traffic, CPU), how full for what fills (memory, + storage), each radio's airtime, and how the clients' signals spread */ + checkPicture: function(c) { + var st = this.st, d = (this.m && this.m.device) || {}; + switch (c.id) { + /* the download (the card says the upload) and CPU as an area along + the card's bottom edge; CPU scaled to at least 20 % so a quiet + device still shows its shape */ + case 'uplink': + return [ sparkline(st.hist.net.uplink || [], [ 1 ], 0, 'vt-spark-up', { min: 1000, quiet: true, bare: true }) ]; + case 'cpu': + return [ sparkline(st.hist.cpu || [], [ 1 ], 0, 'vt-spark-cpu', { min: 20, quiet: true, bare: true }) ]; + case 'memory': + /* in use, then the reclaimable cache (part of what is available), as in the System tile */ + if (!d.memory || !d.memory.segments) return []; + return [ E('span', { 'class': 'vt-chip-bar vt-chip-mem' + (c.level === 'ok' ? '' : ' vt-chip-mem-' + c.level) }, d.memory.segments.filter(function(g) { return g.key !== 'free'; }).map(function(g) { + var x = E('span', { 'class': 'vt-chip-mem-' + g.key }); + setW(x, g.pct); + return x; + })) ]; + case 'storage': + return (d.storage || [])[0] ? [ fillBar(d.storage[0].usedPct, c.level) ] : []; + case 'radios': + return this.radioPicture(); + case 'signal': + return this.signalPicture(); + } + return []; + }, + + /* each radio's airtime (how busy its channel is) as a short bar under + its band; nothing where the driver doesn't report airtime */ + radioPicture: function() { + var radios = ((this.m && this.m.radios) || []).filter(function(r) { return !r.disabled && r.airtime != null; }); + if (!radios.length) return this.bandPicture(); + /* two radios on one band: each by its channel too */ + var perBand = {}; + radios.forEach(function(r) { perBand[r.band] = (perBand[r.band] || 0) + 1; }); + return [ E('span', { 'class': 'vt-chip-radios' }, radios.map(function(r) { + var name = (r.bandLabel || r.id) + (perBand[r.band] > 1 && r.channel ? ' · ' + r.channel : ''); + return E('span', { 'class': 'vt-chip-radio vt-band-' + (r.band || 'x') }, [ + E('span', { 'class': 'vt-chip-radio-top' }, [ E('span', {}, [ name ]), E('b', { 'class': 'vt-tn' }, [ fmt.pct(r.airtime) ]) ]), + /* in its band's colour; the figure says how busy */ + fillBar(r.airtime, 'ok') + ]); + })) ]; + }, + + /* without airtime: the Wi-Fi clients by band along the card's bottom + edge, in the bands' colours (as the other cards' lines) */ + bandPicture: function() { + var clients = (this.m && this.m.clients) || [], by = {}; + clients.forEach(function(c) { if (c.band) by[c.band] = (by[c.band] || 0) + 1; }); + var bands = Object.keys(by).sort(); + if (!bands.length) return []; + return [ E('span', { 'class': 'vt-chip-dist vt-chip-bands' }, bands.map(function(b) { + var x = E('span', { 'class': 'vt-chip-band vt-band-' + b }); + setW(x, by[b] / clients.length * 100); + return x; + })) ]; + }, + + /* the clients by signal class (wifi.signal), weakest on the right */ + signalPicture: function() { + var clients = ((this.m && this.m.clients) || []).filter(function(c) { return c.signal != null; }); + if (!clients.length) return []; + var by = { 4: 0, 3: 0, 2: 0, 1: 0 }; + clients.forEach(function(c) { var b = wifi.signal(c.signal).bars; if (by[b] != null) by[b]++; }); + return [ E('span', { 'class': 'vt-chip-dist' }, [ 4, 3, 2, 1 ].filter(function(b) { return by[b]; }).map(function(b) { + var s = E('span', { 'class': 'vt-dist-' + b }); + setW(s, by[b] / clients.length * 100); + return s; + })) ]; }, /* ------------------------------------------------------------- hero */ @@ -1398,11 +1686,9 @@ return view.extend({ el.path.appendChild(el.flows); this.wireMap = Object.create(null); this.hero = null; - el.kpis = E('div', { 'class': 'vt-kpis vt-fold-keep' }); var tile = this.foldable('hero', E('section', { 'class': 'vt-tile vt-hero', 'aria-label': _('Network path') }, [ - tileHead('pulse', _('Network path'), [ E('span', { 'class': 'vt-hint vt-hint-wide' }, [ _('Click any node for details') ]), this.foldButton('hero', _('Show or hide the network path')) ]), - el.path, - el.kpis + tileHead('pulse', _('Network path'), [ this.foldButton('hero', _('Show or hide the network path')) ]), + el.path ])); /* packets or stars behind the path, moved by the uplink's rate */ this.backdrop = backdrop.mount(tile, el.path, this.backdropStyle); @@ -1460,7 +1746,6 @@ return view.extend({ var key = this.heroKey(); if (!this.hero || this.hero.key !== key) this.buildHeroNodes(key); this.updateHero(); - this.paintKpis(); this.paintWireState(); }, @@ -1605,7 +1890,7 @@ return view.extend({ txt(b.kicker, n.proto || _('Interface')); txt(b.title, n.name); txt(b.addr, n.ipv4 ? n.ipv4.split('/')[0] : (n.dev || fmt.DASH)); - txt(b.sub, r ? '↓ ' + fmt.bitsShort(r.tx) + ' ↑ ' + fmt.bitsShort(r.rx) : fmt.DASH); + txt(b.sub, r ? fmt.rates(r.tx, r.rx) : fmt.DASH); b.active = !!(r && r.rx + r.tx > 50e3); b.rate = r ? r.rx + r.tx : 0; }); @@ -1631,15 +1916,17 @@ return view.extend({ var s = ssids[sn.id]; if (!s) return; sn.data = s; - var tone = s.security.tone === 'open' ? 'unlock' : 'lock'; + /* a lock only where the security is open or weak */ + var tone = s.security.tone === 'open' ? 'unlock' : s.security.tone === 'weak' ? 'lock' : null; if (sn.tone !== tone) { - var ico = icon(tone, 'vt-ico-sm'); - if (sn.ico) sn.title.replaceChild(ico, sn.ico); else sn.title.insertBefore(ico, sn.name); + var ico = tone ? icon(tone, 'vt-ico-sm') : null; + if (sn.ico) sn.title.removeChild(sn.ico); + if (ico) sn.title.insertBefore(ico, sn.name); sn.ico = ico; sn.tone = tone; } setClass(sn.el, 'vt-node vt-node-ssid' + (s.clients ? '' : ' vt-node-idle')); - setTitle(sn.el, _('Show the clients of %s').format(s.ssid)); + setTitle(sn.el, _('Show the clients of %s').format(s.ssid) + (tone ? '\n' + s.security.long : '')); txt(sn.name, s.ssid || _('(hidden)')); txt(sn.count, s.clients === 1 ? _('1 client') : _('%d clients').format(s.clients)); var dots = m.clients.filter(function(c) { return c.ssidId === s.id; }).slice(0, 8); @@ -1668,8 +1955,8 @@ return view.extend({ setTitle(sn.el, _('Show the devices on %s').format(sn.port) + (r ? '\n' + _('Port total: %s').format('↓ ' + fmt.bits(r.tx) + ' · ↑ ' + fmt.bits(r.rx)) : '') + (sw ? '\n' + switchNote(sw) : '')); txt(sn.name, one ? sn.port + ' · ' + one.name : sn.port); - txt(sn.count, one ? (one.speed ? fmt.phyRate(one.speed.mbps * 1000) : fmt.DASH) : on.length === 1 ? _('1 device') : _('%d devices').format(on.length)); - txt(sn.rate, r ? '↓ ' + fmt.bitsShort(r.tx) + ' ↑ ' + fmt.bitsShort(r.rx) : fmt.DASH); + txt(sn.count, one ? (one.speed ? fmt.phyRate(one.speed.mbps * 1000) : fmt.DASH) : _('%d devices').format(on.length)); + txt(sn.rate, r ? fmt.rates(r.tx, r.rx) : fmt.DASH); sn.active = !!(r && r.rx + r.tx > 50e3); }); txt(b.title, n === 1 ? _('1 device') : _('%d devices').format(n)); @@ -1678,78 +1965,6 @@ return view.extend({ b.rate = seen ? rx + tx : 0; }, - /* four numbers under the path: who is here, what flows, where, and - who is worst off. The cells stay; only a change of shape (tone, or - whether a cell links somewhere) rebuilds them. */ - paintKpis: function() { - var self = this, specs = this.m.wired ? this.netKpiSpecs() : this.kpiSpecs(); - var shape = specs.map(function(k) { return k.tone + (k.act ? '+' : '-'); }).join(' '); - this.kpiActs = specs.map(function(k) { return k.act; }); - if (this.kpiShape !== shape) { - this.kpiShape = shape; - this.kpiCells = specs.map(function(k, i) { - var c = { label: E('span', { 'class': 'vt-kpi-label' }), value: E('span', { 'class': 'vt-kpi-value vt-tn' }), sub: E('span', { 'class': 'vt-kpi-sub' }) }; - var body = [ c.label, c.value, c.sub ]; - c.el = k.act - ? E('button', { 'type': 'button', 'class': 'vt-kpi vt-kpi-' + k.tone, 'click': function() { var f = self.kpiActs[i]; if (f) f(); } }, body) - : E('div', { 'class': 'vt-kpi vt-kpi-' + k.tone }, body); - return c; - }); - dom.content(this.el.kpis, this.kpiCells.map(function(c) { return c.el; })); - } - this.kpiCells.forEach(function(c, i) { - txt(c.label, specs[i].label); - txt(c.value, specs[i].value); - txt(c.sub, specs[i].sub); - }); - }, - - kpiSpecs: function() { - var self = this, m = this.m, st = this.st, up = st.uplinkRate; - var byBand = {}; - m.clients.forEach(function(c) { byBand[c.band] = (byBand[c.band] || 0) + 1; }); - var bandText = Object.keys(byBand).sort().map(function(b) { return _('%d on %s').format(byBand[b], wifi.bandLabel(b)); }).join(' · '); - /* wired hosts downstream count as clients too */ - var ports = this.wiredPorts(), wiredN = (m.wiredHosts || []).filter(function(c) { return ports.indexOf(c.port) >= 0; }).length; - if (wiredN) bandText = [ bandText, _('%d wired').format(wiredN) ].filter(Boolean).join(' · '); - var busiest = null; - m.radios.forEach(function(r) { var i = st.radioInsights[r.id]; if (i && i.busiest) busiest = { r: r, share: i.share }; }); - var weakest = m.clients.filter(function(c) { return c.signal != null; }).sort(function(a, b) { return a.signal - b.signal; })[0]; - return [ - { label: _('Clients'), value: String(m.clients.length + wiredN), sub: bandText || _('none connected'), tone: 'plain', - act: function() { self.el.clients.scrollIntoView({ behavior: reducedMotion() ? 'auto' : 'smooth', block: 'start' }); } }, - { label: _('Traffic now'), value: up ? '↓ ' + fmt.bits(up.rx) : fmt.DASH, sub: up ? _('↑ %s · via %s').format(fmt.bits(up.tx), m.uplink ? m.uplink.dev : '') : _('measuring'), tone: 'plain', - act: function() { self.openDrawer('uplink', 'uplink'); } }, - busiest ? { label: _('Busiest radio'), value: busiest.r.bandLabel, sub: _('%s of Wi-Fi traffic').format(fmt.pct(busiest.share * 100)), tone: 'plain', - act: function() { self.openDrawer('radio', busiest.r.id); } } - : { label: _('Busiest radio'), value: fmt.DASH, sub: _('no Wi-Fi traffic yet'), tone: 'plain', act: null }, - weakest ? { label: _('Weakest signal'), value: fmt.dbm(weakest.signal), sub: weakest.name, tone: weakest.signal < insight.WEAK_DBM ? 'warn' : 'plain', - act: function() { self.openDrawer('client', weakest.mac); } } - : { label: _('Weakest signal'), value: fmt.DASH, sub: _('no clients'), tone: 'plain', act: null } - ]; - }, - - /* wired-only: what flows, how long the uplink has held, which - networks are up and which is busiest */ - netKpiSpecs: function() { - var self = this, m = this.m, st = this.st, up = st.uplinkRate, link = m.uplink; - var nets = m.networks, upNets = nets.filter(function(n) { return n.up; }); - var busiest = null; - upNets.forEach(function(n) { - var r = n.dev ? st.devRates[n.dev] : null; - if (r && r.rx + r.tx > 0 && (!busiest || r.rx + r.tx > busiest.r.rx + busiest.r.tx)) busiest = { n: n, r: r }; - }); - function toNetwork() { window.location.href = L.url.apply(L, insight.PAGES.network); } - function toUplink() { self.openDrawer('uplink', 'uplink'); } - return [ - { label: _('Traffic now'), value: up ? '↓ ' + fmt.bits(up.rx) : fmt.DASH, sub: up ? _('↑ %s · via %s').format(fmt.bits(up.tx), link ? link.dev : '') : _('measuring'), tone: 'plain', act: toUplink }, - { label: _('Connected for'), value: link && link.uptime != null ? fmt.duration(link.uptime) : fmt.DASH, sub: link ? [ link.iface, link.proto ].filter(Boolean).join(' · ') : _('no uplink'), tone: 'plain', act: toUplink }, - { label: _('Networks'), value: String(upNets.length), sub: nets.length > upNets.length ? _('%d down').format(nets.length - upNets.length) : _('all up'), tone: 'plain', act: toNetwork }, - busiest ? { label: _('Busiest network'), value: busiest.n.name, sub: '↓ ' + fmt.bits(busiest.r.tx) + ' ↑ ' + fmt.bits(busiest.r.rx), tone: 'plain', act: toNetwork } - : { label: _('Busiest network'), value: fmt.DASH, sub: _('no traffic yet'), tone: 'plain', act: toNetwork } - ]; - }, - scheduleWires: function() { var self = this; if (this.wirePending) return; @@ -1953,6 +2168,7 @@ return view.extend({ /* memory: one bar, three named segments */ var mem = d.memory; + el.memBar.hidden = !mem; if (mem) { patch(el.memHead, [ E('span', { 'class': 'vt-mem-avail vt-tn' }, [ _('%s available', 'vantage').format(fmt.pct(mem.availPct)) ]), @@ -1973,7 +2189,13 @@ return view.extend({ })); } else { + /* nothing left of the last reading, so the next one starts afresh */ patch(el.memHead, [ E('span', { 'class': 'vt-muted' }, [ _('Not reported') ]) ]); + dom.content(el.memBar, []); + el.memBar.removeAttribute('aria-label'); + el.memSegs = null; + el.memPct = null; + patch(el.memLegend, []); } if (d.swap) { var sb = E('span', { 'class': 'vt-thin-fill' }); @@ -2052,7 +2274,11 @@ return view.extend({ can run ahead of the browser's: the axis ends at the newest one */ list.forEach(function(s) { var h = net[s.key]; if (h && h.length) now = Math.max(now, h[h.length - 1][0]); }); - var dm = series.domain(list.map(function(s) { return net[s.key]; }), now, 60000, WINDOW_MS); + /* always the full five minutes: while history collects, the lines + start part way across and the minute labels stay where they are + (a span that grew with the history moved them every poll, #71) */ + var dm = series.domain(list.map(function(s) { return net[s.key]; }), now, WINDOW_MS, WINDOW_MS); + dm.full = dm.age >= WINDOW_MS - 1000; var ticks = []; for (var k = 1; k * 60000 < dm.span - 20000; k++) ticks.push(k); var rows = [], samples = 0; @@ -2062,7 +2288,7 @@ return view.extend({ var d = (net[s.key] || []).filter(function(p) { return p[0] >= dm.t0 - POLL_S * 1000; }); var sd = series.stats(d, s.dn, dm.t0), su = series.stats(d, s.up, dm.t0); var last = d.length ? d[d.length - 1] : null, fresh = !!(last && now - last[0] < POLL_S * 3000); - var g = series.chartGeom(style, sd.peak, su.peak); + var g = series.chartGeom(style, sd.peak, su.peak), pk = fmt.rateParts(sd.peak, su.peak); samples = Math.max(samples, sd.n); var svg = svgRoot('vt-mult-svg', '0 0 ' + W + ' ' + H); @@ -2111,7 +2337,10 @@ return view.extend({ E('span', { 'class': 'vt-mult-now vt-mult-now-up', 'title': _('Upload') }, [ dirKey('up'), E('b', { 'class': 'vt-tn' }, [ dirArrow('up'), ' ', fresh && su.now != null ? fmt.bits(last[s.up]) : fmt.DASH ]) ]), E('span', { 'class': 'vt-mult-stats vt-tn' }, sd.n > 1 ? [ - E('span', {}, [ _('peak', 'vantage'), ' ', E('b', {}, [ dirArrow('dn'), ' ' + fmt.bitsShort(sd.peak) ]), ' ', E('b', {}, [ dirArrow('up'), ' ' + fmt.bitsShort(su.peak) ]) ]) + /* each direction its own item, so they wrap in the narrow readout column */ + /* the shared unit on both, so a wrapped line keeps its own */ + E('span', {}, [ _('peak', 'vantage'), ' ', E('b', {}, [ dirArrow('dn'), ' ' + pk.dn ]), pk.unit ? ' ' + pk.unit : '' ]), + E('span', {}, [ E('b', {}, [ dirArrow('up'), ' ' + pk.up ]), pk.unit ? ' ' + pk.unit : '' ]) ] : [ E('span', {}, [ _('measuring…') ]) ]) ]), E('div', { 'class': 'vt-mult-plot vt-chart-' + style }, [ @@ -2138,7 +2367,6 @@ return view.extend({ var age = dm.age; txt(el.chartSub, dm.full ? _('last 5 min') : samples < 2 ? _('collecting · first samples') : _('collecting · %s of data').format(spanShort(age))); - el.plot.classList.toggle('vt-collecting', !dm.full); if (this.ui.hover) this.chartShow(this.ui.hover); }, @@ -2267,7 +2495,7 @@ return view.extend({ } var hist = st.hist.net[r.id] || []; var clients = m.clients.filter(function(c) { return c.radio === r.id; }); - return E('article', { 'class': 'vt-tile vt-radio vt-radio-' + (r.band || 'x') + (r.up ? '' : ' vt-radio-off') + (ins.busiest ? ' vt-radio-busiest' : ''), 'data-radio': r.id }, [ + return E('article', { 'class': 'vt-tile vt-radio vt-radio-' + (r.band || 'x') + (r.up ? '' : ' vt-radio-off'), 'data-radio': r.id }, [ E('header', { 'class': 'vt-radio-head' }, [ bandBadge(r.band), E('span', { 'class': 'vt-radio-name' }, [ r.gen || r.id ]), @@ -2280,11 +2508,12 @@ return view.extend({ E('span', { 'class': 'vt-radio-width vt-tn' }, [ r.width ? _('%s MHz').format(r.width) : '', r.auto ? ' · ' + _('auto') : '' ]) ]), spec, + /* noise and airtime only where the driver reports them */ E('dl', { 'class': 'vt-stats' }, [ kv(_('Clients'), E('span', { 'class': 'vt-tn' }, [ String(r.clients) ])), kv(_('Tx power'), E('span', { 'class': 'vt-tn' }, [ r.txpower != null ? _('%s dBm').format(r.txpower) : fmt.DASH ])), - kv(_('Noise'), r.noise != null ? E('span', { 'class': 'vt-tn' }, [ fmt.dbm(r.noise) ]) : E('span', { 'class': 'vt-muted', 'title': _('The driver reports a placeholder value, so no noise floor or SNR is shown') }, [ _('not reported') ])), - kv(_('Airtime'), r.airtime != null ? E('span', { 'class': 'vt-tn' }, [ fmt.pct(r.airtime) ]) : E('span', { 'class': 'vt-muted' }, [ _('not reported') ])) + r.noise != null ? kv(_('Noise'), E('span', { 'class': 'vt-tn' }, [ fmt.dbm(r.noise) ])) : '', + r.airtime != null ? kv(_('Airtime'), E('span', { 'class': 'vt-tn' }, [ fmt.pct(r.airtime) ])) : '' ]), E('div', { 'class': 'vt-radio-live' }, [ rateLine(rr ? rr.tx : null, rr ? rr.rx : null), @@ -2307,13 +2536,13 @@ return view.extend({ var self = this, el = this.el, ui = this.ui; el.filter = E('input', { 'type': 'text', 'class': 'vt-filter-input', 'placeholder': _('Filter by name, address, SSID…'), 'aria-label': _('Filter clients'), 'autocomplete': 'off', 'spellcheck': 'false', - 'input': function(ev) { self.ui.filter = ev.target.value; self.paintClients(); } }); + 'input': function(ev) { self.ui.filter = ev.target.value; self.pickClients(); } }); el.filterClear = E('button', { 'type': 'button', 'class': 'vt-filter-clear', 'aria-label': _('Clear filter', 'vantage'), 'hidden': 'hidden', 'click': function() { self.setFilter(''); el.filter.focus(); } }, [ icon('close') ]); /* the quick filters sit in a menu at the end of the search box; the one in force shows as a tag in the box, so none is ever hidden */ el.filterTag = E('button', { 'type': 'button', 'class': 'vt-ftag', 'hidden': 'hidden', - 'click': function(ev) { ev.preventDefault(); ui.chip = 'all'; self.paintClients(); el.filter.focus(); } }); + 'click': function(ev) { ev.preventDefault(); ui.chip = 'all'; self.pickClients(); el.filter.focus(); } }); el.filterBtn = E('button', { 'type': 'button', 'class': 'vt-filter-btn', 'aria-haspopup': 'true', 'aria-expanded': 'false', 'aria-label': _('Quick filters'), 'title': _('Quick filters'), 'click': function(ev) { ev.preventDefault(); self.filterMenu(); } }, [ icon('filter') ]); @@ -2370,7 +2599,16 @@ return view.extend({ setFilter: function(v) { this.ui.filter = v; this.el.filter.value = v; + this.pickClients(); + }, + + /* the viewer changed what the Clients tile lists (filter, quick + filter, Wi-Fi or wired): its new height at once. The hold that + keeps the page still is for polls, not for a pick */ + pickClients: function() { + if (this.held) delete this.held.clients; this.paintClients(); + this.scheduleLayout(); }, filterSsid: function(ssid, band) { @@ -2470,7 +2708,7 @@ return view.extend({ dom.content(el.filterMenu, defs.map(function(d) { var sel = ui.chip === d[0]; return E('button', { 'type': 'button', 'role': 'menuitemradio', 'aria-checked': String(sel), 'class': 'vt-fmenu-item' + (d[3] && d[2] ? ' vt-fmenu-warn' : ''), - 'click': function() { ui.chip = d[0]; self.filterMenu(false); self.paintClients(); el.filterBtn.focus(); } }, [ + 'click': function() { ui.chip = d[0]; self.filterMenu(false); self.pickClients(); el.filterBtn.focus(); } }, [ E('span', { 'class': 'vt-fmenu-check', 'aria-hidden': 'true' }, [ sel ? icon('check') : '' ]), E('span', { 'class': 'vt-fmenu-label' }, [ d[1] ]), E('span', { 'class': 'vt-fmenu-n vt-tn' }, [ String(d[2]) ]) @@ -2492,7 +2730,7 @@ return view.extend({ this.kindSig = kindSig; dom.content(el.kinds, !both ? [] : [ [ 'wifi', _('Wi-Fi'), m.clients.length ], [ 'wired', _('Wired'), hosts.length ] ].map(function(k) { return E('button', { 'type': 'button', 'class': 'vt-kind' + (ui.kind === k[0] ? ' vt-kind-on' : ''), 'aria-pressed': String(ui.kind === k[0]), - 'click': function() { if (ui.kind !== k[0]) { ui.kind = k[0]; ui.chip = 'all'; self.paintClients(); } } }, [ + 'click': function() { if (ui.kind !== k[0]) { ui.kind = k[0]; ui.chip = 'all'; self.pickClients(); } } }, [ E('span', {}, [ k[1] ]), E('span', { 'class': 'vt-kind-n vt-tn' }, [ String(k[2]) ]) ]); })); @@ -2594,14 +2832,18 @@ return view.extend({ }, /* the device cell of a client row: avatar, name, where the name comes - from, tags and the address */ + from, tags and the address. A name made up from the address + ("Private device 53:0F") says where it comes from itself, and + drops the octets when the second line is the MAC */ whoCell: function(c, tags) { + var made = madeName(c), label = made && c.secondary === c.macLabel ? c.plainName : c.name; return E('td', { 'class': 'vt-td-name', 'data-title': _('Device') }, [ E('div', { 'class': 'vt-who' }, [ avatar(c), E('div', { 'class': 'vt-who-text' }, [ - E('div', { 'class': 'vt-who-label', 'title': c.name }, [ c.name ]), - E('div', { 'class': 'vt-who-sub' }, [ E('span', { 'class': 'vt-src vt-src-' + c.nameSource, 'title': _('Name from: %s').format(this.sourceText(c)) }, [ c.nameSourceLabel ]) ].concat(tags, [ E('span', { 'class': 'vt-mono vt-who-id' }, [ c.secondary ]) ])) + E('div', { 'class': 'vt-who-label', 'title': label }, [ label ]), + E('div', { 'class': 'vt-who-sub' }, (made ? [] : [ E('span', { 'class': 'vt-src vt-src-' + c.nameSource, 'title': _('Name from: %s').format(this.sourceText(c)) }, [ c.nameSourceLabel ]) ]) + .concat(tags, [ E('span', { 'class': 'vt-mono vt-who-id' }, [ c.secondary ]) ])) ]) ]) ]); @@ -2637,7 +2879,7 @@ return view.extend({ E('div', { 'class': 'vt-live-cell' }, [ E('span', { 'class': 'vt-tn vt-live-total' }, [ r ? fmt.bits(total) : fmt.DASH ]), E('span', { 'class': 'vt-mini' }, [ bar ]), - E('span', { 'class': 'vt-live-split vt-tn', 'title': r ? _('To device %s, from device %s').format(fmt.bits(r.tx), fmt.bits(r.rx)) : '' }, [ r ? '↓ ' + fmt.bitsShort(r.tx) + ' ↑ ' + fmt.bitsShort(r.rx) : '' ]) + E('span', { 'class': 'vt-live-split vt-tn', 'title': r ? _('To device %s, from device %s').format(fmt.bits(r.tx), fmt.bits(r.rx)) : '' }, [ r ? fmt.rates(r.tx, r.rx) : '' ]) ]) ]), E('td', { 'class': 'vt-td-seen vt-tn', 'data-title': _('Last heard') }, [ c.seen == null ? _('static entry') : fmt.ago(c.seen * 1000) ]) @@ -2672,7 +2914,7 @@ return view.extend({ E('div', { 'class': 'vt-live-cell' }, [ E('span', { 'class': 'vt-tn vt-live-total' }, [ r ? fmt.bits(total) : fmt.DASH ]), E('span', { 'class': 'vt-mini' }, [ bar ]), - E('span', { 'class': 'vt-live-split vt-tn', 'title': r ? _('To device %s, from device %s').format(fmt.bits(r.tx), fmt.bits(r.rx)) : '' }, [ r ? '↓ ' + fmt.bitsShort(r.tx) + ' ↑ ' + fmt.bitsShort(r.rx) : '' ]) + E('span', { 'class': 'vt-live-split vt-tn', 'title': r ? _('To device %s, from device %s').format(fmt.bits(r.tx), fmt.bits(r.rx)) : '' }, [ r ? fmt.rates(r.tx, r.rx) : '' ]) ]) ]), E('td', { 'class': 'vt-td-exp', 'data-title': _('Experience') }, c.gone ? [ E('span', { 'class': 'vt-muted' }, [ fmt.DASH ]) ] : [ @@ -2690,7 +2932,7 @@ return view.extend({ buildTalkers: function() { this.el.talkers = E('div', { 'class': 'vt-talkers' }); return E('section', { 'class': 'vt-tile vt-talk', 'aria-label': _('Top talkers', 'vantage') }, [ - tileHead('pulse', _('Top talkers', 'vantage'), [ E('span', { 'class': 'vt-hint' }, [ _('who uses the bandwidth') ]) ]), + tileHead('pulse', _('Top talkers', 'vantage')), this.el.talkers ]); }, @@ -2726,7 +2968,7 @@ return view.extend({ E('span', { 'class': 'vt-talk-top' }, [ E('span', { 'class': 'vt-talk-name', 'title': c.name }, [ c.name ]) ]), E('span', { 'class': 'vt-talk-bar' }, [ fill ]), E('span', { 'class': 'vt-talk-sub vt-tn', 'title': _('To device %s, from device %s').format(fmt.bits(x.down), fmt.bits(x.up)) }, [ - 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) ]) + E('b', {}, [ fmt.bits(x.total) ]), E('span', { 'class': 'vt-talk-share' }, [ fmt.pct(x.share * 100) ]), fmt.rates(x.down, x.up) ]) ]) ]); }).concat(slots)); @@ -2753,12 +2995,13 @@ return view.extend({ var rx = 0, tx = 0, has = false; g.ids.forEach(function(id) { var r = st.ssidRates[id]; if (r) { rx += r.rx; tx += r.tx; has = true; } }); var bands = g.bands.map(function(b) { return bandBadge(b); }); + /* a lock, in amber, only where the security is open or weak */ + var tone = g.security.tone === 'open' ? 'unlock' : g.security.tone === 'weak' ? 'lock' : null; return E('button', { 'type': 'button', 'class': 'vt-ssid' + (g.clients ? '' : ' vt-ssid-idle'), 'title': _('Show the clients of %s').format(g.ssid), 'click': function() { self.filterSsid(g.ssid); } }, [ - E('span', { 'class': 'vt-ssid-ico' + (g.security.tone === 'open' || g.security.tone === 'weak' ? ' vt-t-warn' : '') }, [ icon(g.security.tone === 'open' ? 'unlock' : 'lock') ]), E('span', { 'class': 'vt-ssid-main' }, [ E('span', { 'class': 'vt-ssid-top' }, [ E('span', { 'class': 'vt-ssid-name' }, [ g.ssid || _('(hidden)') ]), g.hidden ? pill(_('Hidden', 'vantage'), 'muted') : '' ]), - E('span', { 'class': 'vt-ssid-meta' }, bands.concat([ E('span', { 'class': 'vt-sec', 'title': g.security.long }, [ g.security.short ]) ])) + E('span', { 'class': 'vt-ssid-meta' }, bands.concat([ E('span', { 'class': 'vt-sec' + (tone ? ' vt-t-warn' : ''), 'title': g.security.long }, [ tone ? icon(tone, 'vt-ico-sm') : '', g.security.short ]) ])) ]), E('span', { 'class': 'vt-ssid-side' }, [ E('span', { 'class': 'vt-ssid-n vt-tn' }, [ String(g.clients) ]), @@ -2788,13 +3031,15 @@ return view.extend({ var el = this.el; this.ui.drawer = { kind: kind, id: id }; this.ui.editing = null; + /* the address names what is shown, also when the open drawer + moves on (from a radio to one of its clients) */ + try { history.replaceState(null, '', '#' + kind + '=' + encodeURIComponent(id)); } catch (e) {} if (!el.drawer.hidden) { this.paintDrawer(); this.paintClients(); return; } this.lastFocus = document.activeElement; el.drawer.hidden = false; el.drawerBack.hidden = false; this.paintDrawer(); this.paintClients(); - try { history.replaceState(null, '', '#' + kind + '=' + encodeURIComponent(id)); } catch (e) {} window.requestAnimationFrame(function() { el.root.classList.add('vt-drawer-open'); el.drawerClose.focus(); }); }, @@ -2846,6 +3091,22 @@ return view.extend({ return E('section', { 'class': 'vt-dsec' + (cls ? ' ' + cls : '') }, [ E('h4', { 'class': 'vt-dsec-title' }, [ title ]) ].concat(children)); }, + /* a client's drawer title: its name, where the name comes from and + its address; a name made up from the MAC shows the MAC instead */ + drawerWho: function(c) { + var made = madeName(c); + return [ + avatar(c), + E('div', { 'class': 'vt-drawer-titles' }, [ + E('div', { 'class': 'vt-drawer-name', 'id': 'vt-drawer-name' }, [ made ? c.plainName : c.name ]), + E('div', { 'class': 'vt-drawer-sub' }, made ? [ E('span', { 'class': 'vt-mono' }, [ c.macLabel ]) ] : [ + E('span', { 'class': 'vt-src vt-src-' + c.nameSource }, [ c.nameSourceLabel ]), + E('span', { 'class': 'vt-mono' }, [ c.secondary ]) + ]) + ]) + ]; + }, + drawerClient: function(mac) { var self = this, st = this.st, c = null, gone = null; this.m.clients.forEach(function(x) { if (x.mac === mac) c = x; }); @@ -2862,16 +3123,7 @@ return view.extend({ var exp = c.exp || insight.experience(c); var radio = this.m.radios.filter(function(x) { return x.id === c.radio; })[0]; - var title = [ - avatar(c), - E('div', { 'class': 'vt-drawer-titles' }, [ - E('div', { 'class': 'vt-drawer-name', 'id': 'vt-drawer-name' }, [ c.name ]), - E('div', { 'class': 'vt-drawer-sub' }, [ - E('span', { 'class': 'vt-src vt-src-' + c.nameSource }, [ c.nameSourceLabel ]), - E('span', { 'class': 'vt-mono' }, [ c.secondary ]) - ]) - ]) - ]; + var title = this.drawerWho(c); var rename = this.canWrite ? E('button', { 'type': 'button', 'class': 'vt-btn vt-btn-ghost', 'click': function() { self.startRename(c); } }, [ icon('pencil'), E('span', {}, [ c.alias ? _('Rename', 'vantage') : _('Name this device') ]) ]) : ''; var sigSeries = hist.map(function(p) { return [ p[0], p[1] ]; }).filter(function(p) { return isFinite(p[1]); }); @@ -2886,7 +3138,7 @@ return view.extend({ E('div', { 'class': 'vt-dactions' }, [ rename, pageLink(insight.PAGES.wireless, _('Wireless settings')) ]), this.el.renameSlot = E('div', { 'class': 'vt-rename-slot' }), c.gone ? '' : E('div', { 'class': 'vt-expcard vt-expcard-' + exp.level }, [ - E('div', { 'class': 'vt-ring vt-tn' }, [ this.ring(exp.score, exp.level), E('span', { 'class': 'vt-ring-n' }, [ String(exp.score) ]) ]), + E('div', { 'class': 'vt-ring vt-tn' }, [ this.ring(exp.score), E('span', { 'class': 'vt-ring-n' }, [ String(exp.score) ]) ]), E('div', { 'class': 'vt-expcard-text' }, [ E('div', { 'class': 'vt-expcard-grade' }, [ _('%s experience').format(exp.grade) ]), E('div', { 'class': 'vt-expcard-reason' }, [ exp.reason ]), @@ -2920,19 +3172,19 @@ return view.extend({ kv(_('Network'), [ c.ssid, ' ', bandBadge(c.band) ]), kv(_('Radio', 'vantage'), radio ? _('%s · channel %d · %d MHz').format(radio.id, radio.channel || 0, radio.width || 20) : c.radio), kv(_('Connected for'), c.gone ? fmt.DASH : fmt.duration(c.connected)), - kv(_('Last activity', 'vantage'), c.inactive == null || c.gone ? fmt.DASH : c.inactive < 1000 ? _('now', 'vantage') : _('%s ago', 'vantage').format(fmt.duration(c.inactive / 1000))), + kv(_('Last activity', 'vantage'), c.inactive == null || c.gone ? fmt.DASH : fmt.ago(c.inactive)), kv(_('Seen since'), c.firstSeen ? (c.isNew ? _('%s (new this session)').format(new Date(c.firstSeen).toLocaleTimeString()) : _('before this page opened')) : fmt.DASH) ]) ]), this.section(_('Traffic'), [ E('dl', { 'class': 'vt-kvs' }, [ kv(_('Downloaded', 'vantage'), fmt.bytes(c.txBytes)), kv(_('Uploaded', 'vantage'), fmt.bytes(c.rxBytes)), - kv(_('Frames to device'), c.txPackets ? _('%d sent · %s retried · %s failed').format(c.txPackets, fmt.pct(c.txRetries / Math.max(1, c.txPackets) * 100, 1), fmt.pct(c.txFailed / Math.max(1, c.txPackets + c.txFailed) * 100, 1)) : fmt.DASH) + kv(_('Frames to device'), c.txPackets ? _('%s sent · %s retried · %s failed').format(fmt.count(c.txPackets), fmt.pct(c.txRetries / Math.max(1, c.txPackets) * 100, 1), fmt.pct(c.txFailed / Math.max(1, c.txPackets + c.txFailed) * 100, 1)) : fmt.DASH) ]) ]), this.section(_('Identity'), [ E('dl', { 'class': 'vt-kvs' }, [ kv(_('MAC address'), c.macLabel, true), kv(_('Address type'), c.isPrivate ? _('Private Wi-Fi address (randomised by the device)') : (c.vendor ? _('Globally unique · %s').format(c.vendor) : _('Globally unique'))), kv(_('IP addresses'), c.ips && c.ips.length ? c.ips.join('\n') : E('span', { 'class': 'vt-muted' }, [ _('not known to this AP') ]), true), - kv(_('Name from'), this.sourceText(c)), + madeName(c) ? '' : kv(_('Name from'), this.sourceText(c)), c.wps && c.nameSource !== 'wps' ? kv(_('WPS device name'), c.wps) : '' ]) ]) ]; @@ -2941,16 +3193,7 @@ return view.extend({ drawerWired: function(c) { var self = this, r = this.portRate(c), shared = c.shared ? this.st.devRates[c.port] : null; - var title = [ - avatar(c), - E('div', { 'class': 'vt-drawer-titles' }, [ - E('div', { 'class': 'vt-drawer-name', 'id': 'vt-drawer-name' }, [ c.name ]), - E('div', { 'class': 'vt-drawer-sub' }, [ - E('span', { 'class': 'vt-src vt-src-' + c.nameSource }, [ c.nameSourceLabel ]), - E('span', { 'class': 'vt-mono' }, [ c.secondary ]) - ]) - ]) - ]; + var title = this.drawerWho(c); var rename = this.canWrite ? E('button', { 'type': 'button', 'class': 'vt-btn vt-btn-ghost', 'click': function() { self.startRename(c); } }, [ icon('pencil'), E('span', {}, [ c.alias ? _('Rename', 'vantage') : _('Name this device') ]) ]) : ''; var speed = c.speed ? model.speedLabel(c.speed) : fmt.DASH; var body = [ @@ -2973,7 +3216,7 @@ return view.extend({ kv(_('MAC address'), c.macLabel, true), kv(_('Address type'), c.isPrivate ? _('Private address (randomised by the device)') : (c.vendor ? _('Globally unique · %s').format(c.vendor) : _('Globally unique'))), kv(_('IP addresses'), c.ips && c.ips.length ? c.ips.join('\n') : E('span', { 'class': 'vt-muted' }, [ _('not known to this device') ]), true), - kv(_('Name from'), this.sourceText(c)) + madeName(c) ? '' : kv(_('Name from'), this.sourceText(c)) ]) ]) ]; return { title: title, body: body }; @@ -2986,14 +3229,12 @@ return view.extend({ case 'mdns': return _('mDNS announcement'); case 'dhcp': return _('DHCP hostname'); case 'wps': return _('The name the device announces (WPS)'); - case 'vendor': return _('Manufacturer of the network adapter'); - case 'private': return _('Nothing better known; the address is randomised'); } return _('Nothing better known'); }, - ring: function(score, level) { - var s = svgRoot('vt-ring-svg vt-lvlc-' + level, '0 0 36 36'); + ring: function(score) { + var s = svgRoot('vt-ring-svg', '0 0 36 36'); var c = 2 * Math.PI * 15.5, f = Math.max(0, Math.min(100, score)) / 100 * c; var track = document.createElementNS(SVGNS, 'circle'); track.setAttribute('cx', '18'); track.setAttribute('cy', '18'); track.setAttribute('r', '15.5'); @@ -3112,7 +3353,9 @@ return view.extend({ kv(_('Mode'), [ r.htmode || fmt.DASH, r.hwmodes ? E('small', {}, [ r.hwmodes ]) : '' ]), kv(_('Centre frequency'), r.spectrum ? _('%d MHz (%d–%d MHz)').format(r.spectrum.centre, r.spectrum.lo, r.spectrum.hi) : fmt.DASH), kv(_('Tx power'), r.txpower != null ? _('%s dBm').format(r.txpower) + (r.txpowerCfg != null && r.txpowerCfg !== r.txpower ? ' ' + _('(configured %d dBm, limited by regulatory rules)').format(r.txpowerCfg) : '') : fmt.DASH), - kv(_('Noise floor'), r.noise != null ? fmt.dbm(r.noise) : E('span', { 'class': 'vt-muted' }, [ r.noiseRaw != null ? _('not reported (driver placeholder %s)').format(fmt.dbm(r.noiseRaw)) : _('not reported') ])), + /* a placeholder from the driver says why there is none */ + r.noise != null ? kv(_('Noise floor'), fmt.dbm(r.noise)) + : r.noiseRaw != null ? kv(_('Noise floor'), E('span', { 'class': 'vt-muted' }, [ _('not reported (driver placeholder %s)').format(fmt.dbm(r.noiseRaw)) ])) : '', kv(_('Country'), r.country || fmt.DASH) ]) ]), this.section(_('Clients on this radio'), clients.length ? [ E('div', { 'class': 'vt-dlist' }, clients.map(function(c) { @@ -3120,13 +3363,14 @@ return view.extend({ avatar(c, true), E('span', { 'class': 'vt-dlist-name' }, [ c.name ]), E('span', { 'class': 'vt-signal' }, [ signalGlyph(c.level), E('span', { 'class': 'vt-tn' }, [ fmt.dbm(c.signal) ]) ]) ]); - })) ] : [ E('p', { 'class': 'vt-empty-inline' }, [ _('No clients; an idle radio is fine.') ]) ]) + })) ] : [ E('p', { 'class': 'vt-empty-inline' }, [ _('No clients connected') ]) ]) ] }; }, drawerUplink: function() { var up = this.m.uplink, r = this.st.uplinkRate; + function errors(n) { return fmt.N_(n, '%s error', '%s errors').format(fmt.count(n)); } if (!up) return { title: [ E('span', { 'class': 'vt-drawer-name' }, [ _('Uplink', 'vantage') ]) ], body: [ E('p', { 'class': 'vt-empty-inline' }, [ _('No interface with a route is up.') ]) ] }; var s = up.stats || {}; return { @@ -3154,9 +3398,9 @@ return view.extend({ kv(_('DNS'), up.dns.join('\n') || fmt.DASH, true) ]) ]), this.section(_('Counters since boot'), [ E('dl', { 'class': 'vt-kvs' }, [ - kv(_('Received', 'vantage'), fmt.bytes(s.rx_bytes) + ' · ' + _('%d errors').format(+s.rx_errors || 0)), - kv(_('Sent', 'vantage'), fmt.bytes(s.tx_bytes) + ' · ' + _('%d errors').format(+s.tx_errors || 0)), - kv(_('Dropped', 'vantage'), _('%d in · %d out').format(+s.rx_dropped || 0, +s.tx_dropped || 0)) + kv(_('Received', 'vantage'), fmt.bytes(s.rx_bytes) + ' · ' + errors(+s.rx_errors || 0)), + kv(_('Sent', 'vantage'), fmt.bytes(s.tx_bytes) + ' · ' + errors(+s.tx_errors || 0)), + kv(_('Dropped', 'vantage'), _('%s in · %s out').format(fmt.count(+s.rx_dropped || 0), fmt.count(+s.tx_dropped || 0))) ]) ]) ] }; @@ -3180,7 +3424,7 @@ return view.extend({ kv(_('Local time'), d.localtime != null ? new Date(d.localtime * 1000).toISOString().replace('T', ' ').replace(/\.\d+Z$/, '') : fmt.DASH, true) ]) ]), this.section(_('Load'), [ E('dl', { 'class': 'vt-kvs' }, [ - kv(_('CPU', 'vantage'), cpu ? _('%s over %d cores').format(fmt.pct(cpu.pct), cpu.cores.length || 1) : fmt.DASH), + kv(_('CPU', 'vantage'), cpu ? fmt.N_(cpu.cores.length || 1, '%s over %d core', '%s over %d cores').format(fmt.pct(cpu.pct), cpu.cores.length || 1) : fmt.DASH), kv(_('Load average', 'vantage'), d.load.map(fmt.load).join(' · ')), kv(_('Memory in use'), d.memory ? _('%s of %s').format(fmt.bytes(d.memory.used), fmt.bytes(d.memory.total)) : fmt.DASH) ]) ]) diff --git a/luci-app-vantage/po/templates/vantage.pot b/luci-app-vantage/po/templates/vantage.pot index 94867b30b..5968746d3 100644 --- a/luci-app-vantage/po/templates/vantage.pot +++ b/luci-app-vantage/po/templates/vantage.pot @@ -1,337 +1,342 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3113 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3354 msgid "%d MHz (%d–%d MHz)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:111 -msgid "%d SSIDs broadcasting" -msgstr "" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:112 +msgid "%d SSID broadcasting" +msgid_plural "%d SSIDs broadcasting" +msgstr[0] "" +msgstr[1] "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:112 +msgid "%d SSID broadcasting, %d idle" +msgid_plural "%d SSIDs broadcasting, %d idle" +msgstr[0] "" +msgstr[1] "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:111 -msgid "%d SSIDs broadcasting; %d without clients, which is fine" -msgstr "" +msgid "%d SSID on air" +msgid_plural "%d SSIDs on air" +msgstr[0] "" +msgstr[1] "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:110 -msgid "%d SSIDs on air" -msgstr "" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:111 +msgid "%d SSID · %d idle" +msgid_plural "%d SSIDs · %d idle" +msgstr[0] "" +msgstr[1] "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:110 -msgid "%d SSIDs · %d idle" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1349 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1644 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2248 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1523 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1931 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2476 msgid "%d clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2575 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2813 msgid "%d connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1671 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1675 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2574 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1958 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1962 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2812 msgid "%d devices" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1747 -msgid "%d down" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3157 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3158 -msgid "%d errors" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:91 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:119 msgctxt "vantage" msgid "%d h ago" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3159 -msgid "%d in · %d out" -msgstr "" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:133 +msgid "%d measured client is above %s" +msgid_plural "%d measured clients are above %s" +msgstr[0] "" +msgstr[1] "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:396 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:449 msgctxt "vantage" 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:390 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:118 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:443 msgctxt "vantage" msgid "%d min ago" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2573 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2811 msgid "%d of %d" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1236 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1410 msgid "%d of %d columns" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:107 -msgid "%d off" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:250 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:258 msgid "%d older devices (Wi-Fi 4 or earlier) slow airtime" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1711 -msgid "%d on %s" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:218 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:235 msgid "%d on this router, %d into your network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2240 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106 +msgid "%d radio down" +msgid_plural "%d radios down" +msgstr[0] "" +msgstr[1] "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108 +msgid "%d radio off" +msgid_plural "%d radios off" +msgstr[0] "" +msgstr[1] "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:110 +msgid "%d radio up" +msgid_plural "%d radios up" +msgstr[0] "" +msgstr[1] "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2468 msgid "%d radios" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:396 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:449 msgctxt "vantage" 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:390 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:117 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:443 msgctxt "vantage" msgid "%d s ago" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2929 -msgid "%d sent · %s retried · %s failed" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:135 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:213 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:143 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:230 msgid "%d things need attention" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:109 -msgid "%d up" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:118 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:120 msgid "%d weak" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1714 -msgid "%d wired" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2259 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2487 msgid "%d–%d MHz of the %d–%d MHz band" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:109 msgid "%s (%s) is disabled" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:107 msgid "%s (%s) is enabled but not up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:201 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:242 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:362 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:218 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:259 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:379 msgid "%s (IPv%d)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2924 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3176 msgid "%s (new this session)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:25 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:24 #: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:212 msgid "%s Gbit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:137 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:166 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:103 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2266 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2280 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2669 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3106 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2494 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2508 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2911 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3347 msgid "%s MHz" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:25 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:52 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:24 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51 #: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:212 msgid "%s Mbit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:230 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:247 msgid "%s accepts every connection" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2923 -msgctxt "vantage" -msgid "%s ago" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:120 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:123 msgid "%s at %s; below %s roaming and throughput suffer" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:82 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1958 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:83 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2174 msgctxt "vantage" msgid "%s available" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2285 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3114 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2514 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3355 msgid "%s dBm" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:267 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:271 msgid "%s device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:166 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:174 msgid "%s device on a newer radio; uses more airtime per byte" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2891 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3373 +msgid "%s error" +msgid_plural "%s errors" +msgstr[0] "" +msgstr[1] "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3143 msgid "%s experience" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:94 msgid "%s free" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:94 msgid "%s free on the overlay (%s used)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:49 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:48 msgid "%s has no carrier: cable unplugged or switch port down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1203 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1377 msgid "%s hidden" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:107 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3403 +msgid "%s in · %s out" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108 msgid "%s is disabled" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:234 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:251 msgid "%s is forwarded into %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:242 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:259 msgid "%s is in no zone and accepts every connection" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1196 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1370 msgid "%s is narrower" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106 msgid "%s is not up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2628 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2870 msgid "" "%s is shared by %d devices (a switch or another access point behind it); its " "%s link is not theirs" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2627 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2869 msgid "%s is shared by %d devices behind the switch" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1199 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1373 msgid "%s is wider" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:254 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:271 msgid "%s lets the internet into %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:56 msgid "%s link" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:259 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:276 msgid "%s may open the router's admin" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1491 msgid "%s moved" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1193 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1367 msgid "%s moved down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1184 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1358 msgid "%s moved left" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1187 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1361 msgid "%s moved right" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1190 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1364 msgid "%s moved up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:50 msgid "%s negotiated half duplex; check the cable and switch port" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:52 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:83 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1959 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1982 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3185 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:84 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2175 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3429 msgid "%s of %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:84 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:85 msgid "%s of %s available (%s in use)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1723 -msgid "%s of Wi-Fi traffic" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:161 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:162 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:169 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:170 msgid "%s of frames fail" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:162 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:170 msgid "%s of frames to the device fail" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:161 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:169 msgid "%s of frames to the device fail; interference likely" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3183 -msgid "%s over %d cores" -msgstr "" +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3427 +msgid "%s over %d core" +msgid_plural "%s over %d cores" +msgstr[0] "" +msgstr[1] "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2044 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2266 msgid "%s radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1242 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3181 +msgid "%s sent · %s retried · %s failed" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1416 msgid "%s shown" msgstr "" @@ -343,73 +348,72 @@ msgstr "" msgid "%s up at %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:92 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93 msgid "%s used" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1990 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2212 msgid "%s used of %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2625 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2867 msgid "%s · %d devices" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:119 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:122 msgid "%s · %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2921 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3173 msgid "%s · channel %d · %d MHz" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:50 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:49 msgid "%s · check cable" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:52 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51 msgid "%s · slow link" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:48 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 msgid "%s: no carrier" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3114 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3355 msgid "(configured %d dBm, limited by regulatory rules)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1643 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2760 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1930 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3003 msgid "(hidden)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1349 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1644 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2248 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1523 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1931 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2476 msgid "1 client" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2575 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2813 msgid "1 connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1671 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1675 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2574 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1962 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2812 msgid "1 device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:250 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:258 msgid "1 older device (Wi-Fi 4 or earlier) slows airtime" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2240 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2468 msgid "1 radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:135 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:213 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:143 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:230 msgid "1 thing needs attention" msgstr "" @@ -432,20 +436,20 @@ msgstr "" msgid "60 GHz" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2438 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2676 msgid "Active" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2933 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2974 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3185 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3217 msgid "Address type" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3150 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3394 msgid "Addresses" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2287 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2516 msgid "Airtime" msgstr "" @@ -454,59 +458,37 @@ msgctxt "vantage" msgid "Alias" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2429 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2435 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2667 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2673 msgid "All" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:125 -msgid "All %d clients above %s" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:124 -msgid "All above %s" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:124 -msgid "All good" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:234 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:251 msgid "Any zone" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:235 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:252 msgid "" "Anything on the internet can reach that network. Remove the forwarding " "unless you mean it." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:231 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:248 msgid "" "Anything on the internet can reach the router itself. Set this zone's Input " "to reject." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:81 msgctxt "vantage" msgid "B" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1748 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1749 -msgid "Busiest network" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1723 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1725 -msgid "Busiest radio" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:249 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:257 msgid "Busiest radio: %s of Wi-Fi traffic" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1924 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2139 msgid "Busy share of each CPU core" msgstr "" @@ -515,13 +497,15 @@ msgid "Busy · load %s" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:74 -msgid "Busy; load %s on %d cores; see the busiest processes" -msgstr "" +msgid "Busy; load %s on %d core; see the busiest processes" +msgid_plural "Busy; load %s on %d cores; see the busiest processes" +msgstr[0] "" +msgstr[1] "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:71 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:72 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1917 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3183 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2132 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3427 msgctxt "vantage" msgid "CPU" msgstr "" @@ -530,115 +514,109 @@ msgstr "" msgid "Cache (reclaimable)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3049 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3290 msgid "Cancel" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2916 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3168 msgctxt "vantage" msgid "Capabilities" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3145 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3389 msgid "Carrier" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3113 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3354 msgid "Centre frequency" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2279 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2507 msgid "Ch %d" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1626 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2247 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1911 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2475 msgid "Ch %d · %d MHz" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3106 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3347 msgid "Channel" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1626 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1911 msgid "Channel —" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2311 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2540 msgctxt "vantage" msgid "Clear filter" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1403 -msgid "Click any node for details" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:955 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1719 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2284 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2329 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2330 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1125 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2513 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2559 msgid "Clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3118 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3361 msgid "Clients on this radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2777 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3020 msgid "Close" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2684 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2926 msgid "Connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2654 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2896 msgid "Connected after you opened this page" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1746 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2922 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3174 msgid "Connected for" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2919 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2959 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3171 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3202 msgid "Connection" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1951 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2166 msgid "Core %d: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:165 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:182 msgid "Could not read the firewall configuration" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3032 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3273 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:3156 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3400 msgid "Counters since boot" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3116 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3359 msgid "Country" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:331 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:348 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:1338 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1512 msgid "Customize" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1148 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1337 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1322 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1323 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1511 msgid "Customize the dashboard" msgstr "" @@ -646,16 +624,16 @@ msgstr "" msgid "DHCP" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2987 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3230 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:3154 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3398 msgid "DNS" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1581 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1866 msgid "DNS %s" msgstr "" @@ -664,96 +642,95 @@ msgstr "" 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:2510 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2599 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3174 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2748 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3418 msgid "Device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3016 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3257 msgid "Device name" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3045 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3286 msgid "Device type" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2588 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2826 msgid "" "Devices on the Ethernet ports appear here once they send traffic; the bridge " "forgets quiet ones after about five minutes." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1627 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2249 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2274 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3111 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1912 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2477 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2502 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352 msgid "Disabled" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3137 msgid "Disconnected %s; shown from the last sample." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1162 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1336 msgctxt "vantage" msgid "Done" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:46 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1627 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2249 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2274 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3111 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:45 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1912 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2477 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2502 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352 msgctxt "vantage" msgid "Down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2023 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2109 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2182 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2245 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2335 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2410 msgid "Download" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:331 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:368 msgid "Download (to clients)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2927 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3179 msgctxt "vantage" msgid "Downloaded" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1223 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1397 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:1224 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1398 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:1222 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1396 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:1175 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1349 msgid "Drag to move" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3159 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3403 msgctxt "vantage" msgid "Dropped" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2740 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2982 msgid "Edit" msgstr "" @@ -761,62 +738,66 @@ msgstr "" msgid "Enhanced Open (OWE)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:135 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1575 +msgid "Error" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:143 msgid "Everything looks healthy" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:171 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:179 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:117 msgctxt "vantage" msgid "Excellent" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2678 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2920 msgid "Experience" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:171 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:179 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:119 msgctxt "vantage" msgid "Fair" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:150 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:158 msgid "Fair signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:150 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:158 msgid "Fair signal %s; lower rates at range" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2308 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2500 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2537 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2738 msgid "Filter by name, address, SSID…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2500 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2738 msgid "Filter by name, address, port…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2309 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2538 msgid "Filter clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3177 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3421 msgctxt "vantage" msgid "Firmware" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:375 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:392 msgid "Forwarding %s to %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:238 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:255 msgid "Forwarding is accepted by default" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2929 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3181 msgid "Frames to device" msgstr "" @@ -825,115 +806,123 @@ msgctxt "vantage" msgid "Free" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2914 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3166 msgid "From device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2667 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2909 msgid "From device: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3140 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384 msgid "From network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:335 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:352 msgid "" "From the firewall configuration. Ports opened by UPnP or by custom rule " "files are not shown." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1579 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2619 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3153 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1864 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2861 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3397 msgid "Gateway" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:30 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:40 msgctxt "vantage" msgid "Gbit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:366 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:383 msgid "General Settings" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3167 msgctxt "vantage" msgid "Generation" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:81 msgctxt "vantage" msgid "GiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2933 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2974 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3185 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3217 msgid "Globally unique" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2933 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2974 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3185 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3217 msgid "Globally unique · %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:171 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:179 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:118 msgctxt "vantage" msgid "Good" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:151 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:159 msgid "Good signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:151 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:159 msgid "Good signal %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1121 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1293 msgid "Grid packets" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:50 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:126 +msgid "HTTP (port 80)" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:126 +msgid "HTTPS (port 443)" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:49 msgid "Half duplex" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:852 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1021 msgctxt "vantage" msgid "Health checks" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1239 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2760 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1413 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3003 msgctxt "vantage" msgid "Hidden" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1202 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1376 msgid "Hide %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2934 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2975 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3186 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3218 msgid "IP addresses" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3151 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3395 msgid "IPv4" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3152 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3396 msgid "IPv6" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2931 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2972 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3183 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3215 msgid "Identity" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:363 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:380 msgid "In no zone: the default policies apply." msgstr "" @@ -942,148 +931,152 @@ msgctxt "vantage" msgid "In use" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:353 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:370 msgctxt "vantage" msgid "Input" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1605 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1890 msgid "Interface" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3148 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3392 msgid "Interface up for" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2957 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3138 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3200 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3382 msgid "Interfaces" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1579 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1864 msgid "Internet" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:214 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:222 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:231 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:239 msgid "Internet-facing: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:312 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:329 msgid "Into your network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:255 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:272 msgid "" "It accepts every port from any address, like a zone forwarding. Limit it to " "the ports and addresses you need." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:260 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:277 msgid "" -"It forwards SSH or web ports from any address on the internet to %s. The " -"interface list could not be read, so this page cannot tell whether that is " -"the router itself." +"It forwards %s from any address on the internet to %s. The interface list " +"could not be read, so this page cannot tell whether that is the router " +"itself." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3178 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3422 msgid "Kernel" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1996 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2218 msgid "Kernel %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:81 msgctxt "vantage" msgid "KiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2323 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2552 msgid "Kind of client" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2923 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3175 msgctxt "vantage" msgid "Last activity" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2511 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2643 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2970 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2749 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3213 msgid "Last heard" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1160 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1334 msgid "Layout reset" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2653 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2895 msgid "Left %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:166 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2655 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:174 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2897 msgctxt "vantage" msgid "Legacy" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2510 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2623 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2912 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2961 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3144 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2748 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2865 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3164 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3204 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3388 msgctxt "vantage" msgid "Link" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2666 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2908 msgid "Link rate" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1357 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2510 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2634 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2671 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1543 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2748 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2876 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913 msgid "Live" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3182 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3426 msgid "Load" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:74 -msgid "Load %s on %d cores" -msgstr "" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:75 +msgid "Load %s on %d core" +msgid_plural "Load %s on %d cores" +msgstr[0] "" +msgstr[1] "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:73 -msgid "Load %s · %d cores" -msgstr "" +msgid "Load %s · %d core" +msgid_plural "Load %s · %d cores" +msgstr[0] "" +msgstr[1] "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3184 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3428 msgctxt "vantage" msgid "Load average" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1905 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2120 msgid "Load average over 1, 5 and 15 minutes" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1941 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2156 msgid "Load avg %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3180 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3424 msgid "Local time" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:156 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164 msgid "Low link rate %s despite good signal; interference or an old device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:156 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164 msgid "Low link rate for its signal" msgstr "" @@ -1091,8 +1084,8 @@ msgstr "" msgid "MAC" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2932 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2973 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3184 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3216 msgid "MAC address" msgstr "" @@ -1100,19 +1093,15 @@ msgstr "" msgid "MCS %d" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1195 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1369 msgid "Make %s narrower" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1198 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1372 msgid "Make %s wider" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2989 -msgid "Manufacturer of the network adapter" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:30 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:40 msgid "Mbit/s" msgstr "" @@ -1124,77 +1113,77 @@ msgstr "" msgid "Measuring…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:82 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1928 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:83 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2143 msgid "Memory" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3185 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3429 msgid "Memory in use" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:81 msgctxt "vantage" msgid "MiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1109 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1279 msgid "Mirrored" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1110 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1280 msgid "Mirrored, scale per direction" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3112 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3353 msgid "Mode" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3175 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3419 msgid "Model" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1192 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1366 msgid "Move %s down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1183 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1357 msgid "Move %s left" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1186 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1360 msgid "Move %s right" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1189 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1363 msgid "Move %s up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1175 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1349 msgid "Move %s: drag, or use the arrow keys" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3044 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3285 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:3084 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3325 msgid "Name contains invisible or control characters" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2935 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2976 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3187 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3219 msgid "Name from" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2604 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2845 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:3085 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3326 msgid "Name is longer than %d characters" msgstr "" @@ -1202,117 +1191,106 @@ msgstr "" msgid "Name must be text" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2876 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2954 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3197 msgid "Name this device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2510 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2633 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2663 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2920 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2969 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2748 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2875 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2905 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3172 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3212 msgid "Network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:955 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1402 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1403 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1125 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1689 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1690 msgid "Network path" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1125 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1298 msgid "Network path background" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1747 -msgid "Networks" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:360 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:377 msgid "Networks: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2440 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2654 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2678 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2896 msgctxt "vantage" msgid "New" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1528 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1813 msgid "No SSIDs" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:119 msgid "No clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2590 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2828 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3366 msgid "No clients connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2715 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2957 msgid "No clients connected." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2581 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2819 msgid "No clients in this view" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2581 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2819 msgid "No clients match “%s”" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3123 -msgid "No clients; an idle radio is fine." -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:252 -msgid "No clients; idle radios are fine" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1580 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1865 msgctxt "vantage" msgid "No default route" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:46 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:45 msgid "No interface with a route" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3130 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3374 msgid "No interface with a route is up." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:209 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:226 msgid "No internet-facing zone found" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:48 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3145 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3389 msgid "No link" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:46 msgid "No network interface with a route is up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1509 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1794 msgid "No other interfaces are up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:175 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:177 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:183 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:185 msgid "No problems detected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:104 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1532 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1817 msgid "No radios reported" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:315 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:332 msgid "" "No rule or port forward opens anything; the warnings above say what does." msgstr "" @@ -1321,98 +1299,91 @@ msgstr "" msgid "No signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:119 msgid "No stations are associated right now" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2587 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2825 msgid "No wired devices heard" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2749 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2991 msgctxt "vantage" msgid "No wireless networks configured." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2254 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2482 msgid "No wireless radios are reported by this device." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:210 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:227 msgid "" "No zone masquerades, holds the uplink or is called wan, so this page cannot " "tell which side faces the internet. On an access point that is expected; on " "a router, check the zones below." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:365 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:382 msgid "No zones are configured." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 -msgid "Nobody associated" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2715 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2957 msgid "Nobody is moving data right now." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2286 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2515 msgid "Noise" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2917 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3169 msgid "Noise / SNR" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3115 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3357 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3358 msgid "Noise floor" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:251 -msgid "Noise floor not reported by the driver" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:104 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1121 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1293 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:3083 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3324 msgid "Not a station MAC address" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2858 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3119 msgid "Not connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2635 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2966 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2877 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3209 msgid "Not counted per device on a shared port" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:383 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:400 msgid "Not in effect" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1976 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2193 msgid "Not reported" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2992 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:129 +msgid "Not reported by the driver" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3233 msgid "Nothing better known" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2990 -msgid "Nothing better known; the address is randomised" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:221 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:238 msgid "Nothing is open in your firewall rules" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:316 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:333 msgid "Nothing is open in your firewall rules." msgstr "" @@ -1421,24 +1392,24 @@ msgctxt "vantage" msgid "OWE" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:167 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:175 msgid "Older %s device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2655 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2897 msgid "Older Wi-Fi generation than the radio; uses more airtime" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:311 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:328 msgid "On this router" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 msgctxt "vantage" msgid "Online" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:222 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:239 msgid "Only standard housekeeping (ping, DHCP renewals and the like): %d rule" msgid_plural "" "Only standard housekeeping (ping, DHCP renewals and the like): %d rules" @@ -1450,15 +1421,15 @@ msgctxt "vantage" msgid "Open" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2556 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2794 msgid "Open details of %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:336 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:353 msgid "Open from the internet" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:217 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:234 msgid "Open from the internet: %d" msgstr "" @@ -1466,21 +1437,21 @@ msgstr "" msgid "Open network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:656 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:658 msgid "OpenWrt device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:251 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:268 msgid "" "Option %s in General Settings has a value firewall4 refuses, so it loads no " "new rules: what is open is unknown." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1107 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1277 msgid "Overlaid" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1108 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1278 msgid "Overlaid, log scale" msgstr "" @@ -1488,35 +1459,35 @@ msgstr "" msgid "Overview" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2916 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3168 msgid "PMF" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1355 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1541 msgid "Paused while hidden" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:81 msgid "PiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:320 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:337 msgid "" "Ping and other control messages, multicast, DHCP renewals and IPsec passed " "on to your network: what every router lets in." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3176 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3420 msgctxt "vantage" msgid "Platform" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:171 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:179 msgctxt "vantage" msgid "Poor" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2960 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3203 msgid "Port" msgstr "" @@ -1524,11 +1495,11 @@ msgstr "" msgid "Port %d" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2628 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2870 msgid "Port %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1668 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1955 msgid "Port total: %s" msgstr "" @@ -1536,326 +1507,341 @@ msgstr "" msgid "Private" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2933 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3185 msgid "Private Wi-Fi address (randomised by the device)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2974 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3217 msgid "Private address (randomised by the device)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:266 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:270 msgid "Private device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3173 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3417 msgid "Processes" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3147 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3391 msgid "Protocol" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2320 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2547 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2549 msgid "Quick filters" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2921 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3110 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3173 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3351 msgctxt "vantage" msgid "Radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2275 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2503 msgid "Radio details" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:247 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:255 msgid "Radio is disabled" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:248 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:256 msgid "Radio is enabled but not up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2298 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3104 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2527 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3345 msgid "Radio settings" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:955 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2227 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2229 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1125 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2455 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2457 msgid "Radios" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1581 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1866 msgid "Reachability not probed" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2620 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2862 msgid "Reached through the uplink port %s, not connected to this device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3138 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3382 msgid "Realtime graphs" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3157 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3401 msgctxt "vantage" msgid "Received" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1356 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1542 msgctxt "vantage" msgid "Reconnecting…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2456 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2694 msgid "Remove filter: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3050 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3291 msgid "Remove name" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2876 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2954 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3197 msgctxt "vantage" msgid "Rename" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1161 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1335 msgid "Reset" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2985 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3228 msgid "Reverse DNS of its address" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:668 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:670 msgid "Root (overlay)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:264 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:281 msgid "Router admin open: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:265 -msgid "" -"SSH or the web interface answers any address on the internet. Limit the rule " -"to the addresses you use." +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:126 +msgid "SSH (port 22)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3042 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3283 msgid "Save" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2924 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3176 msgid "Seen since" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3158 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3402 msgctxt "vantage" msgid "Sent" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1111 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1281 msgid "Separate lanes" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:174 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:191 msgid "Settings to check" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2961 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3204 msgid "Shared by %d devices" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2624 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2866 msgid "Shared port" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1241 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1415 msgid "Show %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2582 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2820 msgid "Show all clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1914 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2129 msgid "Show or hide system details" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1403 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1690 msgid "Show or hide the network path" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2230 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2458 msgid "Show or hide the radio details" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2026 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2248 msgid "Show or hide the throughput chart" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2740 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2982 msgid "Show or hide the wireless networks" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1642 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2756 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1929 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3000 msgid "Show the clients of %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1668 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1955 msgid "Show the devices on %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:118 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:124 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2660 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2900 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:119 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:120 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2902 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3152 msgid "Signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:147 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:155 msgid "Signal not reported" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3146 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3390 msgctxt "vantage" msgid "Speed" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:319 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:336 msgid "Standard housekeeping: %d rule" msgid_plural "Standard housekeeping: %d rules" msgstr[0] "" msgstr[1] "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1121 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1293 msgid "Starfield" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2591 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2829 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:3111 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352 msgid "Status" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:92 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1931 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2146 msgid "Storage" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3051 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3292 msgid "Stored on this device in /etc/config/vantage" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:177 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:185 msgid "Strong signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:175 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:183 msgid "Strong signal %s, %s link" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:177 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:185 msgid "Strong signal, %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1981 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2203 msgctxt "vantage" msgid "Swap" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2964 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3207 msgid "Switch ports" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:344 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:381 msgid "Switch ports of VLAN %d on %s: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:383 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:400 msgid "Switched off" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:956 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1913 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1914 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1126 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2129 msgid "System" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3173 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3417 msgid "System settings" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:30 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:40 msgid "Tbit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:75 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1945 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:126 +msgid "Telnet (port 23)" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:76 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2160 msgid "Temperature %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:668 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:670 msgid "Temporary (RAM)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2511 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2749 msgid "The bridge forgets a device after about five minutes without traffic" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2585 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2823 msgid "" "The bridges have learned so many addresses that listing them here would " "strain this device." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:243 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:260 msgid "" "The default Input policy applies there and accepts, so anything on the " "internet can reach the router itself. Add it to the wan zone or set Input to " "reject in General Settings." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3329 msgid "The device could not write /etc/config/vantage." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2286 -msgid "" -"The driver reports a placeholder value, so no noise floor or SNR is shown" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:131 +msgid "The driver reports no signal levels" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:250 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:267 msgid "The firewall cannot load these settings" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:247 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:282 +msgid "" +"The firewall lets any address on the internet reach %s. Limit the rule to " +"the addresses you use." +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:264 msgid "" "The interface list could not be read, and the default Input policy accepts: " "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:2988 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3231 msgid "The name the device announces (WPS)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2619 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:132 +msgid "The one measured client is above %s" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:129 +msgid "The only measured client" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2861 msgid "The router this device sends its traffic to" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:206 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:223 msgid "The settings below apply if traffic reaches them as configured." msgstr "" @@ -1863,211 +1849,207 @@ msgstr "" msgid "The stored name has an invalid section id" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:246 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:263 msgid "The uplinks could not be checked" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1589 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1874 msgid "This access point" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:363 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:380 msgid "This address family is in no zone: the default policies apply." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1589 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1874 msgid "This device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3087 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3328 msgid "This device already stores %d names; remove some first." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:104 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 msgid "This device reports no radios" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:166 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:183 msgid "" "This page cannot tell what is open. Reload it; if that does not help, check " "the firewall pages." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3095 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3336 msgid "This radio is not reported any more." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:203 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:220 msgid "This setup is beyond what this overview checks" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2858 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3119 msgid "This station is not associated right now." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:955 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2018 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2020 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2906 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1125 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2240 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2242 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3158 msgctxt "vantage" msgid "Throughput" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1116 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1286 msgid "Throughput chart" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2011 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2233 msgid "Throughput per link; arrow keys read the values over time" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:81 msgctxt "vantage" msgid "TiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3165 msgid "To device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2640 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2675 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2728 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2882 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2917 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2970 msgid "To device %s, from device %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2667 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2909 msgid "To device: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3141 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3385 msgid "To network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2584 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2822 msgid "Too many devices to list" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:956 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2692 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2693 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1126 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2934 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2935 msgctxt "vantage" msgid "Top talkers" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2926 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2965 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3107 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3178 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3208 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3348 msgid "Traffic" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:336 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:383 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:353 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:400 msgctxt "vantage" msgid "Traffic Rules" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:239 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:256 msgid "" "Traffic from the internet that no forwarding covers still reaches your other " "networks. Set Forward to reject in General Settings." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1721 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1745 -msgid "Traffic now" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2285 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3114 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2514 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3355 msgid "Tx power" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:328 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:345 msgid "" "UPnP is installed: devices on your network can open ports on their own while " "it runs, and those are not listed here." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2857 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:272 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3118 msgctxt "vantage" msgid "Unknown device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3086 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3327 msgid "Unknown device type" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3095 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3336 msgid "Unknown radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:116 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:115 msgid "Unnamed port forward" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:116 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:254 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:115 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:271 msgctxt "vantage" msgid "Unnamed rule" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:58 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2274 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3111 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3145 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2502 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3389 msgctxt "vantage" msgid "Up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1938 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2153 msgid "Up %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:46 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:48 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:50 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:52 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:58 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2043 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3130 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:45 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 +#: 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:2265 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3374 msgctxt "vantage" msgid "Uplink" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2043 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2265 msgid "Uplink %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3134 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3378 msgid "Uplink · %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2024 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2111 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2183 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2246 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2337 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2411 msgid "Upload" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:332 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:369 msgid "Upload (from clients)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2928 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3180 msgctxt "vantage" msgid "Uploaded" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2620 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2862 msgid "Upstream" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3179 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3423 msgid "Uptime" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2621 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2969 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2863 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3212 msgid "VLAN %d" msgstr "" @@ -2097,11 +2079,11 @@ msgstr "" msgid "Vendor" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:148 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:156 msgid "Very weak signal %s; expect drops" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:148 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:156 msgid "Very weak signal; expect drops" msgstr "" @@ -2201,11 +2183,15 @@ msgstr "" msgid "WPS" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2936 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3188 msgid "WPS device name" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:171 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1575 +msgid "Warning" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:188 msgctxt "vantage" msgid "Warnings" msgstr "" @@ -2214,59 +2200,60 @@ msgstr "" msgid "Weak" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:149 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2439 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2677 msgid "Weak signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:149 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157 msgid "Weak signal %s; may roam poorly" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1726 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1728 -msgid "Weakest signal" -msgstr "" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:130 +msgid "Weakest of %d client" +msgid_plural "Weakest of %d clients" +msgstr[0] "" +msgstr[1] "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:204 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:221 msgid "" "What is open depends on how firewall4 handles %s, which this page does not " "follow. Check the firewall pages." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:104 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:107 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:109 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2493 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:110 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2731 msgid "Wi-Fi" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1539 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2493 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1824 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2731 msgid "Wired" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:956 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2739 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2740 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1126 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2981 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2982 msgctxt "vantage" msgid "Wireless networks" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2886 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3138 msgid "Wireless settings" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2984 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3227 msgid "Your name for this device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:377 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:394 msgid "Zone %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:366 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:383 msgid "Zones" msgstr "" @@ -2275,72 +2262,68 @@ msgctxt "vantage" msgid "accept" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:88 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:87 msgid "all ports except %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:83 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:82 msgid "all protocols" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1747 -msgid "all up" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:134 msgid "an unnamed rule" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:112 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:111 msgctxt "vantage" msgid "any zone" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:345 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:362 msgid "any zone (default policy)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2280 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2508 msgid "auto" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2924 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3176 msgid "before this page opened" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2962 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3205 msgid "behind %s, VLAN %d" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:30 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:40 msgctxt "vantage" msgid "bit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2140 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2369 msgid "collecting · %s of data" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2140 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2369 msgid "collecting · first samples" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:228 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2120 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:248 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2349 msgid "collecting…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:379 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:396 msgid "custom rule file" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:97 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:125 msgid "dBm" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:339 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2624 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2961 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:376 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2866 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3204 msgid "down" msgstr "" @@ -2349,29 +2332,29 @@ msgctxt "vantage" msgid "drop" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3016 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3257 msgctxt "vantage" msgid "e.g. Living room TV" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:88 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:87 msgid "except %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:346 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:363 msgid "forwards nowhere" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:100 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:99 msgctxt "vantage" msgid "from %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:101 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:100 msgid "from anywhere" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:101 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:100 msgid "from anywhere except %s" msgstr "" @@ -2387,60 +2370,61 @@ msgstr "" msgid "half duplex" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2765 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:62 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3008 msgid "idle" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:134 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:140 msgid "ignored: a port forward needs one source zone, not any zone" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:135 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:141 msgid "ignored: its address families conflict" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:136 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:142 msgid "ignored: no source zone" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:133 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:139 msgid "ignored: not marked as compatible with firewall4" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:139 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:145 msgid "ignored: option %s has a value firewall4 refuses" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:138 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:144 msgid "ignored: zone %s does not exist or is switched off" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:352 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:369 msgid "internet" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:88 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:116 msgctxt "vantage" msgid "just now" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:30 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:40 msgctxt "vantage" msgid "kbit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1923 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2139 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2138 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2368 msgid "last 5 min" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:167 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:175 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:104 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2669 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2911 msgid "legacy" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:339 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:376 msgid "link up" msgstr "" @@ -2448,71 +2432,45 @@ msgstr "" msgid "mDNS" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2986 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3229 msgid "mDNS announcement" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1721 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1745 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2908 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2968 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3160 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3211 msgid "measuring" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2115 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2344 msgid "measuring…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1725 -msgid "no Wi-Fi traffic yet" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1728 -msgid "no clients" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2099 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2325 msgctxt "vantage" msgid "no data" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1749 -msgid "no traffic yet" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1587 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1746 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1872 msgid "no uplink" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1719 -msgid "none connected" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2934 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3186 msgid "not known to this AP" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2975 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3218 msgid "not known to this 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 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3115 -msgid "not reported" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3115 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3358 msgid "not reported (driver placeholder %s)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2917 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3169 msgid "not reported by the driver" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2136 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2923 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2365 msgctxt "vantage" msgid "now" msgstr "" @@ -2521,29 +2479,29 @@ msgstr "" msgid "now %s down, %s up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3167 msgid "older than the radio (%s)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2114 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2342 msgctxt "vantage" msgid "peak" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1924 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2139 msgid "per core" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:381 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:398 msgctxt "vantage" msgid "port forward" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2902 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3154 msgid "range %s … %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3140 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384 msgid "received on %s" msgstr "" @@ -2552,11 +2510,11 @@ msgctxt "vantage" msgid "reject" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:107 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:106 msgid "router port %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3141 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3385 msgid "sent on %s" msgstr "" @@ -2564,69 +2522,60 @@ msgstr "" msgid "short GI" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2643 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2970 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3213 msgid "static entry" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2963 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3206 msgid "switch port %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:373 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:390 msgid "switched off" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:126 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:132 msgid "the covered subnets of zone %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2967 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3210 msgid "the port in total: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2962 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3205 msgid "the port: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:134 msgid "the set in %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:107 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:106 msgid "this router" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:381 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:398 msgid "traffic rule" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1592 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1877 msgid "up %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2693 -msgid "who uses the bandwidth" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:377 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:394 msgctxt "vantage" msgid "zone" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:375 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:392 msgid "zone forwarding" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:127 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:133 msgid "zones %s and %s if they share a device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1721 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1745 -msgid "↑ %s · via %s" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2133 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2362 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 32e088dee..bd907e175 100644 --- a/luci-app-vantage/po/zh_Hans/vantage.po +++ b/luci-app-vantage/po/zh_Hans/vantage.po @@ -12,338 +12,333 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3113 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3354 msgid "%d MHz (%d–%d MHz)" msgstr "%d MHz(%d–%d MHz)" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:111 -msgid "%d SSIDs broadcasting" -msgstr "正在广播 %d 个 SSID" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:112 +msgid "%d SSID broadcasting" +msgid_plural "%d SSIDs broadcasting" +msgstr[0] "正在广播 %d 个 SSID" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:112 +msgid "%d SSID broadcasting, %d idle" +msgid_plural "%d SSIDs broadcasting, %d idle" +msgstr[0] "正在广播 %d 个 SSID,%d 个空闲" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:111 -msgid "%d SSIDs broadcasting; %d without clients, which is fine" -msgstr "正在广播 %d 个 SSID,%d 个无客户端(正常)" +msgid "%d SSID on air" +msgid_plural "%d SSIDs on air" +msgstr[0] "%d 个 SSID 正在广播" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:110 -msgid "%d SSIDs on air" -msgstr "%d 个 SSID 正在广播" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:111 +msgid "%d SSID · %d idle" +msgid_plural "%d SSIDs · %d idle" +msgstr[0] "%d 个 SSID · %d 个空闲" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:110 -msgid "%d SSIDs · %d idle" -msgstr "%d 个 SSID · %d 个空闲" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1349 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1644 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2248 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1523 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1931 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2476 msgid "%d clients" msgstr "%d 个客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2575 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2813 msgid "%d connected" msgstr "已连接 %d 个" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1671 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1675 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2574 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1958 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1962 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2812 msgid "%d devices" msgstr "%d 台设备" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1747 -msgid "%d down" -msgstr "%d 个已关闭" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3157 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3158 -msgid "%d errors" -msgstr "%d 个错误" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:91 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:119 msgctxt "vantage" msgid "%d h ago" msgstr "%d 小时前" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3159 -msgid "%d in · %d out" -msgstr "%d 入 · %d 出" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:133 +msgid "%d measured client is above %s" +msgid_plural "%d measured clients are above %s" +msgstr[0] "%d 个已测客户端高于 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:396 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:449 msgctxt "vantage" 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:390 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:118 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:443 msgctxt "vantage" msgid "%d min ago" msgstr "%d 分钟前" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2573 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2811 msgid "%d of %d" msgstr "%d/%d" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1236 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1410 msgid "%d of %d columns" msgstr "%d/%d 列" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:107 -msgid "%d off" -msgstr "%d 个关闭" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:250 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:258 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:1711 -msgid "%d on %s" -msgstr "%d 个在 %s" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:218 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:235 msgid "%d on this router, %d into your network" msgstr "路由器上 %d 项,进入你的网络 %d 项" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2240 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106 +msgid "%d radio down" +msgid_plural "%d radios down" +msgstr[0] "%d 个射频未上线" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108 +msgid "%d radio off" +msgid_plural "%d radios off" +msgstr[0] "%d 个射频已禁用" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:110 +msgid "%d radio up" +msgid_plural "%d radios up" +msgstr[0] "%d 个射频已上线" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2468 msgid "%d radios" msgstr "%d 个射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:396 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:449 msgctxt "vantage" 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:390 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:117 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:443 msgctxt "vantage" msgid "%d s ago" msgstr "%d 秒前" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2929 -msgid "%d sent · %s retried · %s failed" -msgstr "发送 %d · 重传 %s · 失败 %s" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:135 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:213 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:143 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:230 msgid "%d things need attention" msgstr "%d 项需要关注" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:109 -msgid "%d up" -msgstr "%d 个已启用" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:118 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:120 msgid "%d weak" msgstr "%d 个信号弱" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1714 -msgid "%d wired" -msgstr "%d 个有线" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2259 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2487 msgid "%d–%d MHz of the %d–%d MHz band" msgstr "%d–%d MHz 属于 %d–%d MHz 频段" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:109 msgid "%s (%s) is disabled" msgstr "%s(%s)已禁用" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:107 msgid "%s (%s) is enabled but not up" msgstr "%s(%s)已启用但未上线" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:201 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:242 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:362 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:218 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:259 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:379 msgid "%s (IPv%d)" msgstr "%s(IPv%d)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2924 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3176 msgid "%s (new this session)" msgstr "%s(本次新增)" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:25 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:24 #: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:212 msgid "%s Gbit/s" msgstr "%s Gbit/s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:137 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:166 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:103 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2266 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2280 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2669 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3106 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2494 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2508 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2911 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3347 msgid "%s MHz" msgstr "%s MHz" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:25 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:52 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:24 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51 #: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:212 msgid "%s Mbit/s" msgstr "%s Mbit/s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:230 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:247 msgid "%s accepts every connection" msgstr "%s 接受所有连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2923 -msgctxt "vantage" -msgid "%s ago" -msgstr "%s 前" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:120 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:123 msgid "%s at %s; below %s roaming and throughput suffer" msgstr "%s(%s);低于 %s 时漫游和吞吐量会受影响" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:82 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1958 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:83 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2174 msgctxt "vantage" msgid "%s available" msgstr "可用 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2285 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3114 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2514 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3355 msgid "%s dBm" msgstr "%s dBm" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:267 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:271 msgid "%s device" msgstr "%s 设备" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:166 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:174 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:2891 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3373 +msgid "%s error" +msgid_plural "%s errors" +msgstr[0] "%s 个错误" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3143 msgid "%s experience" msgstr "%s 体验" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:94 msgid "%s free" msgstr "空闲 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:94 msgid "%s free on the overlay (%s used)" msgstr "overlay 空闲 %s(已用 %s)" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:49 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:48 msgid "%s has no carrier: cable unplugged or switch port down" msgstr "%s 无载波:网线未插或交换机端口关闭" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1203 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1377 msgid "%s hidden" msgstr "%s 已隐藏" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:107 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3403 +msgid "%s in · %s out" +msgstr "%s 入 · %s 出" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108 msgid "%s is disabled" msgstr "%s 已禁用" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:234 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:251 msgid "%s is forwarded into %s" msgstr "%s 被转发到 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:242 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:259 msgid "%s is in no zone and accepts every connection" msgstr "%s 不属于任何区域,接受所有连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1196 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1370 msgid "%s is narrower" msgstr "%s 已变窄" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106 msgid "%s is not up" msgstr "%s 未上线" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2628 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2870 msgid "" "%s is shared by %d devices (a switch or another access point behind it); its " "%s link is not theirs" msgstr "" "%s 由 %d 台设备共用(其后接有交换机或另一个接入点);%s 的链路不属于这些设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2627 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2869 msgid "%s is shared by %d devices behind the switch" msgstr "%s 由交换机后的 %d 台设备共用" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1199 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1373 msgid "%s is wider" msgstr "%s 已加宽" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:254 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:271 msgid "%s lets the internet into %s" msgstr "%s 允许互联网访问 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:56 msgid "%s link" msgstr "%s 链路" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:259 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:276 msgid "%s may open the router's admin" msgstr "%s 可能暴露了路由器管理界面" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1491 msgid "%s moved" msgstr "%s 已移动" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1193 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1367 msgid "%s moved down" msgstr "%s 已下移" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1184 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1358 msgid "%s moved left" msgstr "%s 已左移" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1187 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1361 msgid "%s moved right" msgstr "%s 已右移" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1190 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1364 msgid "%s moved up" msgstr "%s 已上移" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:50 msgid "%s negotiated half duplex; check the cable and switch port" msgstr "%s 协商为半双工;请检查网线和交换机端口" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:52 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:83 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1959 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1982 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3185 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:84 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2175 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2204 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3429 msgid "%s of %s" msgstr "%s / %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:84 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:85 msgid "%s of %s available (%s in use)" msgstr "可用 %s / 共 %s(已用 %s)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1723 -msgid "%s of Wi-Fi traffic" -msgstr "占 Wi-Fi 流量的 %s" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:161 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:162 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:169 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:170 msgid "%s of frames fail" msgstr "帧失败率:%s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:162 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:170 msgid "%s of frames to the device fail" msgstr "发往设备的帧失败率:%s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:161 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:169 msgid "%s of frames to the device fail; interference likely" msgstr "发往设备的帧失败率:%s,可能存在干扰" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3183 -msgid "%s over %d cores" -msgstr "%s / %d 核" +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3427 +msgid "%s over %d core" +msgid_plural "%s over %d cores" +msgstr[0] "%s / %d 核" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2044 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2266 msgid "%s radio" msgstr "%s 射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1242 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3181 +msgid "%s sent · %s retried · %s failed" +msgstr "发送 %s · 重传 %s · 失败 %s" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1416 msgid "%s shown" msgstr "%s 已显示" @@ -355,73 +350,72 @@ msgstr "%s 已连接" msgid "%s up at %s" msgstr "%s 已连接,速率 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:92 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93 msgid "%s used" msgstr "已用 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1990 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2212 msgid "%s used of %s" msgstr "已用 %s / 共 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2625 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2867 msgid "%s · %d devices" msgstr "%s · %d 台设备" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:119 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:122 msgid "%s · %s" msgstr "%s · %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2921 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3173 msgid "%s · channel %d · %d MHz" msgstr "%s · 信道 %d · %d MHz" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:50 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:49 msgid "%s · check cable" msgstr "%s · 检查网线" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:52 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51 msgid "%s · slow link" msgstr "%s · 链路较慢" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:48 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 msgid "%s: no carrier" msgstr "%s:无载波" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3114 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3355 msgid "(configured %d dBm, limited by regulatory rules)" msgstr "(配置 %d dBm,受管制规则限制)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1643 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2760 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1930 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3003 msgid "(hidden)" msgstr "(隐藏)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1349 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1644 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2248 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1523 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1931 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2476 msgid "1 client" msgstr "1 个客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2575 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2813 msgid "1 connected" msgstr "已连接 1 个" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1671 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1675 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2574 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1962 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2812 msgid "1 device" msgstr "1 台设备" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:250 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:258 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:2240 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2468 msgid "1 radio" msgstr "1 个射频" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:135 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:213 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:143 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:230 msgid "1 thing needs attention" msgstr "1 项需要关注" @@ -444,20 +438,20 @@ msgstr "6 GHz" msgid "60 GHz" msgstr "60 GHz" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2438 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2676 msgid "Active" msgstr "活跃" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2933 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2974 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3185 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3217 msgid "Address type" msgstr "地址类型" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3150 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3394 msgid "Addresses" msgstr "地址" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2287 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2516 msgid "Airtime" msgstr "空口时间" @@ -466,59 +460,37 @@ msgctxt "vantage" msgid "Alias" msgstr "别名" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2429 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2435 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2667 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2673 msgid "All" msgstr "全部" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:125 -msgid "All %d clients above %s" -msgstr "全部 %d 个客户端高于 %s" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:124 -msgid "All above %s" -msgstr "全部高于 %s" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:124 -msgid "All good" -msgstr "全部正常" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:234 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:251 msgid "Any zone" msgstr "任意区域" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:235 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:252 msgid "" "Anything on the internet can reach that network. Remove the forwarding " "unless you mean it." msgstr "互联网上的任何主机都能访问该网络。除非有意如此,请删除此转发。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:231 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:248 msgid "" "Anything on the internet can reach the router itself. Set this zone's Input " "to reject." msgstr "互联网上的任何主机都能访问路由器本身。请将此区域的入站数据设为拒绝。" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:81 msgctxt "vantage" msgid "B" msgstr "B" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1748 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1749 -msgid "Busiest network" -msgstr "最繁忙网络" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1723 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1725 -msgid "Busiest radio" -msgstr "最繁忙射频" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:249 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:257 msgid "Busiest radio: %s of Wi-Fi traffic" msgstr "最繁忙射频:占 Wi-Fi 流量的 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1924 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2139 msgid "Busy share of each CPU core" msgstr "每个 CPU 核心的繁忙占比" @@ -527,13 +499,14 @@ msgid "Busy · load %s" msgstr "繁忙 · 负载 %s" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:74 -msgid "Busy; load %s on %d cores; see the busiest processes" -msgstr "繁忙;负载 %s(%d 核);查看最繁忙进程" +msgid "Busy; load %s on %d core; see the busiest processes" +msgid_plural "Busy; load %s on %d cores; see the busiest processes" +msgstr[0] "繁忙;负载 %s(%d 核);查看最繁忙进程" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:71 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:72 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1917 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3183 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2132 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3427 msgctxt "vantage" msgid "CPU" msgstr "CPU" @@ -542,115 +515,109 @@ msgstr "CPU" msgid "Cache (reclaimable)" msgstr "缓存(可回收)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3049 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3290 msgid "Cancel" msgstr "取消" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2916 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3168 msgctxt "vantage" msgid "Capabilities" msgstr "能力" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3145 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3389 msgid "Carrier" msgstr "链路状态" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3113 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3354 msgid "Centre frequency" msgstr "中心频率" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2279 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2507 msgid "Ch %d" msgstr "信道 %d" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1626 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2247 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1911 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2475 msgid "Ch %d · %d MHz" msgstr "信道 %d · %d MHz" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3106 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3347 msgid "Channel" msgstr "信道" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1626 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1911 msgid "Channel —" msgstr "信道 —" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2311 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2540 msgctxt "vantage" msgid "Clear filter" msgstr "清除筛选" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1403 -msgid "Click any node for details" -msgstr "点击任意节点查看详情" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:955 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1719 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2284 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2329 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2330 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1125 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2513 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2559 msgid "Clients" msgstr "客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3118 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3361 msgid "Clients on this radio" msgstr "此射频上的客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2777 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3020 msgid "Close" msgstr "关闭" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2684 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2926 msgid "Connected" msgstr "已连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2654 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2896 msgid "Connected after you opened this page" msgstr "打开本页面后连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1746 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2922 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3174 msgid "Connected for" msgstr "已连接时长" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2919 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2959 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3171 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3202 msgid "Connection" msgstr "连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1951 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2166 msgid "Core %d: %s" msgstr "核心 %d:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:165 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:182 msgid "Could not read the firewall configuration" msgstr "无法读取防火墙配置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3032 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3273 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:3156 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3400 msgid "Counters since boot" msgstr "自启动以来的计数器" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3116 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3359 msgid "Country" msgstr "国家" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:331 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:348 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:1338 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1512 msgid "Customize" msgstr "自定义" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1148 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1337 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1322 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1323 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1511 msgid "Customize the dashboard" msgstr "自定义仪表盘" @@ -658,16 +625,16 @@ msgstr "自定义仪表盘" msgid "DHCP" msgstr "DHCP" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2987 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3230 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:3154 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3398 msgid "DNS" msgstr "DNS" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1581 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1866 msgid "DNS %s" msgstr "DNS %s" @@ -676,97 +643,96 @@ msgstr "DNS %s" 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:2510 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2599 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3174 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2748 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3418 msgid "Device" msgstr "设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3016 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3257 msgid "Device name" msgstr "设备名" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3045 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3286 msgid "Device type" msgstr "设备类型" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2588 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2826 msgid "" "Devices on the Ethernet ports appear here once they send traffic; the bridge " "forgets quiet ones after about five minutes." msgstr "" "以太网端口上的设备发送流量后会显示在这里;网桥会在约五分钟无流量后忘记它们。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1627 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2249 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2274 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3111 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1912 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2477 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2502 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352 msgid "Disabled" msgstr "已禁用" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3137 msgid "Disconnected %s; shown from the last sample." msgstr "断开于 %s;显示最后一次采样的数据。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1162 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1336 msgctxt "vantage" msgid "Done" msgstr "完成" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:46 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1627 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2249 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2274 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3111 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:45 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1912 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2477 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2502 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352 msgctxt "vantage" msgid "Down" msgstr "已下线" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2023 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2109 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2182 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2245 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2335 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2410 msgid "Download" msgstr "下载" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:331 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:368 msgid "Download (to clients)" msgstr "下载(到客户端)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2927 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3179 msgctxt "vantage" msgid "Downloaded" msgstr "已下载" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1223 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1397 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:1224 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1398 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:1222 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1396 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:1175 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1349 msgid "Drag to move" msgstr "拖动以移动" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3159 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3403 msgctxt "vantage" msgid "Dropped" msgstr "已丢弃" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2740 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2982 msgid "Edit" msgstr "编辑" @@ -774,62 +740,66 @@ msgstr "编辑" msgid "Enhanced Open (OWE)" msgstr "增强开放 (OWE)" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:135 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1575 +msgid "Error" +msgstr "错误" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:143 msgid "Everything looks healthy" msgstr "一切正常" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:171 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:179 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:117 msgctxt "vantage" msgid "Excellent" msgstr "极好" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2678 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2920 msgid "Experience" msgstr "体验" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:171 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:179 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:119 msgctxt "vantage" msgid "Fair" msgstr "一般" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:150 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:158 msgid "Fair signal" msgstr "信号一般" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:150 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:158 msgid "Fair signal %s; lower rates at range" msgstr "信号一般 %s;远距离速率较低" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2308 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2500 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2537 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2738 msgid "Filter by name, address, SSID…" msgstr "按名称、地址、SSID…筛选" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2500 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2738 msgid "Filter by name, address, port…" msgstr "按名称、地址、端口…筛选" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2309 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2538 msgid "Filter clients" msgstr "筛选客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3177 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3421 msgctxt "vantage" msgid "Firmware" msgstr "固件" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:375 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:392 msgid "Forwarding %s to %s" msgstr "从 %s 转发到 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:238 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:255 msgid "Forwarding is accepted by default" msgstr "默认接受转发" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2929 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3181 msgid "Frames to device" msgstr "发往设备的帧" @@ -838,115 +808,123 @@ msgctxt "vantage" msgid "Free" msgstr "空闲" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2914 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3166 msgid "From device" msgstr "来自设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2667 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2909 msgid "From device: %s" msgstr "来自设备:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3140 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384 msgid "From network" msgstr "来自网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:335 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:352 msgid "" "From the firewall configuration. Ports opened by UPnP or by custom rule " "files are not shown." msgstr "内容来自防火墙配置。由 UPnP 或自定义规则文件开放的端口不会显示。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1579 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2619 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3153 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1864 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2861 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3397 msgid "Gateway" msgstr "网关" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:30 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:40 msgctxt "vantage" msgid "Gbit/s" msgstr "Gbit/s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:366 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:383 msgid "General Settings" msgstr "基本设置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3167 msgctxt "vantage" msgid "Generation" msgstr "代际" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:81 msgctxt "vantage" msgid "GiB" msgstr "GiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2933 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2974 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3185 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3217 msgid "Globally unique" msgstr "全局唯一" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2933 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2974 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3185 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3217 msgid "Globally unique · %s" msgstr "全局唯一 · %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:171 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:179 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:118 msgctxt "vantage" msgid "Good" msgstr "良好" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:151 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:159 msgid "Good signal" msgstr "信号良好" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:151 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:159 msgid "Good signal %s" msgstr "信号良好 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1121 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1293 msgid "Grid packets" msgstr "网格数据包" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:50 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:126 +msgid "HTTP (port 80)" +msgstr "HTTP(端口 80)" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:126 +msgid "HTTPS (port 443)" +msgstr "HTTPS(端口 443)" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:49 msgid "Half duplex" msgstr "半双工" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:852 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1021 msgctxt "vantage" msgid "Health checks" msgstr "健康检查" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1239 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2760 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1413 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3003 msgctxt "vantage" msgid "Hidden" msgstr "隐藏" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1202 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1376 msgid "Hide %s" msgstr "隐藏 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2934 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2975 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3186 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3218 msgid "IP addresses" msgstr "IP 地址" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3151 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3395 msgid "IPv4" msgstr "IPv4" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3152 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3396 msgid "IPv6" msgstr "IPv6" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2931 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2972 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3183 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3215 msgid "Identity" msgstr "身份" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:363 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:380 msgid "In no zone: the default policies apply." msgstr "不属于任何区域:适用默认策略。" @@ -955,38 +933,38 @@ msgctxt "vantage" msgid "In use" msgstr "已用" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:353 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:370 msgctxt "vantage" msgid "Input" msgstr "入站数据" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1605 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1890 msgid "Interface" msgstr "接口" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3148 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3392 msgid "Interface up for" msgstr "接口已启用时长" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2957 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3138 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3200 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3382 msgid "Interfaces" msgstr "接口" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1579 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1864 msgid "Internet" msgstr "互联网" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:214 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:222 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:231 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:239 msgid "Internet-facing: %s" msgstr "面向互联网:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:312 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:329 msgid "Into your network" msgstr "进入你的网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:255 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:272 msgid "" "It accepts every port from any address, like a zone forwarding. Limit it to " "the ports and addresses you need." @@ -994,113 +972,115 @@ msgstr "" "它接受来自任意地址的所有端口,相当于区域转发。请将其限制为你需要的端口和地" "址。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:260 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:277 msgid "" -"It forwards SSH or web ports from any address on the internet to %s. The " -"interface list could not be read, so this page cannot tell whether that is " -"the router itself." +"It forwards %s from any address on the internet to %s. The interface list " +"could not be read, so this page cannot tell whether that is the router " +"itself." msgstr "" -"它将来自互联网上任何地址的 SSH 或网页端口转发到 %s。无法读取接口列表,因此本" -"页无法判断该地址是否为路由器本身。" +"它将来自互联网上任何地址的 %s 转发到 %s。无法读取接口列表,因此本页无法判断该" +"地址是否为路由器本身。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3178 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3422 msgid "Kernel" msgstr "内核" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1996 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2218 msgid "Kernel %s" msgstr "内核 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:81 msgctxt "vantage" msgid "KiB" msgstr "KiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2323 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2552 msgid "Kind of client" msgstr "客户端类型" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2923 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3175 msgctxt "vantage" msgid "Last activity" msgstr "最后活动" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2511 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2643 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2970 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2749 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3213 msgid "Last heard" msgstr "最后活动" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1160 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1334 msgid "Layout reset" msgstr "布局已重置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2653 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2895 msgid "Left %s" msgstr "离开于 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:166 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2655 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:174 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2897 msgctxt "vantage" msgid "Legacy" msgstr "旧版" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2510 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2623 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2912 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2961 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3144 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2748 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2865 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3164 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3204 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3388 msgctxt "vantage" msgid "Link" msgstr "链路" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2666 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2908 msgid "Link rate" msgstr "链路速率" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1357 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2510 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2634 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2671 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1543 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2748 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2876 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913 msgid "Live" msgstr "实时" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3182 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3426 msgid "Load" msgstr "负载" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:74 -msgid "Load %s on %d cores" -msgstr "负载 %s(%d 核)" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:75 +msgid "Load %s on %d core" +msgid_plural "Load %s on %d cores" +msgstr[0] "负载 %s(%d 核)" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:73 -msgid "Load %s · %d cores" -msgstr "负载 %s · %d 核" +msgid "Load %s · %d core" +msgid_plural "Load %s · %d cores" +msgstr[0] "负载 %s · %d 核" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3184 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3428 msgctxt "vantage" msgid "Load average" msgstr "平均负载" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1905 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2120 msgid "Load average over 1, 5 and 15 minutes" msgstr "1、5、15 分钟平均负载" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1941 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2156 msgid "Load avg %s" msgstr "平均负载 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3180 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3424 msgid "Local time" msgstr "本地时间" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:156 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164 msgid "Low link rate %s despite good signal; interference or an old device" msgstr "信号良好但链路速率仅 %s;可能存在干扰或设备较旧" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:156 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164 msgid "Low link rate for its signal" msgstr "链路速率低于信号预期" @@ -1108,8 +1088,8 @@ msgstr "链路速率低于信号预期" msgid "MAC" msgstr "MAC" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2932 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2973 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3184 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3216 msgid "MAC address" msgstr "MAC 地址" @@ -1117,19 +1097,15 @@ msgstr "MAC 地址" msgid "MCS %d" msgstr "MCS %d" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1195 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1369 msgid "Make %s narrower" msgstr "使 %s 变窄" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1198 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1372 msgid "Make %s wider" msgstr "使 %s 加宽" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2989 -msgid "Manufacturer of the network adapter" -msgstr "网卡制造商" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:30 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:40 msgid "Mbit/s" msgstr "Mbit/s" @@ -1141,77 +1117,77 @@ msgstr "下次轮询中测量" msgid "Measuring…" msgstr "测量中…" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:82 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1928 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:83 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2143 msgid "Memory" msgstr "内存" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3185 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3429 msgid "Memory in use" msgstr "已用内存" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:81 msgctxt "vantage" msgid "MiB" msgstr "MiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1109 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1279 msgid "Mirrored" msgstr "镜像" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1110 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1280 msgid "Mirrored, scale per direction" msgstr "镜像,每个方向单独刻度" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3112 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3353 msgid "Mode" msgstr "模式" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3175 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3419 msgid "Model" msgstr "型号" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1192 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1366 msgid "Move %s down" msgstr "下移 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1183 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1357 msgid "Move %s left" msgstr "左移 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1186 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1360 msgid "Move %s right" msgstr "右移 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1189 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1363 msgid "Move %s up" msgstr "上移 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1175 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1349 msgid "Move %s: drag, or use the arrow keys" msgstr "移动 %s:拖动或使用方向键" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3044 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3285 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:3084 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3325 msgid "Name contains invisible or control characters" msgstr "名称包含不可见或控制字符" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2935 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2976 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3187 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3219 msgid "Name from" msgstr "名称来源" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2604 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2845 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:3085 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3326 msgid "Name is longer than %d characters" msgstr "名称超过 %d 个字符" @@ -1219,117 +1195,106 @@ msgstr "名称超过 %d 个字符" msgid "Name must be text" msgstr "名称必须是文本" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2876 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2954 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3197 msgid "Name this device" msgstr "命名此设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2510 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2633 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2663 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2920 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2969 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2748 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2875 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2905 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3172 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3212 msgid "Network" msgstr "网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:955 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1402 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1403 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1125 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1689 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1690 msgid "Network path" msgstr "网络路径" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1125 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1298 msgid "Network path background" msgstr "网络路径背景" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1747 -msgid "Networks" -msgstr "网络" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:360 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:377 msgid "Networks: %s" msgstr "网络:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2440 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2654 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2678 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2896 msgctxt "vantage" msgid "New" msgstr "新增" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1528 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1813 msgid "No SSIDs" msgstr "无 SSID" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:119 msgid "No clients" msgstr "无客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2590 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2828 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3366 msgid "No clients connected" msgstr "无客户端连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2715 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2957 msgid "No clients connected." msgstr "没有客户端连接。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2581 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2819 msgid "No clients in this view" msgstr "此视图中没有客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2581 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2819 msgid "No clients match “%s”" msgstr "没有匹配“%s”的客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3123 -msgid "No clients; an idle radio is fine." -msgstr "无客户端;射频空闲属正常。" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:252 -msgid "No clients; idle radios are fine" -msgstr "无客户端;射频空闲属正常" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1580 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1865 msgctxt "vantage" msgid "No default route" msgstr "无默认路由" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:46 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:45 msgid "No interface with a route" msgstr "没有带路由的接口" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3130 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3374 msgid "No interface with a route is up." msgstr "没有带路由的接口处于启用状态。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:209 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:226 msgid "No internet-facing zone found" msgstr "未找到面向互联网的区域" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:48 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3145 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3389 msgid "No link" msgstr "无链路" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:46 msgid "No network interface with a route is up" msgstr "没有带路由的网络接口处于启用状态" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1509 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1794 msgid "No other interfaces are up" msgstr "没有其他接口处于启用状态" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:175 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:177 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:183 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:185 msgid "No problems detected" msgstr "未检测到问题" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:104 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1532 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1817 msgid "No radios reported" msgstr "未报告射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:315 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:332 msgid "" "No rule or port forward opens anything; the warnings above say what does." msgstr "没有规则或端口转发开放任何内容;上方的警告说明了开放的内容。" @@ -1338,24 +1303,24 @@ msgstr "没有规则或端口转发开放任何内容;上方的警告说明了 msgid "No signal" msgstr "无信号" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:119 msgid "No stations are associated right now" msgstr "当前没有站点关联" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2587 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2825 msgid "No wired devices heard" msgstr "未发现有线设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2749 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2991 msgctxt "vantage" msgid "No wireless networks configured." msgstr "未配置无线网络。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2254 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2482 msgid "No wireless radios are reported by this device." msgstr "此设备未报告任何无线射频。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:210 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:227 msgid "" "No zone masquerades, holds the uplink or is called wan, so this page cannot " "tell which side faces the internet. On an access point that is expected; on " @@ -1364,74 +1329,67 @@ msgstr "" "没有区域启用 IP 动态伪装、包含上行接口或名为 wan,因此本页无法判断哪一侧面向" "互联网。在接入点上这是正常的;在路由器上,请检查下方的区域。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:365 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:382 msgid "No zones are configured." msgstr "尚未配置区域。" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 -msgid "Nobody associated" -msgstr "无关联站点" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2715 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2957 msgid "Nobody is moving data right now." msgstr "当前没有设备在传输数据。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2286 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2515 msgid "Noise" msgstr "噪声" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2917 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3169 msgid "Noise / SNR" msgstr "噪声 / 信噪比" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3115 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3357 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3358 msgid "Noise floor" msgstr "底噪" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:251 -msgid "Noise floor not reported by the driver" -msgstr "驱动未报告底噪" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:104 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1121 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1293 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:3083 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3324 msgid "Not a station MAC address" msgstr "不是站点 MAC 地址" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2858 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3119 msgid "Not connected" msgstr "未连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2635 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2966 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2877 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3209 msgid "Not counted per device on a shared port" msgstr "共用端口不按设备统计" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:383 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:400 msgid "Not in effect" msgstr "未生效" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1976 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2193 msgid "Not reported" msgstr "未报告" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2992 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:129 +msgid "Not reported by the driver" +msgstr "驱动未报告" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3233 msgid "Nothing better known" msgstr "无更多信息" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2990 -msgid "Nothing better known; the address is randomised" -msgstr "无更多信息;地址已随机化" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:221 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:238 msgid "Nothing is open in your firewall rules" msgstr "你的防火墙规则中没有开放的内容" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:316 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:333 msgid "Nothing is open in your firewall rules." msgstr "你的防火墙规则中没有开放的内容。" @@ -1440,24 +1398,24 @@ msgctxt "vantage" msgid "OWE" msgstr "OWE" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:167 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:175 msgid "Older %s device" msgstr "较旧的 %s 设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2655 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2897 msgid "Older Wi-Fi generation than the radio; uses more airtime" msgstr "比射频支持的 Wi-Fi 代际更旧;占用更多空口时间" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:311 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:328 msgid "On this router" msgstr "在此路由器上" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 msgctxt "vantage" msgid "Online" msgstr "在线" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:222 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:239 msgid "Only standard housekeeping (ping, DHCP renewals and the like): %d rule" msgid_plural "" "Only standard housekeeping (ping, DHCP renewals and the like): %d rules" @@ -1468,15 +1426,15 @@ msgctxt "vantage" msgid "Open" msgstr "开放" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2556 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2794 msgid "Open details of %s" msgstr "打开 %s 的详情" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:336 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:353 msgid "Open from the internet" msgstr "对互联网开放" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:217 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:234 msgid "Open from the internet: %d" msgstr "对互联网开放:%d" @@ -1484,11 +1442,11 @@ msgstr "对互联网开放:%d" msgid "Open network" msgstr "开放网络" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:656 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:658 msgid "OpenWrt device" msgstr "OpenWrt 设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:251 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:268 msgid "" "Option %s in General Settings has a value firewall4 refuses, so it loads no " "new rules: what is open is unknown." @@ -1496,11 +1454,11 @@ msgstr "" "基本设置中的选项 %s 的值被 firewall4 拒绝,因此不会加载新规则:无法确定开放了" "哪些内容。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1107 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1277 msgid "Overlaid" msgstr "叠加" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1108 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1278 msgid "Overlaid, log scale" msgstr "叠加,对数刻度" @@ -1508,19 +1466,19 @@ msgstr "叠加,对数刻度" msgid "Overview" msgstr "概览" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2916 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3168 msgid "PMF" msgstr "PMF" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1355 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1541 msgid "Paused while hidden" msgstr "页面隐藏时暂停" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:81 msgid "PiB" msgstr "PiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:320 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:337 msgid "" "Ping and other control messages, multicast, DHCP renewals and IPsec passed " "on to your network: what every router lets in." @@ -1528,17 +1486,17 @@ msgstr "" "Ping 和其他控制消息、组播、DHCP 续租以及转发到你网络的 IPsec:每台路由器都会" "放行的流量。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3176 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3420 msgctxt "vantage" msgid "Platform" msgstr "平台" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:171 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:179 msgctxt "vantage" msgid "Poor" msgstr "较差" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2960 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3203 msgid "Port" msgstr "端口" @@ -1546,11 +1504,11 @@ msgstr "端口" msgid "Port %d" msgstr "端口 %d" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2628 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2870 msgid "Port %s" msgstr "端口 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1668 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1955 msgid "Port total: %s" msgstr "端口合计:%s" @@ -1558,292 +1516,293 @@ msgstr "端口合计:%s" msgid "Private" msgstr "私有" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2933 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3185 msgid "Private Wi-Fi address (randomised by the device)" msgstr "私有 Wi-Fi 地址(设备随机化)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2974 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3217 msgid "Private address (randomised by the device)" msgstr "私有地址(设备随机化)" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:266 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:270 msgid "Private device" msgstr "私有设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3173 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3417 msgid "Processes" msgstr "进程" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3147 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3391 msgid "Protocol" msgstr "协议" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2320 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2547 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2549 msgid "Quick filters" msgstr "快速筛选" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2921 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3110 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3173 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3351 msgctxt "vantage" msgid "Radio" msgstr "射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2275 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2503 msgid "Radio details" msgstr "射频详情" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:247 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:255 msgid "Radio is disabled" msgstr "射频已禁用" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:248 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:256 msgid "Radio is enabled but not up" msgstr "射频已启用但未上线" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2298 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3104 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2527 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3345 msgid "Radio settings" msgstr "射频设置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:955 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2227 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2229 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1125 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2455 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2457 msgid "Radios" msgstr "射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1581 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1866 msgid "Reachability not probed" msgstr "未探测可达性" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2620 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2862 msgid "Reached through the uplink port %s, not connected to this device" msgstr "经由上行端口 %s 到达,并未连接到本设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3138 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3382 msgid "Realtime graphs" msgstr "实时图表" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3157 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3401 msgctxt "vantage" msgid "Received" msgstr "已接收" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1356 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1542 msgctxt "vantage" msgid "Reconnecting…" msgstr "重新连接中…" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2456 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2694 msgid "Remove filter: %s" msgstr "移除筛选:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3050 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3291 msgid "Remove name" msgstr "移除名称" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2876 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2954 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3197 msgctxt "vantage" msgid "Rename" msgstr "重命名" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1161 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1335 msgid "Reset" msgstr "重置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2985 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3228 msgid "Reverse DNS of its address" msgstr "其地址的反向 DNS" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:668 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:670 msgid "Root (overlay)" msgstr "Root(overlay)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:264 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:281 msgid "Router admin open: %s" msgstr "路由器管理界面已开放:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:265 -msgid "" -"SSH or the web interface answers any address on the internet. Limit the rule " -"to the addresses you use." -msgstr "" -"SSH 或网页管理界面会响应互联网上的任何地址。请将此规则限制为你使用的地址。" +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:126 +msgid "SSH (port 22)" +msgstr "SSH(端口 22)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3042 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3283 msgid "Save" msgstr "保存" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2924 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3176 msgid "Seen since" msgstr "首次出现" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3158 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3402 msgctxt "vantage" msgid "Sent" msgstr "已发送" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1111 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1281 msgid "Separate lanes" msgstr "分开显示" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:174 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:191 msgid "Settings to check" msgstr "待检查的设置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2961 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3204 msgid "Shared by %d devices" msgstr "%d 台设备共用" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2624 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2866 msgid "Shared port" msgstr "共用端口" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1241 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1415 msgid "Show %s" msgstr "显示 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2582 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2820 msgid "Show all clients" msgstr "显示全部客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1914 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2129 msgid "Show or hide system details" msgstr "显示/隐藏系统详情" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1403 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1690 msgid "Show or hide the network path" msgstr "显示/隐藏网络路径" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2230 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2458 msgid "Show or hide the radio details" msgstr "显示/隐藏射频详情" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2026 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2248 msgid "Show or hide the throughput chart" msgstr "显示/隐藏吞吐量图表" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2740 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2982 msgid "Show or hide the wireless networks" msgstr "显示/隐藏无线网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1642 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2756 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1929 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3000 msgid "Show the clients of %s" msgstr "显示 %s 的客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1668 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1955 msgid "Show the devices on %s" msgstr "显示 %s 上的设备" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:118 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:124 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2512 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2660 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2900 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:119 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:120 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2902 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3152 msgid "Signal" msgstr "信号强度" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:147 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:155 msgid "Signal not reported" msgstr "未报告信号" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3146 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3390 msgctxt "vantage" msgid "Speed" msgstr "速率" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:319 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:336 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:1121 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1293 msgid "Starfield" msgstr "星空" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2591 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2829 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:3111 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352 msgid "Status" msgstr "状态" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:92 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1931 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2146 msgid "Storage" msgstr "存储" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3051 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3292 msgid "Stored on this device in /etc/config/vantage" msgstr "保存在本设备 /etc/config/vantage 中" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:177 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:185 msgid "Strong signal" msgstr "信号强" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:175 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:183 msgid "Strong signal %s, %s link" msgstr "信号强 %s,链路 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:177 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:185 msgid "Strong signal, %s" msgstr "信号强,%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1981 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2203 msgctxt "vantage" msgid "Swap" msgstr "交换分区" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2964 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3207 msgid "Switch ports" msgstr "交换机端口" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:344 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:381 msgid "Switch ports of VLAN %d on %s: %s" msgstr "VLAN %d(%s)的交换机端口:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:383 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:400 msgid "Switched off" msgstr "已关闭" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:956 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1913 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1914 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1126 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2129 msgid "System" msgstr "系统" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3173 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3417 msgid "System settings" msgstr "系统设置" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:30 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:40 msgid "Tbit/s" msgstr "Tbit/s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:75 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1945 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:126 +msgid "Telnet (port 23)" +msgstr "Telnet(端口 23)" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:76 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2160 msgid "Temperature %s" msgstr "温度 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:668 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:670 msgid "Temporary (RAM)" msgstr "临时(RAM)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2511 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2749 msgid "The bridge forgets a device after about five minutes without traffic" msgstr "设备约五分钟无流量后,网桥会将其遗忘" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2585 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2823 msgid "" "The bridges have learned so many addresses that listing them here would " "strain this device." msgstr "网桥学习到的地址过多,在此列出会加重本设备的负担。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:243 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:260 msgid "" "The default Input policy applies there and accepts, so anything on the " "internet can reach the router itself. Add it to the wan zone or set Input to " @@ -1852,20 +1811,25 @@ msgstr "" "该处适用默认入站数据策略且为接受,因此互联网上的任何主机都能访问路由器本身。" "请将其加入 wan 区域,或在基本设置中将入站数据设为拒绝。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3088 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3329 msgid "The device could not write /etc/config/vantage." msgstr "设备无法写入 /etc/config/vantage。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2286 -msgid "" -"The driver reports a placeholder value, so no noise floor or SNR is shown" -msgstr "驱动报告的是占位值,不显示底噪与信噪比" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:131 +msgid "The driver reports no signal levels" +msgstr "驱动未报告信号强度" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:250 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:267 msgid "The firewall cannot load these settings" msgstr "防火墙无法加载这些设置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:247 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:282 +msgid "" +"The firewall lets any address on the internet reach %s. Limit the rule to " +"the addresses you use." +msgstr "防火墙允许互联网上的任何地址访问 %s。请将此规则限制为你使用的地址。" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:264 msgid "" "The interface list could not be read, and the default Input policy accepts: " "an uplink in no zone would be open. Set Input to reject in General Settings." @@ -1873,15 +1837,23 @@ msgstr "" "无法读取接口列表,且默认入站数据策略为接受:不属于任何区域的上行接口将会开" "放。请在基本设置中将入站数据设为拒绝。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2988 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3231 msgid "The name the device announces (WPS)" msgstr "设备广播的名称(WPS)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2619 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:132 +msgid "The one measured client is above %s" +msgstr "唯一已测客户端高于 %s" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:129 +msgid "The only measured client" +msgstr "唯一已测客户端" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2861 msgid "The router this device sends its traffic to" msgstr "此设备发送流量所经的路由器" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:206 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:223 msgid "The settings below apply if traffic reaches them as configured." msgstr "以下设置在流量按配置到达时生效。" @@ -1889,111 +1861,111 @@ msgstr "以下设置在流量按配置到达时生效。" msgid "The stored name has an invalid section id" msgstr "保存的名称包含无效的配置节 ID" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:246 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:263 msgid "The uplinks could not be checked" msgstr "无法检查上行接口" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1589 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1874 msgid "This access point" msgstr "此接入点" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:363 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:380 msgid "This address family is in no zone: the default policies apply." msgstr "此地址族不属于任何区域:适用默认策略。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1589 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1874 msgid "This device" msgstr "此设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3087 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3328 msgid "This device already stores %d names; remove some first." msgstr "此设备已存储 %d 个名称;请先移除部分。" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:104 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 msgid "This device reports no radios" msgstr "此设备未报告任何射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:166 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:183 msgid "" "This page cannot tell what is open. Reload it; if that does not help, check " "the firewall pages." msgstr "本页无法判断开放了哪些内容。请重新加载;如果仍无效,请检查防火墙页面。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3095 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3336 msgid "This radio is not reported any more." msgstr "驱动不再报告此射频。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:203 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:220 msgid "This setup is beyond what this overview checks" msgstr "此配置超出本概览的检查范围" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2858 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3119 msgid "This station is not associated right now." msgstr "此站点当前未关联。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:955 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2018 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2020 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2906 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1125 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2240 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2242 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3158 msgctxt "vantage" msgid "Throughput" msgstr "吞吐量" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1116 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1286 msgid "Throughput chart" msgstr "吞吐量图表" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2011 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2233 msgid "Throughput per link; arrow keys read the values over time" msgstr "每条链路的吞吐量;方向键可查看历史值" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:81 msgctxt "vantage" msgid "TiB" msgstr "TiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3165 msgid "To device" msgstr "到设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2640 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2675 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2728 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2882 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2917 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2970 msgid "To device %s, from device %s" msgstr "到设备 %s,来自设备 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2667 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2909 msgid "To device: %s" msgstr "到设备:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3141 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3385 msgid "To network" msgstr "发往网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2584 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2822 msgid "Too many devices to list" msgstr "设备过多,无法列出" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:956 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2692 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2693 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1126 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2934 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2935 msgctxt "vantage" msgid "Top talkers" msgstr "流量大户" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2926 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2965 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3107 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3178 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3208 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3348 msgid "Traffic" msgstr "流量" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:336 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:383 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:353 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:400 msgctxt "vantage" msgid "Traffic Rules" msgstr "通信规则" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:239 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:256 msgid "" "Traffic from the internet that no forwarding covers still reaches your other " "networks. Set Forward to reject in General Settings." @@ -2001,102 +1973,98 @@ msgstr "" "未被任何转发覆盖的互联网流量仍会到达你的其他网络。请在基本设置中将转发设为拒" "绝。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1721 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1745 -msgid "Traffic now" -msgstr "当前流量" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2285 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3114 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2514 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3355 msgid "Tx power" msgstr "发射功率" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:328 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:345 msgid "" "UPnP is installed: devices on your network can open ports on their own while " "it runs, and those are not listed here." msgstr "" "已安装 UPnP:它运行时,你网络中的设备可以自行开放端口,这些端口不会在此列出。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2857 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:272 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3118 msgctxt "vantage" msgid "Unknown device" msgstr "未知设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3086 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3327 msgid "Unknown device type" msgstr "未知设备类型" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3095 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3336 msgid "Unknown radio" msgstr "未知射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:116 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:115 msgid "Unnamed port forward" msgstr "未命名的端口转发" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:116 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:254 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:115 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:271 msgctxt "vantage" msgid "Unnamed rule" msgstr "未命名的规则" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:58 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2274 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3111 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3145 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2502 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3389 msgctxt "vantage" msgid "Up" msgstr "已上线" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1938 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2153 msgid "Up %s" msgstr "已运行 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:46 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:48 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:50 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:52 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:58 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2043 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3130 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:45 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 +#: 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:2265 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3374 msgctxt "vantage" msgid "Uplink" msgstr "上行链路" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2043 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2265 msgid "Uplink %s" msgstr "上行链路 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3134 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3378 msgid "Uplink · %s" msgstr "上行链路 · %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2024 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2111 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2183 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2246 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2337 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2411 msgid "Upload" msgstr "上传" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:332 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:369 msgid "Upload (from clients)" msgstr "上传(来自客户端)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2928 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3180 msgctxt "vantage" msgid "Uploaded" msgstr "已上传" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2620 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2862 msgid "Upstream" msgstr "上游" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3179 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3423 msgid "Uptime" msgstr "运行时间" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2621 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2969 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2863 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3212 msgid "VLAN %d" msgstr "VLAN %d" @@ -2125,16 +2093,21 @@ msgid "" "and which switch ports a port's VLAN has) and the link state of those switch " "ports (luci getSwconfigPortState)" msgstr "" +"Vantage 仪表盘:设备、上行链路、射频与站点的只读状态(经 luci.vantage " +"wireless 读取无线配置,不含密钥),温度传感器(luci.vantage thermal),网桥已" +"学习到的有线主机(luci.vantage wired:MAC、端口、最后一次收到的时间,以及某端" +"口的 VLAN 包含哪些交换机端口),以及这些交换机端口的链路状态(luci " +"getSwconfigPortState)" #: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:43 msgid "Vendor" msgstr "供应商" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:148 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:156 msgid "Very weak signal %s; expect drops" msgstr "信号极弱 %s;可能频繁断连" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:148 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:156 msgid "Very weak signal; expect drops" msgstr "信号极弱;可能频繁断连" @@ -2234,11 +2207,15 @@ msgstr "WPA3 个人版" msgid "WPS" msgstr "WPS" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2936 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3188 msgid "WPS device name" msgstr "WPS 设备名称" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:171 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1575 +msgid "Warning" +msgstr "警告" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:188 msgctxt "vantage" msgid "Warnings" msgstr "警告" @@ -2247,59 +2224,59 @@ msgstr "警告" msgid "Weak" msgstr "弱" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:149 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2439 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2677 msgid "Weak signal" msgstr "信号弱" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:149 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157 msgid "Weak signal %s; may roam poorly" msgstr "信号弱 %s;漫游可能不佳" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1726 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1728 -msgid "Weakest signal" -msgstr "最弱信号" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:130 +msgid "Weakest of %d client" +msgid_plural "Weakest of %d clients" +msgstr[0] "%d 个客户端中最弱" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:204 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:221 msgid "" "What is open depends on how firewall4 handles %s, which this page does not " "follow. Check the firewall pages." msgstr "开放内容取决于 firewall4 如何处理 %s,本页无法跟踪。请检查防火墙页面。" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:104 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:107 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:109 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2493 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:110 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2731 msgid "Wi-Fi" msgstr "Wi-Fi" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1539 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2493 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1824 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2731 msgid "Wired" msgstr "有线" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:956 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2739 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2740 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1126 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2981 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2982 msgctxt "vantage" msgid "Wireless networks" msgstr "无线网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2886 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3138 msgid "Wireless settings" msgstr "无线设置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2984 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3227 msgid "Your name for this device" msgstr "你为此设备设置的名称" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:377 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:394 msgid "Zone %s" msgstr "区域 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:366 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:383 msgid "Zones" msgstr "区域" @@ -2308,72 +2285,68 @@ msgctxt "vantage" msgid "accept" msgstr "接受" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:88 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:87 msgid "all ports except %s" msgstr "除 %s 以外的所有端口" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:83 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:82 msgid "all protocols" msgstr "所有协议" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1747 -msgid "all up" -msgstr "全部启用" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:134 msgid "an unnamed rule" msgstr "一条未命名的规则" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:112 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:111 msgctxt "vantage" msgid "any zone" msgstr "任意区域" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:345 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:362 msgid "any zone (default policy)" msgstr "任意区域(默认策略)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2280 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2508 msgid "auto" msgstr "自动" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2924 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3176 msgid "before this page opened" msgstr "打开本页之前" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2962 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3205 msgid "behind %s, VLAN %d" msgstr "位于 %s 之后,VLAN %d" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:30 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:40 msgctxt "vantage" msgid "bit/s" msgstr "bit/s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2140 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2369 msgid "collecting · %s of data" msgstr "采集中 · 已采集 %s 数据" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2140 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2369 msgid "collecting · first samples" msgstr "采集中 · 首个样本" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:228 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2120 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:248 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2349 msgid "collecting…" msgstr "采集中…" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:379 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:396 msgid "custom rule file" msgstr "自定义规则文件" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:97 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:125 msgid "dBm" msgstr "dBm" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:339 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2624 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2961 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:376 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2866 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3204 msgid "down" msgstr "已断开" @@ -2382,29 +2355,29 @@ msgctxt "vantage" msgid "drop" msgstr "丢弃" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3016 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3257 msgctxt "vantage" msgid "e.g. Living room TV" msgstr "例如:客厅电视" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:88 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:87 msgid "except %s" msgstr "除 %s 外" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:346 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:363 msgid "forwards nowhere" msgstr "不转发到任何区域" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:100 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:99 msgctxt "vantage" msgid "from %s" msgstr "来自 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:101 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:100 msgid "from anywhere" msgstr "来自任意地址" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:101 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:100 msgid "from anywhere except %s" msgstr "来自除 %s 外的任意地址" @@ -2420,60 +2393,61 @@ msgstr "网关 %s" msgid "half duplex" msgstr "半双工" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2765 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:62 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3008 msgid "idle" msgstr "空闲" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:134 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:140 msgid "ignored: a port forward needs one source zone, not any zone" msgstr "已忽略:端口转发需要一个源区域,而不是任意区域" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:135 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:141 msgid "ignored: its address families conflict" msgstr "已忽略:其地址族相互冲突" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:136 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:142 msgid "ignored: no source zone" msgstr "已忽略:没有源区域" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:133 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:139 msgid "ignored: not marked as compatible with firewall4" msgstr "已忽略:未标记为与 firewall4 兼容" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:139 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:145 msgid "ignored: option %s has a value firewall4 refuses" msgstr "已忽略:选项 %s 的值被 firewall4 拒绝" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:138 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:144 msgid "ignored: zone %s does not exist or is switched off" msgstr "已忽略:区域 %s 不存在或已关闭" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:352 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:369 msgid "internet" msgstr "互联网" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:88 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:116 msgctxt "vantage" msgid "just now" msgstr "刚刚" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:30 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:40 msgctxt "vantage" msgid "kbit/s" msgstr "kbit/s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1923 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2139 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2138 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2368 msgid "last 5 min" msgstr "最近 5 分钟" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:167 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:175 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:104 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2669 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2911 msgid "legacy" msgstr "旧版" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:339 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:376 msgid "link up" msgstr "已连接" @@ -2481,71 +2455,45 @@ msgstr "已连接" msgid "mDNS" msgstr "mDNS" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2986 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3229 msgid "mDNS announcement" msgstr "mDNS 广播" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1721 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1745 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2908 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2968 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3160 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3211 msgid "measuring" msgstr "测量中" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2115 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2344 msgid "measuring…" msgstr "测量中…" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1725 -msgid "no Wi-Fi traffic yet" -msgstr "尚无 Wi-Fi 流量" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1728 -msgid "no clients" -msgstr "无客户端" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2099 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2325 msgctxt "vantage" msgid "no data" msgstr "无数据" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1749 -msgid "no traffic yet" -msgstr "尚无流量" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1587 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1746 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1872 msgid "no uplink" msgstr "无上行链路" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1719 -msgid "none connected" -msgstr "无连接" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2934 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3186 msgid "not known to this AP" msgstr "此 AP 未识别" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2975 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3218 msgid "not known to this 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 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3115 -msgid "not reported" -msgstr "未报告" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3115 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3358 msgid "not reported (driver placeholder %s)" msgstr "未报告(驱动占位值 %s)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2917 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3169 msgid "not reported by the driver" msgstr "驱动未报告" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2136 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2923 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2365 msgctxt "vantage" msgid "now" msgstr "现在" @@ -2554,29 +2502,29 @@ msgstr "现在" msgid "now %s down, %s up" msgstr "当前下行 %s,上行 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3167 msgid "older than the radio (%s)" msgstr "比射频支持的标准更旧(%s)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2114 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2342 msgctxt "vantage" msgid "peak" msgstr "峰值" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1924 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2139 msgid "per core" msgstr "每核" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:381 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:398 msgctxt "vantage" msgid "port forward" msgstr "端口转发" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2902 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3154 msgid "range %s … %s" msgstr "范围 %s … %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3140 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384 msgid "received on %s" msgstr "在 %s 上接收" @@ -2585,11 +2533,11 @@ msgctxt "vantage" msgid "reject" msgstr "拒绝" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:107 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:106 msgid "router port %s" msgstr "路由器端口 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3141 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3385 msgid "sent on %s" msgstr "在 %s 上发送" @@ -2597,73 +2545,234 @@ msgstr "在 %s 上发送" msgid "short GI" msgstr "短 GI" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2643 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2970 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3213 msgid "static entry" msgstr "静态条目" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2963 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3206 msgid "switch port %s" msgstr "交换机端口 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:373 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:390 msgid "switched off" msgstr "已关闭" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:126 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:132 msgid "the covered subnets of zone %s" msgstr "区域 %s 覆盖的子网" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2967 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3210 msgid "the port in total: %s" msgstr "该端口合计:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2962 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3205 msgid "the port: %s" msgstr "端口:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:134 msgid "the set in %s" msgstr "%s 中的地址集合" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:107 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:106 msgid "this router" msgstr "此路由器" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:381 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:398 msgid "traffic rule" msgstr "通信规则" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1592 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1877 msgid "up %s" msgstr "已运行 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2693 -msgid "who uses the bandwidth" -msgstr "带宽使用者" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:377 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:394 msgctxt "vantage" msgid "zone" msgstr "区域" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:375 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:392 msgid "zone forwarding" msgstr "区域转发" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:127 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/firewall.js:133 msgid "zones %s and %s if they share a device" msgstr "区域 %s 和 %s(若两者共用设备)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1721 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1745 -msgid "↑ %s · via %s" -msgstr "↑ %s · 经 %s" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2133 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2362 msgid "−%d min" msgstr "−%d 分钟" +#~ msgid "%d client" +#~ msgid_plural "Weakest of %d clients" +#~ msgstr[0] "%d 个客户端中最弱" + +#~ msgid "%d radios down" +#~ msgstr "%d 个射频未上线" + +#~ msgid "%d radios off" +#~ msgstr "%d 个射频已禁用" + +#~ msgid "%d radios up" +#~ msgstr "%d 个射频已上线" + +#~ msgid "1 radio down" +#~ msgstr "1 个射频未上线" + +#~ msgid "1 radio off" +#~ msgstr "1 个射频已禁用" + +#~ msgid "1 radio up" +#~ msgstr "1 个射频已上线" + +#~ msgid "All %d measured clients are above %s" +#~ msgstr "全部 %d 个已测客户端高于 %s" + +#~ msgid "Weakest of %d clients" +#~ msgstr "%d 个客户端中最弱" + +#~ msgid "%d SSIDs broadcasting" +#~ msgstr "正在广播 %d 个 SSID" + +#~ msgid "%d SSIDs broadcasting; %d without clients, which is fine" +#~ msgstr "正在广播 %d 个 SSID,%d 个无客户端(正常)" + +#~ msgid "%d SSIDs on air" +#~ msgstr "%d 个 SSID 正在广播" + +#~ msgid "%d SSIDs · %d idle" +#~ msgstr "%d 个 SSID · %d 个空闲" + +#~ msgid "%d down" +#~ msgstr "%d 个已关闭" + +#~ msgid "%d errors" +#~ msgstr "%d 个错误" + +#~ msgid "%d in · %d out" +#~ msgstr "%d 入 · %d 出" + +#~ msgid "%d off" +#~ msgstr "%d 个关闭" + +#~ msgid "%d on %s" +#~ msgstr "%d 个在 %s" + +#~ msgid "%d sent · %s retried · %s failed" +#~ msgstr "发送 %d · 重传 %s · 失败 %s" + +#~ msgid "%d up" +#~ msgstr "%d 个已启用" + +#~ msgid "%d wired" +#~ msgstr "%d 个有线" + +#~ msgctxt "vantage" +#~ msgid "%s ago" +#~ msgstr "%s 前" + +#~ msgid "%s of Wi-Fi traffic" +#~ msgstr "占 Wi-Fi 流量的 %s" + +#~ msgid "%s over %d cores" +#~ msgstr "%s / %d 核" + +#~ msgid "All %d clients above %s" +#~ msgstr "全部 %d 个客户端高于 %s" + +#~ msgid "All above %s" +#~ msgstr "全部高于 %s" + +#~ msgid "All good" +#~ msgstr "全部正常" + +#~ msgid "Busiest network" +#~ msgstr "最繁忙网络" + +#~ msgid "Busiest radio" +#~ msgstr "最繁忙射频" + +#~ msgid "Busy; load %s on %d cores; see the busiest processes" +#~ msgstr "繁忙;负载 %s(%d 核);查看最繁忙进程" + +#~ msgid "Click any node for details" +#~ msgstr "点击任意节点查看详情" + +#~ msgid "" +#~ "It forwards SSH or web ports from any address on the internet to %s. The " +#~ "interface list could not be read, so this page cannot tell whether that " +#~ "is the router itself." +#~ msgstr "" +#~ "它将来自互联网上任何地址的 SSH 或网页端口转发到 %s。无法读取接口列表,因此" +#~ "本页无法判断该地址是否为路由器本身。" + +#~ msgid "Load %s on %d cores" +#~ msgstr "负载 %s(%d 核)" + +#~ msgid "Load %s · %d cores" +#~ msgstr "负载 %s · %d 核" + +#~ msgid "Manufacturer of the network adapter" +#~ msgstr "网卡制造商" + +#~ msgid "Networks" +#~ msgstr "网络" + +#~ msgid "No clients; an idle radio is fine." +#~ msgstr "无客户端;射频空闲属正常。" + +#~ msgid "No clients; idle radios are fine" +#~ msgstr "无客户端;射频空闲属正常" + +#~ msgid "Nobody associated" +#~ msgstr "无关联站点" + +#~ msgid "Noise floor not reported by the driver" +#~ msgstr "驱动未报告底噪" + +#~ msgid "Nothing better known; the address is randomised" +#~ msgstr "无更多信息;地址已随机化" + +#~ msgid "" +#~ "SSH or the web interface answers any address on the internet. Limit the " +#~ "rule to the addresses you use." +#~ msgstr "" +#~ "SSH 或网页管理界面会响应互联网上的任何地址。请将此规则限制为你使用的地址。" + +#~ msgid "" +#~ "The driver reports a placeholder value, so no noise floor or SNR is shown" +#~ msgstr "驱动报告的是占位值,不显示底噪与信噪比" + +#~ msgid "Traffic now" +#~ msgstr "当前流量" + +#~ msgid "Weakest signal" +#~ msgstr "最弱信号" + +#~ msgid "all up" +#~ msgstr "全部启用" + +#~ msgid "no Wi-Fi traffic yet" +#~ msgstr "尚无 Wi-Fi 流量" + +#~ msgid "no clients" +#~ msgstr "无客户端" + +#~ msgid "no traffic yet" +#~ msgstr "尚无流量" + +#~ msgid "none connected" +#~ msgstr "无连接" + +#~ msgid "not reported" +#~ msgstr "未报告" + +#~ msgid "who uses the bandwidth" +#~ msgstr "带宽使用者" + +#~ msgid "↑ %s · via %s" +#~ msgstr "↑ %s · 经 %s" + #~ msgid "" #~ "Vantage dashboard: read-only status of the device, uplink, radios and " #~ "stations (wireless configuration without keys, through luci.vantage " diff --git a/luci-theme-vantage/Makefile b/luci-theme-vantage/Makefile index b10d29462..f9fd8d578 100644 --- a/luci-theme-vantage/Makefile +++ b/luci-theme-vantage/Makefile @@ -10,8 +10,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-theme-vantage -PKG_VERSION:=1.0.14 -PKG_RELEASE:=30 +PKG_VERSION:=1.0.15 +PKG_RELEASE:=31 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 672693225..d32576cab 100644 --- a/luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js +++ b/luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js @@ -26,6 +26,10 @@ const callWirelessDevices = rpc.declare({ object: 'luci-rpc', method: 'getWirele const THEME_KEY = 'vantage.theme'; const RAIL_KEY = 'vantage.rail'; const LOGIN_KEY = 'vantage.login'; /* read by the login page's login.js */ +/* the dashboard's network path backdrop (luci-app-vantage view/vantage/overview.js), + picked here when the dashboard is installed; the dashboard listens for BACKDROP_EVENT */ +const BACKDROP_KEY = 'vantage.backdrop.v1'; +const BACKDROP_EVENT = 'vantage:backdrop'; /* 24px stroke icons, drawn for this theme: constant [tag, attributes] lists, built with createElementNS (no markup parsing, no user data) */ @@ -41,13 +45,12 @@ const ICONS = { generic: [ [ 'circle', { cx: '12', cy: '12', r: '8' } ], [ 'circle', { cx: '12', cy: '12', r: '2.2' } ] ], page: [ [ 'path', { d: 'M7 3.5h6.5l4.5 4.5v12.5H7z' } ], [ 'path', { d: 'M13.5 3.5V8H18' } ] ], caret: [ [ 'path', { d: 'm9 6 6 6-6 6' } ] ], - enter: [ [ 'path', { d: 'M19 5v6a3 3 0 0 1-3 3H6M10 10l-4 4 4 4' } ] ], + down: [ [ 'path', { d: 'm6 9 6 6 6-6' } ] ], search: [ [ 'circle', { cx: '11', cy: '11', r: '6.5' } ], [ 'path', { d: 'm16 16 4.5 4.5' } ] ], sun: [ [ 'circle', { cx: '12', cy: '12', r: '4' } ], [ 'path', { d: 'M12 2.5v2M12 19.5v2M4.6 4.6 6 6M18 18l1.4 1.4M2.5 12h2M19.5 12h2M4.6 19.4 6 18M18 6l1.4-1.4' } ] ], moon: [ [ 'path', { d: 'M19.5 14.5A7.5 7.5 0 0 1 9.5 4.5a7.5 7.5 0 1 0 10 10z' } ] ], auto: [ [ 'circle', { cx: '12', cy: '12', r: '8' } ], [ 'path', { d: 'M12 4a8 8 0 0 1 0 16z', 'class': 'vt-fill' } ] ], logout: [ [ 'path', { d: 'M14 4h4.5A1.5 1.5 0 0 1 20 5.5v13a1.5 1.5 0 0 1-1.5 1.5H14' } ], [ 'path', { d: 'M10 8l-4 4 4 4M6 12h10' } ] ], - pin: [ [ 'path', { d: 'M4 5v14M9 12h11M15 7l5 5-5 5' } ] ], info: [ [ 'circle', { cx: '12', cy: '12', r: '8.5' } ], [ 'path', { d: 'M12 11v5.5' } ], [ 'circle', { cx: '12', cy: '7.75', r: '.6' } ] ], more: [ [ 'circle', { cx: '5.5', cy: '12', r: '.9' } ], [ 'circle', { cx: '12', cy: '12', r: '.9' } ], [ 'circle', { cx: '18.5', cy: '12', r: '.9' } ] ] }; @@ -174,6 +177,54 @@ function highlight(text, idx) { return out; } +/* A path ("Network › Firewall") matches only on what it says: the query + as a substring, or each of its words starting a word of the path. Not + as letters scattered across it ("wire" in "Network › Firewall"). + null = no match. */ +function pathScore(query, path) { + const q = query.toLowerCase().trim().replace(/\s+/g, ' '); + const t = String(path || '').toLowerCase(); + if (!q || !t) return null; + const at = t.indexOf(q); + if (at >= 0) return (at === 0 || /[\s\/›\-_(.]/.test(t[at - 1])) ? 10 : 6; + const words = t.split(/[\s\/›\-_(.]+/).filter(Boolean); + return q.split(' ').every(w => words.some(x => x.startsWith(w))) ? 4 : null; +} + +/* Palette results for a query, best first: entries whose title matches, + or only when no title does, those whose path does. Equal scores go to + the shallower entry (Network › Wireless before a Wireless tab). */ +function rankPalette(query, pool) { + const onTitle = [], onPath = []; + for (const e of pool) { + const t = fuzzy(query, e.title); + if (t) { onTitle.push({ e, score: t.score, idx: t.idx }); continue; } + const p = pathScore(query, e.path); + if (p != null) onPath.push({ e, score: p, idx: [] }); + } + const depth = r => (r.e.segs || []).length; + return (onTitle.length ? onTitle : onPath).sort((a, b) => (b.score - a.score) || (depth(a) - depth(b))); +} + +/* The palette without a query: rows under their category's header, which + a category of one row goes without. Under a header a row's path leaves + the category out (a tab shows its page only); a row without one keeps + its whole path. results: [ { e } ] in index order -> [ { r, head, path } ] */ +function paletteLayout(results) { + const size = new Map(); + for (const r of results) size.set(r.e.group, (size.get(r.e.group) || 0) + 1); + let prev = null; + return results.map(r => { + const g = r.e.group, headed = size.get(g) > 1; + const head = (headed && g !== prev) ? g : null; + prev = g; + let path = r.e.path || ''; + if (headed && path === g) path = ''; + else if (headed && path.startsWith(g + ' › ')) path = path.slice(g.length + 3); + return { r, head, path }; + }); +} + /* cells holding only addresses, counters, rates or durations get the mono stack */ const UNITS = /(? { const table = pendingTable(section); @@ -397,10 +468,11 @@ function enhanceStorage() { return E('div', { 'class': 'v-meter-row' }, [ label, E('div', { 'class': 'v-meter-bar is-thin', 'role': 'img', - 'aria-label': '%s: %s %s, %s %s'.format(r.label, fmtBytes(used), _('used'), fmtBytes(size - used), _('free')) }, + 'aria-label': '%s: %s %s, %s %s, %s %s'.format(r.label, fmtBytes(used), _('used'), fmtBytes(size - used), _('free'), fmtBytes(size), _('total')) }, segment('v-seg-used' + (p >= 95 ? ' is-crit' : p >= 80 ? ' is-warn' : ''), used, size)), E('span', { 'class': 'v-meter-val' }, [ - E('b', {}, [ fmtBytes(used) ]), ' ' + _('used') + ' · ' + fmtBytes(size - used) + ' ' + _('free') + ' · ' + fmtBytes(size) + /* a figure and its word stay on one line */ + E('b', {}, [ fmtBytes(used) ]), '\u00a0' + _('used') + ' · ' + fmtBytes(size - used) + '\u00a0' + _('free') + ' · ' + fmtBytes(size) + '\u00a0' + _('total') ]) ]); }))); @@ -700,7 +772,14 @@ return baseclass.extend({ if (!admin) return; this.admin = admin; + /* Appearance opened before the menu came in lacks the network + path's group (hasDashboard): add it now */ + if (this.appear && this.hasDashboard() && !this.appear.querySelector('input[name="vt-backdrop"]')) { + this.appear.appendChild(this.backdropGroup()); + this.syncAppearance(); + } this.dp = (L.env.dispatchpath || []).slice(); + this.missing = notFound(L.env.nodespec); this.cats = ui.menu.getChildren(admin) .filter(c => c.name !== 'logout') @@ -958,18 +1037,14 @@ return baseclass.extend({ this.endSwitch(); if (fly.getAttribute('data-cat') !== cat.name || fly.hidden) { fly.textContent = ''; - const total = cat.pages.length; fly.appendChild(E('div', { 'class': 'vt-fly-head' }, [ - svg(cat.icon, 18), - E('span', { 'class': 'vt-fly-title', 'id': 'vt-fly-title' }, [ cat.title ]), - E('span', { 'class': 'vt-fly-count' }, [ '%d %s'.format(total, total === 1 ? _('page') : _('pages')) ]) + E('span', { 'class': 'vt-fly-title', 'id': 'vt-fly-title' }, [ cat.title ]) ])); const ul = E('ul', { 'class': 'vt-fly-list', 'role': 'list' }); for (const p of cat.pages) { const cur = this.dp[1] === cat.name && this.dp[2] === p.name; const item = E('li', {}, E('a', { 'class': 'vt-fly-link', 'href': L.url('admin', cat.name, p.name), 'aria-current': cur ? 'page' : null }, [ - E('span', {}, [ p.title ]), - p.subs.length ? E('span', { 'class': 'vt-fly-meta' }, [ String(p.subs.length) ]) : '' + E('span', {}, [ p.title ]) ])); if (p.subs.length > 1) { const sub = E('ul', { 'class': 'vt-fly-sub' }); @@ -982,7 +1057,6 @@ return baseclass.extend({ ul.appendChild(item); } fly.appendChild(ul); - fly.appendChild(E('div', { 'class': 'vt-fly-foot' }, [ _('Press', 'vantage-theme'), ' ', E('kbd', {}, [ 'Ctrl K' ]), ' ', _('to search all pages') ])); fly.setAttribute('data-cat', cat.name); fly.setAttribute('role', 'region'); fly.setAttribute('aria-labelledby', 'vt-fly-title'); @@ -1032,11 +1106,8 @@ return baseclass.extend({ this.openTimer = null; this.closeFlyout(false); fly.textContent = ''; - const total = page.subs.length; fly.appendChild(E('div', { 'class': 'vt-fly-head' }, [ - svg(cat.icon, 18), - E('span', { 'class': 'vt-fly-title', 'id': 'vt-fly-title' }, [ page.title ]), - E('span', { 'class': 'vt-fly-count' }, [ '%d %s'.format(total, total === 1 ? _('page') : _('pages')) ]) + E('span', { 'class': 'vt-fly-title', 'id': 'vt-fly-title' }, [ page.title ]) ])); const ul = E('ul', { 'class': 'vt-fly-list', 'role': 'list' }); for (const s of page.subs) @@ -1088,28 +1159,31 @@ return baseclass.extend({ for (let i = 1; i < this.dp.length && i <= 3; i++) { node = node && node.children ? node.children[this.dp[i]] : null; if (!node || !node.title) break; - parts.push({ title: _(node.title), segs: [ 'admin' ].concat(this.dp.slice(1, i + 1)) }); + parts.push({ title: _(node.title), segs: [ 'admin' ].concat(this.dp.slice(1, i + 1)), level: i }); } + /* a 404: the crumbs lead to the category LuCI resolved, then say so */ + if (this.missing) parts.push({ title: _('Not found'), segs: null, level: 0 }); if (!parts.length) return; /* a page with page tabs: its current crumb switches between them, from the top bar, which stays in view while the tabs scroll away */ const cat = this.cats.find(c => c.name === this.dp[1]); - const page = cat && this.dp.length > 3 ? cat.pages.find(p => p.name === this.dp[2]) : null; + const page = cat && !this.missing && this.dp.length > 3 ? cat.pages.find(p => p.name === this.dp[2]) : null; const siblings = page && page.subs.length > 1 ? page : null; + const crumbs = mergeCrumbs(parts); nav.textContent = ''; - parts.forEach((p, i) => { - const last = i === parts.length - 1; + crumbs.forEach((p, i) => { + const last = i === crumbs.length - 1; if (i) nav.appendChild(E('span', { 'class': 'vt-crumb-sep', 'aria-hidden': 'true' }, [ '›' ])); - if (last && siblings && parts.length === 3) { + if (last && siblings && p.level === 3) { /* a disclosure (aria-expanded + aria-controls): the panel is a region of links, not a menu, so no aria-haspopup */ const btn = E('button', { 'type': 'button', 'class': 'vt-crumb vt-crumb-current vt-crumb-switch', 'aria-current': 'page', 'aria-expanded': 'false', 'aria-controls': 'vt-flyout', 'title': _('Other pages in %s').format(siblings.title) - }, [ E('span', {}, [ p.title ]), svg('caret', 14) ]); + }, [ E('span', {}, [ p.title ]), svg('down', 14) ]); btn.addEventListener('click', ev => { if (this.switchOpen()) this.closeFlyout(true); else this.openSwitch(cat, siblings, btn, ev.detail === 0); @@ -1134,7 +1208,7 @@ return baseclass.extend({ renderTabs() { const bar = document.getElementById('vt-tabs'); - if (!bar || this.dp.length < 3) return; + if (!bar || this.missing || this.dp.length < 3) return; const cat = this.admin.children[this.dp[1]]; const page = cat && cat.children ? cat.children[this.dp[2]] : null; if (!page) return; @@ -1161,16 +1235,19 @@ return baseclass.extend({ const key = e.segs.join('/') + '|' + e.title; if (seen.has(key)) return; seen.add(key); - e.hay = (e.path ? e.path + ' › ' : '') + e.title; this.entries.push(e); }; + /* pages carry no icon: their category heads them, and only actions + have one. A tab named like its page (System Log's "System Log") + is that page's entry already. */ for (const c of this.cats) { - if (c.leaf) add({ title: c.title, path: '', group: c.title, segs: [ 'admin', c.name ], icon: c.icon }); + if (c.leaf) add({ title: c.title, path: '', group: c.title, segs: [ 'admin', c.name ] }); for (const p of c.pages) { - add({ title: p.title, path: c.title, group: c.title, segs: [ 'admin', c.name, p.name ], icon: c.icon }); + add({ title: p.title, path: c.title, group: c.title, segs: [ 'admin', c.name, p.name ] }); if (p.subs.length > 1) for (const s of p.subs) - add({ title: s.title, path: c.title + ' › ' + p.title, group: c.title, segs: [ 'admin', c.name, p.name, s.name ], icon: 'page' }); + if (headingKey(s.title) !== headingKey(p.title)) + add({ title: s.title, path: c.title + ' › ' + p.title, group: c.title, segs: [ 'admin', c.name, p.name, s.name ] }); } } }, @@ -1184,8 +1261,13 @@ return baseclass.extend({ const login = this.loginPref(), names = this.loginNames(); for (const k of [ 'grid', 'stars', 'none' ]) if (k !== login) list.push({ title: '%s: %s'.format(_('Login background'), names[k]), path: _('Appearance', 'vantage-theme'), icon: 'page', run: () => this.setLoginPref(k) }); + if (this.hasDashboard()) { + const bd = this.backdropPref(); + for (const k of [ 'grid', 'stars', 'none' ]) + if (k !== bd) list.push({ title: '%s: %s'.format(_('Network path background'), names[k]), path: _('Appearance', 'vantage-theme'), icon: 'page', run: () => this.setBackdropPref(k) }); + } list.push({ title: _('Log out'), path: _('Session'), icon: 'logout', segs: [ 'admin', 'logout' ] }); - list.forEach(a => { a.hay = a.path + ' › ' + a.title; a.group = _('Actions'); }); + list.forEach(a => { a.group = _('Actions'); }); return list; }, @@ -1210,7 +1292,7 @@ return baseclass.extend({ const list = E('ul', { 'class': 'vt-pal-list', 'id': 'vt-pal-list', 'role': 'listbox', 'aria-label': _('Results', 'vantage-theme') }); const count = E('span', { 'class': 'vt-pal-count' }); const box = E('div', { 'class': 'vt-pal', 'role': 'dialog', 'aria-modal': 'true', 'aria-label': _('Command palette') }, [ - E('div', { 'class': 'vt-pal-field' }, [ svg('search', 18), input, E('kbd', {}, [ 'Esc' ]) ]), + E('div', { 'class': 'vt-pal-field' }, [ svg('search', 18), input ]), list, E('div', { 'class': 'vt-pal-foot' }, [ E('span', {}, [ E('kbd', {}, [ '↑' ]), E('kbd', {}, [ '↓' ]), _('navigate') ]), @@ -1242,35 +1324,18 @@ return baseclass.extend({ const pal = this.pal; const q = pal.input.value.trim(); const pool = this.entries.concat(this.actions()); - let results; - - if (!q) { - results = pool.map(e => ({ e, idx: [] })); - } - else { - results = []; - for (const e of pool) { - const onTitle = fuzzy(q, e.title); - const onPath = onTitle ? null : fuzzy(q, e.hay); - if (onTitle) results.push({ e, score: onTitle.score + 6, idx: onTitle.idx }); - else if (onPath) results.push({ e, score: onPath.score * .6, idx: [] }); - } - results.sort((a, b) => b.score - a.score); - results = results.slice(0, 40); - } + const found = q ? rankPalette(q, pool) : null; + const results = q ? found.slice(0, 40) : pool.map(e => ({ e, idx: [] })); + const rows = q ? results.map(r => ({ r, head: null, path: r.e.path })) : paletteLayout(results); pal.list.textContent = ''; pal.items = []; - let group = null; - results.forEach((r, n) => { - if (!q && r.e.group !== group) { - group = r.e.group; - pal.list.appendChild(E('li', { 'class': 'vt-pal-group', 'role': 'presentation' }, [ group ])); - } + rows.forEach(({ r, head, path }, n) => { + if (head) pal.list.appendChild(E('li', { 'class': 'vt-pal-group', 'role': 'presentation' }, [ head ])); const li = E('li', { 'class': 'vt-pal-item', 'role': 'option', 'id': 'vt-pal-opt-' + n, 'aria-selected': 'false' }, [ - svg(r.e.icon, 18), + r.e.icon ? svg(r.e.icon, 18) : '', highlight(r.e.title, r.idx), - r.e.path ? E('span', { 'class': 'vt-pal-path' }, [ r.e.path ]) : '', + path ? E('span', { 'class': 'vt-pal-path' }, [ path ]) : '', E('kbd', { 'class': 'vt-pal-enter' }, [ '↵' ]) ]); li.addEventListener('mousemove', () => this.setPaletteActive(n, false)); @@ -1282,7 +1347,7 @@ return baseclass.extend({ if (!results.length) pal.list.appendChild(E('li', { 'class': 'vt-pal-empty', 'role': 'presentation' }, [ _('No matching pages') ])); - pal.count.textContent = q ? '%d / %d'.format(results.length, pool.length) : '%d %s'.format(pool.length, _('items', 'vantage-theme')); + pal.count.textContent = q ? N_(found.length, '%d result', '%d results', 'vantage-theme').format(found.length) : ''; this.setPaletteActive(0, true); }, @@ -1398,6 +1463,23 @@ return baseclass.extend({ this.syncAppearance(); }, + /* Vantage's dashboard, where this user may open it: its network path + takes the same backdrops as the login page */ + hasDashboard() { + return !!(this.admin && ui.menu.getChildren(this.admin).some(c => c.name === 'dashboard' && c.action && c.action.path === 'vantage/overview')); + }, + + backdropPref() { + const p = storageGet(BACKDROP_KEY); + return (p === 'stars' || p === 'none') ? p : 'grid'; + }, + + setBackdropPref(pref) { + storageSet(BACKDROP_KEY, pref === 'grid' ? null : pref); + window.dispatchEvent(new CustomEvent(BACKDROP_EVENT)); + this.syncAppearance(); + }, + setupTheme() { const btn = document.getElementById('vt-theme'); if (btn) { @@ -1415,19 +1497,20 @@ return baseclass.extend({ if (mq && mq.addEventListener) mq.addEventListener('change', () => { if (this.themePref() === 'auto') this.applyTheme(); }); window.addEventListener('storage', ev => { if (ev.key === THEME_KEY) this.applyTheme(); - else if (ev.key === LOGIN_KEY) this.syncAppearance(); + else if (ev.key === LOGIN_KEY || ev.key === BACKDROP_KEY) this.syncAppearance(); }); this.applyTheme(); }, - /* Appearance, under the colour-theme button: the colour theme and the - login background, each a native radio group (the arrow keys move + /* Appearance, under the colour-theme button: the colour theme, the + login background and, with the dashboard, the network path's + background, each a native radio group (the arrow keys move within it) drawn as segments. Choices apply at once and stay open; Escape, Tab out of either end, a click outside, resizing or scrolling the page close it. */ - appearanceEl() { - if (this.appear) return this.appear; - const group = (name, legend, opts, set) => E('fieldset', { 'class': 'vt-appear-set' }, [ + /* one of Appearance's radio groups */ + appearGroup(name, legend, opts, set) { + return E('fieldset', { 'class': 'vt-appear-set' }, [ E('legend', {}, [ legend ]), E('div', { 'class': 'vt-appear-track' }, opts.map(o => { const input = E('input', { 'type': 'radio', 'name': name, 'value': o[0] }); @@ -1435,13 +1518,24 @@ return baseclass.extend({ return E('label', { 'class': 'vt-appear-opt' }, [ input ].concat(o[2] ? [ svg(o[2], 16) ] : [], [ E('span', {}, [ o[1] ]) ])); })) ]); + }, + + /* the network path's group, once the menu says the dashboard is here */ + backdropGroup() { + const n = this.loginNames(); + return this.appearGroup('vt-backdrop', _('Network path background'), [ [ 'grid', n.grid ], [ 'stars', n.stars ], [ 'none', n.none ] ], v => this.setBackdropPref(v)); + }, + + appearanceEl() { + if (this.appear) return this.appear; + const group = (name, legend, opts, set) => this.appearGroup(name, legend, opts, set); const login = this.loginNames(); const box = E('div', { 'id': 'vt-appearance', 'class': 'vt-appearance', 'role': 'dialog', 'aria-label': _('Appearance', 'vantage-theme'), 'hidden': 'hidden' }, [ group('vt-colour', _('Colour theme'), [ [ 'auto', _('Auto', 'vantage-theme'), 'auto' ], [ 'light', _('Light', 'vantage-theme'), 'sun' ], [ 'dark', _('Dark', 'vantage-theme'), 'moon' ] ], v => this.setTheme(v)), group('vt-login', _('Login background'), [ [ 'grid', login.grid ], [ 'stars', login.stars ], [ 'none', login.none ] ], v => this.setLoginPref(v)) - ]); + ].concat(this.hasDashboard() ? [ this.backdropGroup() ] : [])); box.addEventListener('keydown', ev => { if (ev.key === 'Escape') { ev.preventDefault(); ev.stopPropagation(); this.closeAppearance(true); } else if (ev.key === 'Tab') { @@ -1465,7 +1559,7 @@ return baseclass.extend({ syncAppearance() { if (!this.appear) return; - const now = { 'vt-colour': this.themePref(), 'vt-login': this.loginPref() }; + const now = { 'vt-colour': this.themePref(), 'vt-login': this.loginPref(), 'vt-backdrop': this.backdropPref() }; Array.prototype.forEach.call(this.appear.querySelectorAll('input[type="radio"]'), r => { r.checked = (now[r.name] === r.value); }); }, @@ -1513,11 +1607,10 @@ return baseclass.extend({ chip.textContent = ''; /* device strings go in as text nodes (E() would parse a string as HTML) */ const text = v => [ document.createTextNode(String(v)) ]; - chip.appendChild(E('b', {}, text(board.hostname))); - if (product) { - chip.appendChild(E('span', { 'class': 'vt-host-sep', 'aria-hidden': 'true' }, text('·'))); - chip.appendChild(E('span', {}, text(product))); - } + host.chipNames(board.hostname, product).forEach((name, i) => { + if (i) chip.appendChild(E('span', { 'class': 'vt-host-sep', 'aria-hidden': 'true' }, text('·'))); + chip.appendChild(i ? E('span', {}, text(name)) : E('b', {}, text(name))); + }); const rel = board.release && board.release.description; chip.setAttribute('title', [ board.hostname, product, rel ].filter(Boolean).join('\n')); chip.hidden = false; @@ -1909,12 +2002,8 @@ return baseclass.extend({ /* (i) shows, and the text folds to a line, while the text needs more than one line. Text that is not displayed (another tab, an unmet - dependency) measures 0 and waits for the next resize notification. */ - fitHelp(desc) { - this.fitHelps([ desc ]); - }, - - /* all sizes are read before any button changes: a write between two + dependency) measures 0 and waits for the next resize notification. + All sizes are read before any button changes: a write between two reads forced a layout per field (66 when the Wireless modal opened). Folded, the text still measures its full height. The line's end is set as data-v-end ("cut" at --vt-cut, or "fade"), which the CSS reads. */ diff --git a/luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/host.js b/luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/host.js index c84a683be..9e3a8264f 100644 --- a/luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/host.js +++ b/luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/host.js @@ -8,8 +8,9 @@ * name ("Qualcomm Technologies, Inc. IPQ5332/RDP442/AP-MI01.3") rather than * the product. In that case (or when the model is missing) the product name * is derived from board_name ("zyxel,nwa50be" -> "Zyxel NWA50BE"): vendor - * capitalised (or its usual spelling), model upper-cased. Pure functions, - * no DOM, unit tested in tests/host.test.js. + * capitalised (or its usual spelling), model upper-cased. The chip leaves + * out a name the other one contains. Pure functions, no DOM, unit tested + * in tests/host.test.js. */ /* SoC vendors, reference boards and placeholders: not a product name. @@ -52,6 +53,22 @@ function fromBoardName(boardName) { return vendorName(vendor) + ' ' + model.replace(/,/g, ' ').toUpperCase(); } +/* names compared for repeats: case, spaces and punctuation don't count + ("cudy-wr-3000" and "Cudy WR3000" are one name) */ +function nameKey(s) { + return clean(s).toLowerCase().replace(/[^\p{L}\p{N}]+/gu, ''); +} + +/* the host chip's names, hostname first: a name the other one contains + only repeats it and is left out (the product, when they are the same) */ +function chipNames(hostname, product) { + const h = clean(hostname), p = clean(product); + const hk = nameKey(h), pk = nameKey(p); + if (!p || (h && pk && hk.indexOf(pk) >= 0)) return h ? [ h ] : []; + if (!h || (hk && pk.indexOf(hk) >= 0)) return [ p ]; + return [ h, p ]; +} + /* product name for a `system board` reply, '' when nothing usable */ function productName(board) { if (!board || typeof board !== 'object') return ''; @@ -62,6 +79,7 @@ function productName(board) { return baseclass.extend({ productName, + chipNames, fromBoardName, looksLikeReference }); diff --git a/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css b/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css index d59b0e96b..7037bec02 100644 --- a/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css +++ b/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css @@ -24,7 +24,10 @@ --fs-xl: 20px; --fs-2xl: 24px; + /* spacing: steps of 4px, with 2px and 6px for tight insides */ + --sp-0-5: 2px; --sp-1: 4px; + --sp-1-5: 6px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; @@ -32,9 +35,19 @@ --sp-6: 24px; --sp-8: 32px; + /* font weights: four steps only (static fonts draw 620-680 as bold) */ + --fw-regular: 400; + --fw-medium: 500; + --fw-semibold: 600; + --fw-bold: 700; + + /* radii: bars, small controls, controls, cards, large icon tiles + (pills are 999px, dots 50%) */ + --r-xs: 2px; --r-sm: 4px; --r: 6px; --r-lg: 8px; + --r-xl: 12px; --rail-w: 56px; --rail-w-pinned: 204px; @@ -70,6 +83,7 @@ --err: #c42b2b; --err-soft: rgba(196, 43, 43, .1); --err-ink: #ffffff; /* text on an --err / --info fill, >= 4.5:1 */ + --warn-ink: #ffffff; /* text on a --warn fill (counts, warning tooltips); #1a1200 was 3.4:1 */ --info: #1c64c4; --info-ink: #ffffff; --ok-text: #0a7262; /* --ok as text on control fills (s3, s4) */ @@ -82,9 +96,9 @@ --scrim: rgba(20, 23, 26, .38); --shadow-pop: 0 12px 32px rgba(20, 23, 26, .16), 0 2px 6px rgba(20, 23, 26, .08); --zone-mix: .22; - --seg-bg: var(--s3); /* segmented control: track, selected segment */ + --seg-bg: var(--s3); /* segmented control: track, selected segment and its ring */ --seg-on: var(--s2); - --seg-on-ring: inset 0 0 0 1px var(--line); /* inset: drawn at the segment's padding edge */ + --seg-on-ring: inset 0 0 0 1px var(--accent-line); /* inset: drawn at the segment's padding edge */ } html[data-darkmode="true"] { @@ -116,6 +130,7 @@ html[data-darkmode="true"] { --err: #ff6b6b; --err-soft: rgba(255, 107, 107, .12); --err-ink: #1a0505; /* white on the light dark-mode red was 2.8:1 */ + --warn-ink: #1a1200; --info: #6cb4ff; --info-ink: #0d0e10; --ok-text: var(--ok); @@ -128,7 +143,6 @@ html[data-darkmode="true"] { --zone-mix: .2; --seg-bg: var(--bg); --seg-on: var(--s3); - --seg-on-ring: inset 0 0 0 1px var(--line-2); } /* touch: controls are sized by the pointer, not the screen width */ @@ -153,6 +167,14 @@ html[data-darkmode="true"] { --v-accent: var(--accent-text); /* olive: lime is unreadable on light */ --v-accent-ink: #ffffff; --v-accent-soft: var(--accent-soft); + /* the accent by role, as the theme's own controls use it: text and + icons; borders, rings and selection bars; the lime fill of primary + buttons and pressed picks with its ink */ + --v-accent-text: var(--accent-text); + --v-accent-line: var(--accent-line); + --v-accent-fill: var(--accent); + --v-accent-fill-hover: var(--accent-hover); + --v-accent-fill-ink: var(--accent-ink); --v-ok: var(--ok); --v-ok-soft: var(--ok-soft); --v-warn: var(--warn); @@ -161,6 +183,34 @@ html[data-darkmode="true"] { --v-err-soft: var(--err-soft); --v-info: var(--info); --v-info-soft: var(--info-soft); + /* status colours as text on their soft fill, >= 4.5:1 on a hovered row too */ + --v-ok-text: var(--ok-text); + --v-warn-text: var(--warn-text); + --v-err-text: var(--err-text); + --v-info-text: var(--info-text); + --v-focus: var(--focus); /* a focused field: border plus a 1px ring of it */ + --v-scrim: var(--scrim); /* under dialogs, drawers and sheets */ + --v-seg-bg: var(--seg-bg); /* segmented control: track, selected segment, its ring */ + --v-seg-on: var(--seg-on); + --v-seg-on-ring: var(--seg-on-ring); + --v-hover: color-mix(in srgb, var(--s3) 55%, transparent); /* a hovered row on a card */ + --v-surface-4: var(--s4); /* a hovered item in a menu (menus are --v-surface-2) */ + --v-meter: var(--info); /* memory and storage bars: blue (lime is download) */ + --v-card-px: var(--card-px); /* card insides: 20 / 16px, 14px on phones */ + --v-card-py: var(--card-py); + --v-sp-0-5: var(--sp-0-5); /* spacing: 2 4 6 8 12 16 20 24 32 px */ + --v-sp-1: var(--sp-1); + --v-sp-1-5: var(--sp-1-5); + --v-sp-2: var(--sp-2); + --v-sp-3: var(--sp-3); + --v-sp-4: var(--sp-4); + --v-sp-5: var(--sp-5); + --v-sp-6: var(--sp-6); + --v-sp-8: var(--sp-8); + --v-fw-regular: var(--fw-regular); /* weights: 400 500 600 700 */ + --v-fw-medium: var(--fw-medium); + --v-fw-semibold: var(--fw-semibold); + --v-fw-bold: var(--fw-bold); --v-font: var(--font); --v-mono: var(--mono); --v-fs-micro: var(--fs-micro); /* the type scale: 10.5 12 13 14 16 20 24 px */ @@ -170,12 +220,18 @@ html[data-darkmode="true"] { --v-fs-lg: var(--fs-lg); --v-fs-xl: var(--fs-xl); --v-fs-2xl: var(--fs-2xl); + --v-r-xs: var(--r-xs); /* radii: 2 4 6 8 12 px */ --v-r-sm: var(--r-sm); --v-r: var(--r); --v-r-lg: var(--r-lg); + --v-r-xl: var(--r-xl); --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-raise: 0 6px 16px rgba(20, 23, 26, .08); /* a card lifted under the pointer */ --v-shadow-pop: var(--shadow-pop); /* lists and menus that open over the page */ + /* the dashboard's drawer and its scrim: over the rail and the top bar + (300), under modals (1000) and menus (1100) */ + --v-z-drawer: 890; /* where sticky content may start: below the top bar (page tabs scroll) */ --v-stick-top: var(--stick-top); @@ -199,6 +255,7 @@ html[data-darkmode="true"] { --v-accent: var(--accent); /* lime signal */ --v-accent-ink: var(--accent-ink); --v-shadow: 0 1px 0 rgba(0, 0, 0, .35); + --v-shadow-raise: 0 6px 16px rgba(0, 0, 0, .4); --v-chart-1: #c8f031; --v-chart-2: #3f8fe8; @@ -336,11 +393,6 @@ html[data-darkmode="true"] .vt-brand-tile { fill: #16181b; } text-decoration: none !important; } .vt-brand svg { flex: none; } -.vt-brand-word { - font-weight: 650; font-size: var(--fs-md); letter-spacing: .02em; - white-space: nowrap; overflow: hidden; - display: none; -} .vt-rail-list { list-style: none; margin: 0; padding: var(--sp-2) 0; @@ -395,7 +447,6 @@ html[data-darkmode="true"] .vt-brand-tile { fill: #16181b; } /* pinned rail: labels + inline accordion instead of flyouts */ html[data-rail="pinned"] .vt-rail { width: var(--rail-w-pinned); } -html[data-rail="pinned"] .vt-brand-word, html[data-rail="pinned"] .vt-rail-label { display: block; } html[data-rail="pinned"] .vt-rail-caret { display: block; } html[data-rail="pinned"] .vt-rail-item.is-expanded > .vt-rail-link .vt-rail-caret { transform: rotate(90deg); } @@ -436,9 +487,7 @@ html[data-rail="pinned"] .vt-frame { margin-left: var(--rail-w-pinned); } border-bottom: 1px solid var(--line); flex: none; } -.vt-fly-head svg { width: 18px; height: 18px; color: var(--accent-text); } .vt-fly-title { font-size: var(--fs-md); font-weight: 600; } -.vt-fly-count { margin-left: auto; font: var(--fs-micro)/1 var(--mono); color: var(--text-3); letter-spacing: .04em; } .vt-fly-list { list-style: none; margin: 0; padding: var(--sp-2); overflow-y: auto; flex: 1 1 auto; } .vt-fly-list > li + li { margin-top: 1px; } @@ -451,7 +500,6 @@ html[data-rail="pinned"] .vt-frame { margin-left: var(--rail-w-pinned); } } .vt-fly-link:hover { background: var(--s3); } .vt-fly-link[aria-current] { background: var(--accent-soft); color: var(--accent-text); font-weight: 600; } -.vt-fly-link .vt-fly-meta { margin-left: auto; font: var(--fs-micro)/1 var(--mono); color: var(--text-3); } .vt-fly-sub { list-style: none; margin: 0 0 var(--sp-1) 18px; padding: 0; border-left: 1px solid var(--line-2); } .vt-fly-sub a { display: block; padding: 4px 10px; @@ -461,11 +509,6 @@ html[data-rail="pinned"] .vt-frame { margin-left: var(--rail-w-pinned); } } .vt-fly-sub a:hover { color: var(--text); background: var(--s3); } .vt-fly-sub a[aria-current] { color: var(--accent-text); font-weight: 600; box-shadow: inset 2px 0 0 var(--accent-text); } -.vt-fly-foot { - flex: none; padding: var(--sp-2) var(--sp-4); - border-top: 1px solid var(--line); - color: var(--text-3); font-size: var(--fs-micro); letter-spacing: .06em; text-transform: uppercase; -} .vt-scrim { position: fixed; inset: 0; z-index: 280; background: var(--scrim); } @@ -516,7 +559,7 @@ a.vt-crumb:hover { color: var(--text); } .vt-crumb-switch > svg { flex: none; width: 14px; height: 14px; color: var(--text-3); transition: transform .15s; } .vt-crumb-switch:hover, .vt-crumb-switch[aria-expanded="true"] { background: var(--s3); } .vt-crumb-switch:focus-visible { outline-offset: 0; } -.vt-crumb-switch[aria-expanded="true"] > svg { transform: rotate(90deg); } +.vt-crumb-switch[aria-expanded="true"] > svg { transform: rotate(180deg); } @media (width > 720px) { /* the flyout as a dropdown under the crumb (left: set from the crumb) */ .vt-flyout.is-switch { @@ -593,7 +636,7 @@ a.vt-crumb:hover { color: var(--text); } } .vt-appear-opt:hover { color: var(--text); } .vt-appear-opt > input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; pointer-events: none; } -.vt-appear-opt:has(> input:checked) { background-color: var(--seg-on); color: var(--accent-text); font-weight: 600; box-shadow: inset 0 0 0 1px var(--accent-line); } +.vt-appear-opt:has(> input:checked) { background-color: var(--seg-on); color: var(--accent-text); font-weight: 600; box-shadow: var(--seg-on-ring); } .vt-appear-opt:has(> input:focus-visible) { outline: 2px solid var(--focus); outline-offset: -1px; } .vt-appear-opt svg { flex: none; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; } @@ -608,7 +651,7 @@ a.vt-crumb:hover { color: var(--text); } font-size: var(--fs-sm); white-space: nowrap; } -.vt-host b { color: var(--text); font-weight: 600; font-family: var(--mono); font-size: var(--fs-micro); } +.vt-host b { color: var(--text); font-weight: 600; } .vt-host span { overflow: hidden; text-overflow: ellipsis; } .vt-host-sep { color: var(--text-3); } @@ -626,31 +669,15 @@ a.vt-crumb:hover { color: var(--text); } } #indicators > span[data-clickable] { cursor: pointer; } #indicators > span[data-clickable]:hover { border-color: var(--text-3); color: var(--text); } -#indicators > span[data-indicator="poll-status"][data-style="active"] { position: relative; isolation: isolate; } +/* auto-refresh on: a still dot (the label says it, a pulse only + distracted); paused: a square */ #indicators > span[data-indicator="poll-status"][data-style="active"]::before { content: ""; width: 7px; height: 7px; border-radius: 50%; - background: var(--accent-text); -} -/* the pulse is a ring of its own that scales and fades: the compositor - runs it, where an animated box-shadow repainted the page every frame. - It sits behind the dot (z-index -1 in the pill's isolated stack), so - the dot never lightens, and is invisible unless animated: with reduced - motion the one near-instant run ends on opacity 0. */ -#indicators > span[data-indicator="poll-status"][data-style="active"]::after { - content: ""; position: absolute; z-index: -1; left: 10px; top: calc(50% - 3.5px); - width: 7px; height: 7px; border-radius: 50%; - background: var(--accent-line); - opacity: 0; - pointer-events: none; - animation: vt-live 2s ease-out infinite; + background: var(--ok); } #indicators > span[data-indicator="poll-status"][data-style="inactive"]::before { content: ""; width: 7px; height: 7px; border-radius: 1px; background: var(--text-3); } -@keyframes vt-live { - 0% { transform: scale(1); opacity: 1; } - 70%, 100% { transform: scale(2.7); opacity: 0; } -} /* "Unsaved Changes: N" -> label + prominent count (text node stays for LuCI) */ #indicators > span[data-indicator][data-count] { font-size: 0; gap: 8px; padding-right: 4px; @@ -666,7 +693,7 @@ a.vt-crumb:hover { color: var(--text); } display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 999px; - background: var(--warn); color: #1a1200; + background: var(--warn); color: var(--warn-ink); font: 700 var(--fs-micro)/1 var(--mono); } #indicators > span[data-indicator="media_error"] { color: var(--err); border-color: var(--err); background: var(--err-soft); } @@ -770,6 +797,11 @@ a.vt-crumb:hover { color: var(--text); } } .vt-pal-foot span { display: inline-flex; align-items: center; gap: 6px; } .vt-pal-foot .vt-pal-count { margin-left: auto; font-family: var(--mono); font-size: var(--fs-micro); } +/* no keyboard, no key hints */ +/* no keyboard hints on touch; the result count stays */ +@media (hover: none) { + .vt-pal kbd, .vt-pal-foot > span:not(.vt-pal-count) { display: none; } +} /* ------------------------------------ 5. content: map, section, options */ @@ -786,7 +818,7 @@ a.vt-crumb:hover { color: var(--text); } .cbi-map { margin-bottom: var(--sp-6); } .cbi-map > h2, .vt-main > h2, #view > h2, #view > div > h2:first-child, .cbi-map > h2:first-child { margin: 0 0 6px; - font-size: var(--fs-2xl); font-weight: 650; line-height: 1.2; + font-size: var(--fs-2xl); font-weight: 600; line-height: 1.2; letter-spacing: -.02em; } .vt-main > h2[name="content"] { margin-bottom: var(--sp-5); } @@ -1012,7 +1044,8 @@ legend { font-size: var(--fs-md); font-weight: 600; padding: 0; margin-bottom: v /* ------------------------------------------------------------ 6. widgets */ -input, select, textarea, button { font: inherit; color: inherit; } +/* zero specificity, like the button rule below, which must win over it */ +:where(input, select, textarea, button) { font: inherit; color: inherit; } .cbi-input-text, .cbi-input-password, .cbi-input-select, .cbi-input-textarea, .cbi-section-create-name, .vt-main select, .vt-main textarea, @@ -1709,22 +1742,24 @@ table { border-collapse: separate; border-spacing: 0; width: 100%; } .td.cbi-section-actions .vt-acts-more.spinning::before { margin: 0; } .vt-actmenu { position: fixed; z-index: 1100; - display: flex; flex-direction: column; gap: 2px; - min-width: 168px; max-width: calc(100vw - 16px); padding: 6px; + display: flex; flex-direction: column; + min-width: 168px; max-width: calc(100vw - 16px); padding: var(--sp-1); overflow-y: auto; overscroll-behavior: contain; border: 1px solid var(--line-2); border-radius: var(--r); background: var(--s2); box-shadow: var(--shadow-pop); } .vt-actmenu[hidden] { display: none; } +/* items as .cbi-dropdown's: the pointer's on --s4, the keyboard's with the + accent bar too */ .vt-actmenu-item { display: flex; align-items: center; - min-height: var(--ctl-h); padding: 0 12px; + min-height: calc(var(--ctl-h) - 4px); padding: 4px 8px; border: 0; border-radius: var(--r-sm); background: transparent; color: var(--text); - font: inherit; font-size: var(--fs-base); text-align: left; white-space: nowrap; cursor: pointer; + font: inherit; font-size: var(--fs-base); font-weight: 400; text-align: left; white-space: nowrap; cursor: pointer; } -.vt-actmenu-item:hover { background: var(--s3); } -.vt-actmenu-item:focus-visible { background: var(--s3); outline: 2px solid var(--focus); outline-offset: -2px; } +.vt-actmenu-item:hover { background: var(--s4); } +.vt-actmenu-item:focus-visible { background: var(--s4); outline: none; box-shadow: inset 2px 0 0 var(--accent-text); } .vt-actmenu-item.is-danger { color: var(--err); } .vt-actmenu-item[disabled] { opacity: .5; cursor: default; } .vt-actmenu-item[disabled]:hover { background: none; } @@ -1785,7 +1820,7 @@ div.right > .btn, div.right > .cbi-button, div.right > button { margin-left: 0; :is(.cbi-tabmenu > li > a, .vt-pagetabs > .vt-tab):focus-visible { outline-offset: -1px; border-radius: calc(var(--r) + 3px); } /* the selected segment carries the signal (text and ring): white on the grey track alone was hard to pick out; hover keeps it */ -.cbi-tabmenu > li.cbi-tab > a, .cbi-tabmenu > li.cbi-tab > a:hover, .vt-pagetabs > .vt-tab[aria-current] { background-color: var(--seg-on); color: var(--accent-text); font-weight: 600; box-shadow: inset 0 0 0 1px var(--accent-line); } +.cbi-tabmenu > li.cbi-tab > a, .cbi-tabmenu > li.cbi-tab > a:hover, .vt-pagetabs > .vt-tab[aria-current] { background-color: var(--seg-on); color: var(--accent-text); font-weight: 600; box-shadow: var(--seg-on-ring); } .cbi-tabmenu > li[data-errors] > a::after { content: attr(data-errors); display: inline-flex; align-items: center; justify-content: center; @@ -1867,7 +1902,7 @@ div.right > .btn, div.right > .cbi-button, div.right > button { margin-left: 0; :is(.ifacebox-body, .ifacebadge) > span:has(> .nowrap) > .nowrap > strong { color: var(--text-3); font: 600 var(--fs-micro)/1.55 var(--font); - letter-spacing: .06em; text-transform: uppercase; + letter-spacing: .08em; text-transform: uppercase; white-space: nowrap; } @@ -1920,16 +1955,17 @@ div:has(> .ifacebox > .ifacebox-head.cbi-tooltip-container) > .ifacebox { width: .ifacebox-head.active { background: var(--accent-soft); color: var(--accent-text); } .ifacebox-body { padding: 8px 10px; font-size: var(--fs-sm); color: var(--text-2); } .ifacebox-body img { width: 18px; height: 18px; } -/* Status -> Port status, each box: a link dot by the name (as on the - upstream and radio cards), the speed as its figure, the zone as a bare - bar and the counters' arrows in the dashboard's upload and download - colours (menu-vantage.js puts them in spans). LuCI's port picture only - repeats the link state: hidden. A port without link is muted throughout */ +/* Status -> Port status, each box: a ring by the name of a port without + link (as on the upstream and radio cards; a port with link has none), + the speed as its figure, the zone as a bare bar and the counters' + arrows in the dashboard's upload and download colours (menu-vantage.js + puts them in spans). LuCI's port picture only repeats the link state: + hidden. A port without link is muted throughout */ .ifacebox:has(> .ifacebox-head.cbi-tooltip-container) > .ifacebox-head:first-child { display: flex; align-items: center; gap: 8px; padding: 10px 10px 2px; background: none; border-bottom: 0; - font-family: var(--mono); font-weight: 650 !important; text-align: left; + font-family: var(--mono); font-weight: 600 !important; text-align: left; } .ifacebox:has(> .ifacebox-head.cbi-tooltip-container) > .ifacebox-head:first-child::before { content: ""; flex: none; @@ -1937,7 +1973,7 @@ div:has(> .ifacebox > .ifacebox-head.cbi-tooltip-container) > .ifacebox { width: box-shadow: inset 0 0 0 1.5px var(--text-3); } .ifacebox:has(> .ifacebox-body > img[src$="_down.svg"]) > .ifacebox-head:first-child { color: var(--text-2); } -.ifacebox:has(> .ifacebox-body > img[src$="_up.svg"]) > .ifacebox-head:first-child::before { background: var(--v-chart-1); box-shadow: 0 0 0 3px var(--accent-soft); } +.ifacebox:has(> .ifacebox-body > img[src$="_up.svg"]) > .ifacebox-head:first-child::before { content: none; } .ifacebox:has(> .ifacebox-head.cbi-tooltip-container) > .ifacebox-head:first-child + .ifacebox-body { padding: 2px 10px 6px; color: var(--text-3); } .ifacebox:has(> .ifacebox-body > img[src$="_up.svg"]) > .ifacebox-head:first-child + .ifacebox-body { color: var(--text-2); } .ifacebox:has(> .ifacebox-head.cbi-tooltip-container) > .ifacebox-head:first-child + .ifacebox-body > :is(img, br) { display: none; } @@ -1948,7 +1984,7 @@ div:has(> .ifacebox > .ifacebox-head.cbi-tooltip-container) > .ifacebox { width: .ifacebox-head.cbi-tooltip-container:has(> .zonebadge) { gap: 3px; padding: 4px 10px; background: none; border-bottom: 0; } .ifacebox-head.cbi-tooltip-container > .zonebadge[style*="--zone-color-rgb"] { height: 3px !important; padding: 0; - border: 0; border-radius: 2px; box-shadow: none; + border: 0; border-radius: var(--r-xs); box-shadow: none; background-color: rgb(var(--zone-color-rgb)) !important; } .ifacebox-head.cbi-tooltip-container > .zonebadge:is([style*="--zone-color-rgb: 238, 238, 238"], [style*="--zone-color-rgb:238, 238, 238"], [style*="--zone-color-rgb:238,238,238"]) { background-color: var(--text-3) !important; } @@ -1968,13 +2004,15 @@ div:has(> .ifacebox > .ifacebox-head.cbi-tooltip-container) > .ifacebox { width: color: var(--text) !important; font-size: var(--fs-md); text-align: left; } -.network-status-table .ifacebox-head strong { font-weight: 650; font-family: var(--mono); letter-spacing: -.01em; } +.network-status-table .ifacebox-head strong { font-weight: 600; font-family: var(--mono); letter-spacing: -.01em; } +/* up is the normal case and draws nothing; a box that is down (an + upstream not connected, a radio off) gets a hollow ring */ .network-status-table .ifacebox-head::before { content: ""; flex: none; width: 8px; height: 8px; border-radius: 50%; - background: var(--text-3); + box-shadow: inset 0 0 0 1.5px var(--text-3); } -.network-status-table .ifacebox-head.active::before { background: var(--accent-text); box-shadow: 0 0 0 3px var(--accent-soft); } +.network-status-table .ifacebox-head.active::before { content: none; } .network-status-table .ifacebox-head[data-v-band]::after { content: attr(data-v-band); margin-left: auto; @@ -2038,34 +2076,6 @@ div:has(> .ifacebox > .ifacebox-head.cbi-tooltip-container) > .ifacebox { width: .zone-forwards { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; } .zone-forwards > span { color: var(--text-3); } -/* progress bar: text only exists in title */ -.cbi-progressbar { - position: relative; - width: 100%; max-width: 520px; - height: 22px; - background: var(--s2); - border: 1px solid var(--line); - border-radius: var(--r-sm); - overflow: hidden; -} -.cbi-progressbar > div { - height: 100%; - width: 0; - background: linear-gradient(90deg, color-mix(in srgb, var(--accent-text) 22%, transparent), color-mix(in srgb, var(--accent-text) 48%, transparent)); - transition: width .3s ease-out; -} -.cbi-progressbar::before { - content: attr(title); - position: absolute; inset: 0; - display: flex; align-items: center; - padding: 0 8px; - color: var(--text); - font: 500 var(--fs-micro)/1 var(--mono); - font-variant-numeric: tabular-nums; - white-space: nowrap; - z-index: 1; -} - /* notifications */ .alert-message { position: relative; @@ -2128,7 +2138,7 @@ div:has(> .ifacebox > .ifacebox-head.cbi-tooltip-container) > .ifacebox { width: pointer-events: none; } .cbi-tooltip.error { background: var(--err); border-color: var(--err); color: var(--err-ink); } -.cbi-tooltip.warning { background: var(--warn); border-color: var(--warn); color: #1a1200; } +.cbi-tooltip.warning { background: var(--warn); border-color: var(--warn); color: var(--warn-ink); } .cbi-tooltip.info { background: var(--info); border-color: var(--info); color: var(--info-ink); } .cbi-tooltip-container { position: relative; cursor: help; } /* sized to its text, not to a narrow container such as a 100 px port box */ @@ -2280,7 +2290,7 @@ body.modal-overlay-active #modal_overlay { display: block; } .uci-change-legend-label > :is(ins, del, var) { display: inline-flex; flex: none; width: 14px; height: 14px; padding: 0; - border: 1px solid; border-radius: 3px; + border: 1px solid; border-radius: var(--r-xs); font-size: 0; overflow: hidden; text-decoration: none; font-style: normal; } @@ -2429,7 +2439,7 @@ body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border- } body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border-bottom"]) > .tr > .td:nth-child(1) strong::before { content: ""; flex: none; - width: 14px; height: 3px; border-radius: 2px; + width: 14px; height: 3px; border-radius: var(--r-xs); background: var(--key); } body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border-bottom"]) > .tr > .td:is(:nth-child(3), :nth-child(5)) strong { @@ -2442,7 +2452,7 @@ body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border- white-space: nowrap; } body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border-bottom"]) > .tr > .td:is(:nth-child(2), :nth-child(4), :nth-child(6))::first-line { color: var(--v-text-2); font-size: var(--fs-sm); } -body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border-bottom"]) > .tr > .td:nth-child(2)::first-line { color: var(--v-text); font-weight: 650; font-size: var(--fs-md); } +body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border-bottom"]) > .tr > .td:nth-child(2)::first-line { color: var(--v-text); font-weight: 600; font-size: var(--fs-md); } body[data-page^="admin-status-realtime"] #view .tr:has(:is(#lb_load01_cur, #rx_bw_cur, #rssi_bw_cur, #lb_udp_cur)) { --key: var(--v-chart-1); } body[data-page^="admin-status-realtime"] #view .tr:has(:is(#lb_load05_cur, #tx_bw_cur, #rate_bw_cur, #lb_tcp_cur)) { --key: var(--v-chart-2); } body[data-page^="admin-status-realtime"] #view .tr:has(:is(#lb_load15_cur, #noise_bw_cur, #lb_otr_cur)) { --key: var(--v-chart-3); } @@ -2519,7 +2529,7 @@ body[data-page^="admin-status-channel_analysis"] #view [data-tab-title]:not([dat paint-order: stroke; stroke: var(--s1); stroke-width: 3px; stroke-linejoin: round; } -#view div[id="channel_graph"] svg text.v-ca-label[data-v-own] { fill: var(--v-accent) !important; font-weight: 650 !important; } +#view div[id="channel_graph"] svg text.v-ca-label[data-v-own] { fill: var(--v-accent) !important; font-weight: 600 !important; } #view span[data-v-series] { font-size: .75em; vertical-align: 1px; color: var(--v-chart-2) !important; } #view span[data-v-series="1"] { color: var(--v-chart-1) !important; } #view span[data-v-series="3"] { color: var(--v-chart-3) !important; } @@ -2549,16 +2559,10 @@ body[data-page^="admin-status-channel_analysis"] #view [data-tab-title]:not([dat .vt-login-page { display: flex; align-items: center; justify-content: center; padding: var(--sp-4); - background: - radial-gradient(1200px 600px at 50% -10%, color-mix(in srgb, var(--accent) 6%, transparent), transparent 60%), - linear-gradient(var(--line) 1px, transparent 1px) 0 0 / 32px 32px, - linear-gradient(90deg, var(--line) 1px, transparent 1px) 0 0 / 32px 32px, - var(--bg); - background-blend-mode: normal; } html[data-darkmode="true"] .vt-login-page { background: - radial-gradient(900px 520px at 50% 0%, rgba(200, 240, 49, .06), transparent 60%), + radial-gradient(900px 520px at 50% 0%, color-mix(in srgb, var(--accent) 6%, transparent), transparent 60%), linear-gradient(rgba(255, 255, 255, .025) 1px, transparent 1px) 0 0 / 32px 32px, linear-gradient(90deg, rgba(255, 255, 255, .025) 1px, transparent 1px) 0 0 / 32px 32px, var(--bg); @@ -2569,7 +2573,7 @@ html:not([data-darkmode="true"]) .vt-login-page { linear-gradient(90deg, rgba(20, 23, 26, .04) 1px, transparent 1px) 0 0 / 32px 32px, var(--bg); } -/* the starfield (login.js), between the grid and the card */ +/* the backdrop (login.js: packets or starfield), between the grid and the card */ .vt-login-sky { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; } .vt-login { position: relative; width: min(380px, 100%); @@ -2599,19 +2603,7 @@ html:not([data-darkmode="true"]) .vt-login-page::before { } .vt-login-head { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-6); } .vt-login-mark { flex: none; } -.vt-login-title { margin: 0; font-size: var(--fs-lg); font-family: var(--mono); font-weight: 600; letter-spacing: -.01em; overflow-wrap: anywhere; } -.vt-login-sub { - display: flex; align-items: center; gap: 6px; - margin: 2px 0 0; - color: var(--text-3); - font-size: var(--fs-micro); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; -} -.vt-login-sub { isolation: isolate; } -/* the ring as on the poll pill: behind the dot (the dot itself makes no - stacking context, so z-index -1 lands under its background), opacity 0 - unless animated */ -.vt-login-dot { position: relative; width: 6px; height: 6px; border-radius: 50%; background: var(--accent-text); } -.vt-login-dot::after { content: ""; position: absolute; z-index: -1; inset: 0; border-radius: 50%; background: var(--accent-line); opacity: 0; animation: vt-live 2s ease-out infinite; } +.vt-login-title { margin: 0; font-size: var(--fs-lg); font-weight: 600; letter-spacing: -.01em; overflow-wrap: anywhere; } .vt-login-error { margin: 0 0 var(--sp-4); padding: var(--sp-2) var(--sp-3); @@ -2635,7 +2627,6 @@ html:not([data-darkmode="true"]) .vt-login-page::before { } .vt-field input[name="luci_username"] { font-family: var(--mono); } .vt-login-submit { height: var(--ctl-h); margin-top: var(--sp-2); font-size: var(--fs-md) !important; width: 100%; } -.vt-login-foot { margin: var(--sp-4) 0 0; text-align: center; color: var(--text-3); font: var(--fs-micro)/1.4 var(--mono); letter-spacing: .03em; } /* ------------------------------------------------ 9. stock page layouts */ @@ -2683,7 +2674,7 @@ body[data-page="admin-statistics-graphs"] p.controls > .nowrap > .cbi-button { m } [id$="-ifc-description"] > .nowrap > strong, .td[data-name="_stat"] .nowrap > strong { color: var(--text-3); - font: 600 var(--fs-micro)/1.5 var(--font); letter-spacing: .06em; text-transform: uppercase; + font: 600 var(--fs-micro)/1.5 var(--font); letter-spacing: .08em; text-transform: uppercase; } /* Network -> Wireless: radios as group headers, networks as rows */ @@ -2702,21 +2693,27 @@ body[data-page="admin-statistics-graphs"] p.controls > .nowrap > .cbi-button { m .cbi-section-table-row:has(> .td[data-name="_stat"] big):first-child > .td { border-top: 0; } .cbi-section-table-row:not(:has(big)) > .td[data-name="_badge"] { padding-left: calc(var(--card-px) + 16px); } -/* progress bars: thin track, value text above it and in flow, so larger - browser fonts cannot run into the heading */ +/* progress bars (their text only exists in title): a thin track, the + value text above it and in flow, so larger browser fonts cannot run + into the heading */ .cbi-progressbar { + position: relative; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 6px; gap: 5px; - height: auto; margin: 0 0 2px; - background: none; - border: 0; border-radius: 3px; - overflow: visible; + width: 100%; max-width: 520px; + margin: 0 0 2px; +} +.cbi-progressbar > div { + grid-area: 2 / 1; z-index: 1; + width: 0; height: 6px; + border-radius: 3px; + background: var(--accent-text); + transition: width .3s ease-out; } -.cbi-progressbar > div { grid-area: 2 / 1; height: 6px; z-index: 1; border-radius: 3px; background: var(--accent-text); } .cbi-progressbar::before { - position: static; inset: auto; padding: 0; + content: attr(title); display: block; color: var(--text-2); font: 500 var(--fs-micro)/1.2 var(--mono); @@ -2729,8 +2726,9 @@ body[data-page="admin-statistics-graphs"] p.controls > .nowrap > .cbi-button { m .v-meter { display: grid; gap: 10px; padding: 4px 0 6px; } .v-meter + .v-meter { margin-top: var(--sp-3); padding-top: var(--sp-4); border-top: 1px solid var(--line); } .v-meter-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; } -.v-meter-title { color: var(--text); font-weight: 600; } -.v-meter-big { font: 650 var(--fs-xl)/1 var(--mono); letter-spacing: -.02em; color: var(--text); } +/* the meter's figures, as the dashboard's: the share in tabular sans, the + amounts in monospace */ +.v-meter-big { font: 700 var(--fs-xl)/1 var(--font); font-variant-numeric: tabular-nums; letter-spacing: -.02em; color: var(--text); } .v-meter-big small { margin-left: 6px; font: 500 var(--fs-sm) var(--font); letter-spacing: 0; color: var(--text-2); } .v-meter-sub { margin-left: auto; color: var(--text-2); font: var(--fs-sm)/1.4 var(--mono); font-variant-numeric: tabular-nums; } .v-meter-bar { @@ -2738,18 +2736,19 @@ body[data-page="admin-statistics-graphs"] p.controls > .nowrap > .cbi-button { m display: flex; height: 12px; background: var(--s3); - border-radius: 3px; + border-radius: var(--r-xs); overflow: hidden; box-shadow: inset 0 0 0 1px var(--line); } .v-meter-bar.is-thin { height: 6px; } .v-seg { height: 100%; flex: none; transition: width .4s ease-out; } .v-seg + .v-seg { box-shadow: inset 1px 0 0 var(--s1); } -.v-seg-used { background: var(--v-accent); } +/* blue, as the dashboard's meters: lime there means download */ +.v-seg-used { background: var(--v-meter); } .v-seg-cache { background: repeating-linear-gradient(-45deg, - color-mix(in srgb, var(--v-accent) 55%, transparent) 0 3px, - color-mix(in srgb, var(--v-accent) 25%, transparent) 3px 6px); + color-mix(in srgb, var(--v-meter) 55%, transparent) 0 3px, + color-mix(in srgb, var(--v-meter) 25%, transparent) 3px 6px); } .v-seg.is-warn { background: var(--warn); } .v-seg.is-crit { background: var(--err); } @@ -2757,7 +2756,7 @@ body[data-page="admin-statistics-graphs"] p.controls > .nowrap > .cbi-button { m .v-meter-legend li { display: inline-flex; align-items: center; gap: 7px; } .v-meter-legend b { color: var(--text); font: 600 var(--fs-sm) var(--mono); font-variant-numeric: tabular-nums; } .v-meter-legend em { color: var(--text-3); font-style: normal; font-size: var(--fs-micro); } -.v-key { width: 10px; height: 10px; border-radius: 2px; flex: none; } +.v-key { width: 10px; height: 10px; border-radius: var(--r-xs); flex: none; } .v-key.v-seg-free { background: var(--s3); box-shadow: inset 0 0 0 1px var(--line-2); } .v-meter-rows { display: grid; grid-template-columns: minmax(120px, max-content) minmax(0, 1fr) max-content; gap: 14px 20px; padding: 4px 0 6px; } .v-meter-row { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; grid-template-areas: "label bar val"; align-items: center; } @@ -2766,7 +2765,6 @@ body[data-page="admin-statistics-graphs"] p.controls > .nowrap > .cbi-button { m .v-meter-row > .v-meter-bar { grid-area: bar; } .v-meter-row > .v-meter-val { grid-area: val; color: var(--text-2); font: var(--fs-sm) var(--mono); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; } .v-meter-row > .v-meter-val b { color: var(--text); font-weight: 600; } -.v-sr { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; } /* Share the widest table's intrinsic width with its headings and dividers. */ @media (width > 720px) { @@ -2876,16 +2874,16 @@ html[data-darkmode="true"] :is(#ban-status, #ban-report) { --ban-ok: #63c79b; -- } .zone-forwards :is(.zone-src, .zone-dest) { display: inline-flex; flex-wrap: wrap; gap: 6px; } .zonebadge.zonebadge-empty { background: transparent !important; border-style: dashed; color: var(--text-2) !important; box-shadow: none; } -/* zone and default policies: reject and drop in red, accept in green */ -select[id^="widget.cbid.firewall."]:has(> option:checked:is([value="REJECT"], [value="DROP"])) { color: var(--err); font-weight: 600; } -select[id^="widget.cbid.firewall."]:has(> option:checked[value="ACCEPT"]) { color: var(--ok-text); font-weight: 600; } -select[id^="widget.cbid.firewall."] > option { color: var(--text); font-weight: 400; } -/* except where accept is the risk: the masquerading (internet-facing) - zone accepting input, or forwarding into another zone. Green says - "passes", not "safe"; these two get the warning colour instead. */ +/* zone and default policies stay plain: reject and drop are the safe + values, accept between your own zones is normal (as on the Overview + tab). The one policy that is a risk is coloured: the masquerading + (internet-facing) zone accepting input, in the error colours the + Overview tab gives it. Forwarding from it into another zone is + outlined in the warning colour. */ #cbi-firewall-zone .tr:has(input[data-widget-id$=".masq"]:checked) > .td[data-name="input"] select:has(> option:checked[value="ACCEPT"]) { - color: var(--warn-text); border-color: var(--warn); background-color: var(--warn-soft); + color: var(--err-text); border-color: var(--err); background-color: var(--err-soft); font-weight: 600; } +#cbi-firewall-zone .tr:has(input[data-widget-id$=".masq"]:checked) > .td[data-name="input"] select:has(> option:checked[value="ACCEPT"]) > option { color: var(--text); font-weight: 400; } #cbi-firewall-zone .tr:has(input[data-widget-id$=".masq"]:checked) .zone-dest > .zonebadge:not(.zonebadge-empty) { outline: 2px solid var(--warn); outline-offset: 1px; } @@ -3083,7 +3081,7 @@ select[id^="widget.cbid.firewall."] > option { color: var(--text); font-weight: .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-n { width: 10px; height: 10px; margin: 4px 5px; border-radius: var(--r-xs); 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; } @@ -3212,17 +3210,26 @@ body[data-page="admin-system-filemanager"] .sort-button { border-color: var(--li @media (max-width: 900px) { .vt-host { display: none !important; } - /* indicators go compact (dot, count) before the crumbs get cut; the - label stays as text for screen readers and as the title */ + /* indicators go compact (a sign, a count) before the crumbs get cut; + the label stays as text for screen readers and as the title */ #indicators > span[data-indicator] { height: 28px; padding: 0 8px; } #indicators > span[data-indicator="poll-status"] { font-size: 0; gap: 0; width: 28px; justify-content: center; padding: 0; } - #indicators > span[data-indicator="poll-status"][data-style="active"]::after { left: calc(50% - 3.5px); } + /* without its label the pill is the pause / resume button: a pause + sign while it refreshes, a play sign while paused */ + #indicators > span[data-indicator="poll-status"][data-style="active"]::before { + width: 8px; height: 10px; border-radius: 0; + background: none; border-inline: 3px solid currentColor; + } + #indicators > span[data-indicator="poll-status"][data-style="inactive"]::before { + width: 0; height: 0; margin-left: 2px; border-radius: 0; + background: none; border-left: 9px solid currentColor; border-block: 5px solid transparent; + } #indicators > span[data-indicator][data-count] { padding: 0 3px; gap: 0; } #indicators > span[data-indicator][data-count]::before { content: none; } html[data-rail="pinned"] .vt-rail { width: var(--rail-w); } html[data-rail="pinned"] .vt-frame { margin-left: var(--rail-w); } html[data-rail="pinned"] body.vt-auth .vt-shell::before { width: var(--rail-w); } - html[data-rail="pinned"] .vt-brand-word, html[data-rail="pinned"] .vt-rail-label, + html[data-rail="pinned"] .vt-rail-label, html[data-rail="pinned"] .vt-rail-caret, html[data-rail="pinned"] .vt-rail-sub { display: none !important; } .vt-rail-pin { display: none; } } @@ -3289,7 +3296,6 @@ body[data-page="admin-system-filemanager"] .sort-button { border-color: var(--li } .vt-fly-link { min-height: 44px; font-size: var(--fs-md); } .vt-fly-sub a { padding: 8px 12px; font-size: var(--fs-base); } - .vt-fly-foot { display: none; } @keyframes vt-sheet-in { from { transform: translateY(16px); opacity: 0; } to { transform: none; opacity: 1; } } .vt-topbar { gap: var(--sp-2); padding: 0 var(--sp-3) 0 var(--sp-4); } @@ -3475,7 +3481,7 @@ body[data-page="admin-system-filemanager"] .sort-button { border-color: var(--li /* short row buttons (Processes' Kill) at least as wide as they are high */ .td.cbi-section-actions :is(.btn, .cbi-button):not(.drag-handle) { min-width: var(--ctl-h); } /* dropdown choices (Save & Apply's too) are touch targets */ - .cbi-dropdown[open] > ul.dropdown > li { min-height: var(--ctl-h); } + .cbi-dropdown[open] > ul.dropdown > li, .vt-actmenu-item { min-height: var(--ctl-h); } .cbi-value { padding: 8px 0; } } diff --git a/luci-theme-vantage/po/templates/vantage-theme.pot b/luci-theme-vantage/po/templates/vantage-theme.pot index ba38c80d4..51f2b938a 100644 --- a/luci-theme-vantage/po/templates/vantage-theme.pot +++ b/luci-theme-vantage/po/templates/vantage-theme.pot @@ -13,6 +13,13 @@ msgid_plural "%d more chains at this hook" msgstr[0] "" msgstr[1] "" +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1350 +msgctxt "vantage-theme" +msgid "%d result" +msgid_plural "%d results" +msgstr[0] "" +msgstr[1] "" + #: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:345 msgctxt "vantage-theme" msgid "%d rule" @@ -49,7 +56,7 @@ msgctxt "vantage-theme" msgid "Accept" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1188 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1270 msgid "Actions" msgstr "" @@ -58,21 +65,22 @@ msgctxt "nft match any traffic" msgid "Any packet" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1181 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1182 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1183 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1186 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1439 -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:81 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1258 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1259 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1260 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1263 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1267 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1533 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:84 msgctxt "vantage-theme" msgid "Appearance" msgstr "" -#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:43 +#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:41 msgid "Authorization Required" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1441 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1535 msgctxt "vantage-theme" msgid "Auto" msgstr "" @@ -87,7 +95,7 @@ msgctxt "vantage-theme" msgid "Back to the calling chain" msgstr "" -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:69 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:72 msgctxt "vantage-theme" msgid "Breadcrumb" msgstr "" @@ -105,17 +113,17 @@ msgctxt "vantage-theme" msgid "Bridged between ports" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:338 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:409 msgid "Buffered" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:349 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:359 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:363 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:420 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:430 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:434 msgid "Cache" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:338 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:409 msgid "Cached" msgstr "" @@ -134,19 +142,19 @@ msgctxt "vantage-theme" msgid "Chains no rule jumps to directly" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:419 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:491 msgid "Channel" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:818 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:897 msgid "Collapse navigation" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1440 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1534 msgid "Colour theme" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1212 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1294 msgid "Command palette" msgstr "" @@ -165,7 +173,7 @@ msgctxt "vantage-theme" msgid "Continues in %s, then comes back here" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1441 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1535 msgctxt "vantage-theme" msgid "Dark" msgstr "" @@ -189,8 +197,8 @@ msgstr "" msgid "Egress" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:818 -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:54 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:897 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:57 msgid "Expand navigation" msgstr "" @@ -207,7 +215,7 @@ msgid "" "their counters see only its first packets." msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1183 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1260 msgid "Follow system theme" msgstr "" @@ -225,17 +233,17 @@ msgid "" "if br_netfilter is enabled; the ruleset doesn't show that.)" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:350 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:364 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:421 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:435 msgctxt "vantage-theme" msgid "Free" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1393 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1458 msgid "Grid packets" msgstr "" -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:48 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:52 msgctxt "vantage-theme" msgid "Home" msgstr "" @@ -252,9 +260,9 @@ msgstr "" msgid "IPv6 traffic table \"%h\"" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:349 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:358 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:362 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:420 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:429 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:433 msgctxt "vantage-theme" msgid "In use" msgstr "" @@ -268,11 +276,11 @@ msgctxt "vantage-theme" msgid "Input" msgstr "" -#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:48 +#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:45 msgid "Invalid username and/or password! Please try again." msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1208 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1290 msgid "Jump to a page or action…" msgstr "" @@ -281,27 +289,27 @@ msgctxt "vantage-theme" msgid "Leaves unmatched unchanged" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1441 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1535 msgctxt "vantage-theme" msgid "Light" msgstr "" #: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:23 -#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:60 +#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:57 msgid "Log in" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1187 -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:84 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1269 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:87 msgid "Log out" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1186 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1443 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1263 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1537 msgid "Login background" msgstr "" -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:47 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:51 msgctxt "vantage-theme" msgid "Main navigation" msgstr "" @@ -311,13 +319,13 @@ msgctxt "vantage-theme" msgid "Masquerade" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:333 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:348 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:404 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:419 msgid "Memory" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1713 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1730 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1806 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1823 msgctxt "vantage-theme" msgid "More actions" msgstr "" @@ -335,12 +343,17 @@ msgstr "" msgid "Network device table \"%h\"" msgstr "" +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1267 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1526 +msgid "Network path background" +msgstr "" + #: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:162 msgctxt "vantage-theme" msgid "Next rule" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1283 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1348 msgid "No matching pages" msgstr "" @@ -354,12 +367,17 @@ msgctxt "vantage-theme" msgid "No rules: %s" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1393 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1458 msgctxt "vantage-theme" msgid "None" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1111 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1165 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:17 +msgid "Not found" +msgstr "" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1185 msgid "Other pages in %s" msgstr "" @@ -373,7 +391,7 @@ msgctxt "vantage-theme" msgid "Packet path" msgstr "" -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:90 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:93 msgid "Page tabs" msgstr "" @@ -387,7 +405,7 @@ msgctxt "vantage-theme" msgid "Passes unmatched" msgstr "" -#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:57 +#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:54 msgid "Password" msgstr "" @@ -401,11 +419,6 @@ msgctxt "vantage-theme" msgid "Prerouting" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:985 -msgctxt "vantage-theme" -msgid "Press" -msgstr "" - #: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:158 msgctxt "vantage-theme" msgid "Queue to a program" @@ -421,7 +434,7 @@ msgctxt "vantage-theme" msgid "Reject" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1210 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1292 msgctxt "vantage-theme" msgid "Results" msgstr "" @@ -441,13 +454,13 @@ msgctxt "vantage-theme" msgid "Rules table" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1208 -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:72 -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:74 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1290 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:75 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:77 msgid "Search pages" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1187 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1269 msgid "Session" msgstr "" @@ -458,33 +471,33 @@ msgid_plural "Show %d more rules" msgstr[0] "" msgstr[1] "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1870 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1963 msgid "Show full description" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1859 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1952 msgid "Show full help: %s" msgstr "" -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:44 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:48 msgid "Skip to content" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1393 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1458 msgid "Starfield" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:385 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:456 msgid "Storage" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:371 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:373 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:442 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:444 msgctxt "vantage-theme" msgid "Swap" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:338 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:409 msgid "Swap free" msgstr "" @@ -493,12 +506,12 @@ msgctxt "vantage-theme" msgid "This device" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:350 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:421 msgctxt "vantage-theme" msgid "Total" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:337 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:408 msgid "Total Available" msgstr "" @@ -512,19 +525,19 @@ msgctxt "vantage-theme" msgid "Unchanged" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1181 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1258 msgid "Use dark theme" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1182 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1259 msgid "Use light theme" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:337 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:408 msgid "Used" msgstr "" -#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:53 +#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:50 msgid "Username" msgstr "" @@ -538,16 +551,16 @@ msgctxt "vantage-theme" msgid "View" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:412 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:484 msgid "Wireless" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:354 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:425 msgctxt "vantage-theme" msgid "available" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1218 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1300 msgid "close" msgstr "" @@ -561,17 +574,12 @@ msgctxt "vantage-theme" msgid "drops unmatched %s" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:400 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:403 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:471 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:475 msgid "free" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1285 -msgctxt "vantage-theme" -msgid "items" -msgstr "" - -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1216 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1298 msgid "navigate" msgstr "" @@ -590,29 +598,19 @@ msgctxt "vantage-theme" msgid "on %s" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1217 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1299 msgctxt "vantage-theme" msgid "open" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:965 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1039 -msgid "page" -msgstr "" - -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:965 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1039 -msgid "pages" -msgstr "" - #: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:340 msgctxt "vantage-theme" msgid "priority %d" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:349 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:359 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:363 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:420 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:430 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:434 msgid "reclaimable" msgstr "" @@ -621,11 +619,12 @@ msgctxt "vantage-theme" msgid "rules drop some" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:985 -msgid "to search all pages" +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:471 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:475 +msgid "total" msgstr "" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:400 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:403 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:471 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:475 msgid "used" msgstr "" diff --git a/luci-theme-vantage/po/zh_Hans/vantage-theme.po b/luci-theme-vantage/po/zh_Hans/vantage-theme.po index f851439c8..349beedd2 100644 --- a/luci-theme-vantage/po/zh_Hans/vantage-theme.po +++ b/luci-theme-vantage/po/zh_Hans/vantage-theme.po @@ -21,6 +21,12 @@ msgid "%d more chain at this hook" msgid_plural "%d more chains at this hook" msgstr[0] "此钩子还有 %d 条链" +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1350 +msgctxt "vantage-theme" +msgid "%d result" +msgid_plural "%d results" +msgstr[0] "%d 个结果" + #: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:345 msgctxt "vantage-theme" msgid "%d rule" @@ -56,7 +62,7 @@ msgctxt "vantage-theme" msgid "Accept" msgstr "接受" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1188 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1270 msgid "Actions" msgstr "操作" @@ -65,21 +71,22 @@ msgctxt "nft match any traffic" msgid "Any packet" msgstr "任意数据包" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1181 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1182 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1183 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1186 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1439 -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:81 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1258 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1259 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1260 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1263 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1267 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1533 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:84 msgctxt "vantage-theme" msgid "Appearance" msgstr "外观" -#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:43 +#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:41 msgid "Authorization Required" msgstr "需要授权" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1441 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1535 msgctxt "vantage-theme" msgid "Auto" msgstr "自动" @@ -94,7 +101,7 @@ msgctxt "vantage-theme" msgid "Back to the calling chain" msgstr "返回调用链" -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:69 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:72 msgctxt "vantage-theme" msgid "Breadcrumb" msgstr "面包屑" @@ -112,17 +119,17 @@ msgctxt "vantage-theme" msgid "Bridged between ports" msgstr "端口间桥接" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:338 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:409 msgid "Buffered" msgstr "已缓冲" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:349 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:359 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:363 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:420 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:430 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:434 msgid "Cache" msgstr "缓存" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:338 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:409 msgid "Cached" msgstr "已缓存" @@ -141,19 +148,19 @@ msgctxt "vantage-theme" msgid "Chains no rule jumps to directly" msgstr "没有规则直接跳转到的链" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:419 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:491 msgid "Channel" msgstr "信道" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:818 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:897 msgid "Collapse navigation" msgstr "收起导航" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1440 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1534 msgid "Colour theme" msgstr "颜色主题" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1212 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1294 msgid "Command palette" msgstr "命令面板" @@ -172,7 +179,7 @@ msgctxt "vantage-theme" msgid "Continues in %s, then comes back here" msgstr "转入 %s,随后返回此处" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1441 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1535 msgctxt "vantage-theme" msgid "Dark" msgstr "深色" @@ -196,8 +203,8 @@ msgstr "丢弃未匹配流量" msgid "Egress" msgstr "出口" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:818 -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:54 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:897 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:57 msgid "Expand navigation" msgstr "展开导航" @@ -216,7 +223,7 @@ msgstr "" "流量卸载已开启:一条转发连接建立后,它的数据包可以跳过 prerouting、forward " "和 postrouting,因此这些链和它们的计数器只会看到该连接最初的数据包。" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1183 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1260 msgid "Follow system theme" msgstr "跟随系统主题" @@ -237,17 +244,17 @@ msgstr "" "达 input、forward 或 output 链,这里也没有桥接链会过滤它们。(启用 " "br_netfilter 时内核可以把它们交给 IP 链;规则集不体现这一点。)" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:350 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:364 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:421 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:435 msgctxt "vantage-theme" msgid "Free" msgstr "空闲" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1393 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1458 msgid "Grid packets" msgstr "网格数据包" -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:48 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:52 msgctxt "vantage-theme" msgid "Home" msgstr "首页" @@ -264,9 +271,9 @@ msgstr "IPv4/IPv6 流量表 \"%h\"" msgid "IPv6 traffic table \"%h\"" msgstr "IPv6 流量表 \"%h\"" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:349 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:358 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:362 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:420 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:429 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:433 msgctxt "vantage-theme" msgid "In use" msgstr "已用" @@ -280,11 +287,11 @@ msgctxt "vantage-theme" msgid "Input" msgstr "输入" -#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:48 +#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:45 msgid "Invalid username and/or password! Please try again." msgstr "用户名或密码错误,请重试。" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1208 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1290 msgid "Jump to a page or action…" msgstr "跳转到页面或操作…" @@ -293,27 +300,27 @@ msgctxt "vantage-theme" msgid "Leaves unmatched unchanged" msgstr "未匹配流量保持原样" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1441 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1535 msgctxt "vantage-theme" msgid "Light" msgstr "浅色" #: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:23 -#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:60 +#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:57 msgid "Log in" msgstr "登录" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1187 -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:84 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1269 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:87 msgid "Log out" msgstr "退出登录" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1186 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1443 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1263 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1537 msgid "Login background" msgstr "登录背景" -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:47 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:51 msgctxt "vantage-theme" msgid "Main navigation" msgstr "主导航" @@ -323,13 +330,13 @@ msgctxt "vantage-theme" msgid "Masquerade" msgstr "伪装(NAT)" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:333 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:348 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:404 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:419 msgid "Memory" msgstr "内存" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1713 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1730 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1806 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1823 msgctxt "vantage-theme" msgid "More actions" msgstr "更多操作" @@ -347,12 +354,17 @@ msgstr "网络" msgid "Network device table \"%h\"" msgstr "网络设备表 \"%h\"" +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1267 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1526 +msgid "Network path background" +msgstr "网络路径背景" + #: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:162 msgctxt "vantage-theme" msgid "Next rule" msgstr "下一条规则" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1283 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1348 msgid "No matching pages" msgstr "没有匹配的页面" @@ -366,12 +378,17 @@ msgctxt "vantage-theme" msgid "No rules: %s" msgstr "无规则:%s" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1393 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1458 msgctxt "vantage-theme" msgid "None" msgstr "无" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1111 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1165 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:17 +msgid "Not found" +msgstr "未找到" + +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1185 msgid "Other pages in %s" msgstr "%s 中的其他页面" @@ -385,7 +402,7 @@ msgctxt "vantage-theme" msgid "Packet path" msgstr "数据包路径" -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:90 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:93 msgid "Page tabs" msgstr "页面标签页" @@ -399,7 +416,7 @@ msgctxt "vantage-theme" msgid "Passes unmatched" msgstr "放行未匹配流量" -#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:57 +#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:54 msgid "Password" msgstr "密码" @@ -413,11 +430,6 @@ msgctxt "vantage-theme" msgid "Prerouting" msgstr "路由前" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:985 -msgctxt "vantage-theme" -msgid "Press" -msgstr "按" - #: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:158 msgctxt "vantage-theme" msgid "Queue to a program" @@ -433,7 +445,7 @@ msgctxt "vantage-theme" msgid "Reject" msgstr "拒绝" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1210 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1292 msgctxt "vantage-theme" msgid "Results" msgstr "结果" @@ -453,13 +465,13 @@ msgctxt "vantage-theme" msgid "Rules table" msgstr "规则表" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1208 -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:72 -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:74 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1290 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:75 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:77 msgid "Search pages" msgstr "搜索页面" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1187 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1269 msgid "Session" msgstr "会话" @@ -469,33 +481,33 @@ msgid "Show %d more rule" msgid_plural "Show %d more rules" msgstr[0] "再显示 %d 条规则" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1870 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1963 msgid "Show full description" msgstr "显示完整描述" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1859 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1952 msgid "Show full help: %s" msgstr "显示完整帮助:%s" -#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:44 +#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:48 msgid "Skip to content" msgstr "跳至正文" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1393 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1458 msgid "Starfield" msgstr "星空" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:385 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:456 msgid "Storage" msgstr "存储" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:371 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:373 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:442 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:444 msgctxt "vantage-theme" msgid "Swap" msgstr "交换空间" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:338 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:409 msgid "Swap free" msgstr "空闲交换空间" @@ -504,12 +516,12 @@ msgctxt "vantage-theme" msgid "This device" msgstr "本设备" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:350 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:421 msgctxt "vantage-theme" msgid "Total" msgstr "总计" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:337 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:408 msgid "Total Available" msgstr "总可用" @@ -523,19 +535,19 @@ msgctxt "vantage-theme" msgid "Unchanged" msgstr "不变" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1181 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1258 msgid "Use dark theme" msgstr "使用深色主题" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1182 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1259 msgid "Use light theme" msgstr "使用浅色主题" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:337 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:408 msgid "Used" msgstr "已用" -#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:53 +#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:50 msgid "Username" msgstr "用户名" @@ -549,16 +561,16 @@ msgctxt "vantage-theme" msgid "View" msgstr "视图" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:412 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:484 msgid "Wireless" msgstr "无线" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:354 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:425 msgctxt "vantage-theme" msgid "available" msgstr "可用" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1218 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1300 msgid "close" msgstr "关闭" @@ -572,17 +584,12 @@ msgctxt "vantage-theme" msgid "drops unmatched %s" msgstr "丢弃未匹配的 %s" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:400 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:403 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:471 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:475 msgid "free" msgstr "空闲" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1285 -msgctxt "vantage-theme" -msgid "items" -msgstr "条" - -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1216 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1298 msgid "navigate" msgstr "移动" @@ -601,29 +608,19 @@ msgctxt "vantage-theme" msgid "on %s" msgstr "接口 %s" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1217 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1299 msgctxt "vantage-theme" msgid "open" msgstr "打开" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:965 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1039 -msgid "page" -msgstr "页" - -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:965 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1039 -msgid "pages" -msgstr "页" - #: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:340 msgctxt "vantage-theme" msgid "priority %d" msgstr "优先级 %d" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:349 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:359 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:363 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:420 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:430 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:434 msgid "reclaimable" msgstr "可回收" @@ -632,15 +629,33 @@ msgctxt "vantage-theme" msgid "rules drop some" msgstr "部分规则会丢弃" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:985 -msgid "to search all pages" -msgstr "搜索所有页面" +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:471 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:475 +msgid "total" +msgstr "总计" -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:400 -#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:403 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:471 +#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:475 msgid "used" msgstr "已用" +#~ msgctxt "vantage-theme" +#~ msgid "Press" +#~ msgstr "按" + +#~ msgctxt "vantage-theme" +#~ msgid "items" +#~ msgstr "条" + +#~ msgid "page" +#~ msgstr "页" + +#~ msgid "pages" +#~ msgstr "页" + +#~ msgid "to search all pages" +#~ msgstr "搜索所有页面" + #~ msgid "Show full help" #~ msgstr "显示完整帮助" diff --git a/luci-theme-vantage/ucode/template/themes/vantage/header.ut b/luci-theme-vantage/ucode/template/themes/vantage/header.ut index bd554baf4..aa56c23f4 100644 --- a/luci-theme-vantage/ucode/template/themes/vantage/header.ut +++ b/luci-theme-vantage/ucode/template/themes/vantage/header.ut @@ -10,7 +10,11 @@ -#} {% const authed = !!ctx.authsession; - const page_title = (authed && dispatched?.title) ? striptags(_(dispatched.title)) : 'LuCI'; + /* LuCI renders its 404 with the deepest node it resolved: a category + (firstchild) or a node without an action, whose title is not the + page asked for. Visitors who are not logged in get no title at all. */ + const found = !!dispatched?.action?.type && dispatched.action.type != 'firstchild'; + const page_title = !authed ? null : !found ? _('Not found') : dispatched?.title ? striptags(_(dispatched.title)) : null; const lang = entityencode(dispatcher.lang ?? 'en', true); const boardinfo = ubus.call("system", "board"); const hostname = striptags(boardinfo?.hostname ?? '?'); @@ -21,7 +25,7 @@ -{{ entityencode(page_title, true) }} · LuCI +{{ page_title ? entityencode(page_title, true) + ' · ' : '' }}LuCI