diff --git a/luci-app-fwlive/Makefile b/luci-app-fwlive/Makefile index bb3df9d3a..24148e685 100644 --- a/luci-app-fwlive/Makefile +++ b/luci-app-fwlive/Makefile @@ -12,7 +12,7 @@ LUCI_DEPENDS:=+luci-base +logd +jsonfilter LUCI_PKGARCH:=all PKG_VERSION:=0.1.52 -PKG_RELEASE:=63 +PKG_RELEASE:=64 # Reproducible build: honor SOURCE_DATE_EPOCH from the build environment (set by docker-sdk.sh / CI). ifdef SOURCE_DATE_EPOCH diff --git a/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js b/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js index ed05d8120..b18e06d70 100644 --- a/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js +++ b/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js @@ -2932,8 +2932,6 @@ return view.extend({ this.hostnameCache = new Map(); this.hostnameFailed = new Map(); this.resolveGeneration = 0; - this.lastPollError = false; - this.lastPollErrorCode = null; this.applyHash(); this.attachHandlers(); this.applyRowTintMode(); diff --git a/luci-app-fwlive/root/usr/libexec/fwlive-logging.sh b/luci-app-fwlive/root/usr/libexec/fwlive-logging.sh index be8292014..f6ef8e201 100755 --- a/luci-app-fwlive/root/usr/libexec/fwlive-logging.sh +++ b/luci-app-fwlive/root/usr/libexec/fwlive-logging.sh @@ -394,6 +394,10 @@ wan_firewall_zone_same() { wan_log_staged_line_section() { _line="$1" case "$_line" in + firewall.*.log+=*|firewall.*.log-=*) + _rest=${_line#firewall.} + printf '%s' "${_rest%%.log*}" + ;; firewall.*.log=*) _rest=${_line#firewall.} printf '%s' "${_rest%%.log=*}" @@ -467,6 +471,8 @@ wan_log_count_our_staged_lines() { if (id[i] == "") continue np++ p[np] = "firewall." id[i] ".log=" + la[np] = "firewall." id[i] ".log+=" + ld[np] = "firewall." id[i] ".log-=" d[np] = "-firewall." id[i] ".log" ds[np] = "- firewall." id[i] ".log" } @@ -474,7 +480,7 @@ wan_log_count_our_staged_lines() { NF == 0 { next } { for (i = 1; i <= np; i++) { - if (index($0, p[i]) == 1) { c++; break } + if (index($0, p[i]) == 1 || index($0, la[i]) == 1 || index($0, ld[i]) == 1) { c++; break } if ($0 == d[i] || $0 == ds[i]) { c++; break } } } @@ -482,6 +488,83 @@ wan_log_count_our_staged_lines() { ' } +# Revert only a single staged log delta that still has the value this call +# requested. Repeated or changed same-option entries may belong to a competing +# UCI writer; preserve them rather than reverting an indistinguishable edit. +wan_log_staged_option_matches_target() { + _zone="$1" + _target="$2" + _staged="$3" + _ids=$(wan_log_staged_zone_ids "$_zone" "$_staged") + printf '%s\n' "$_staged" | awk -v ids="$_ids" -v target="$_target" ' + BEGIN { + n = split(ids, id, "\n") + for (i = 1; i <= n; i++) { + if (id[i] == "") continue + p[i] = "firewall." id[i] ".log=" + la[i] = "firewall." id[i] ".log+=" + ld[i] = "firewall." id[i] ".log-=" + d[i] = "-firewall." id[i] ".log" + ds[i] = "- firewall." id[i] ".log" + } + } + NF == 0 { next } + { + for (i = 1; i <= n; i++) { + if (p[i] != "" && index($0, p[i]) == 1) { + count++ + value = substr($0, length(p[i]) + 1) + if (value == target || value == sprintf("%c%s%c", 39, target, 39)) matched = 1 + break + } + if (index($0, la[i]) == 1 || index($0, ld[i]) == 1) { + count++ + break + } + if ($0 == d[i] || $0 == ds[i]) { + count++ + if (target == "") matched = 1 + break + } + } + } + END { exit !(count == 1 && matched) } + ' +} + +wan_log_revert_staged_option_if_ours() { + _zone="$1" + _target="$2" + _staged="$3" + if ! _before_revert=$(uci -q changes firewall 2>/dev/null); then + logger -t fwlive "WAN log option-scoped revert could not re-read staged changes" 2>/dev/null || true + return 1 + fi + if [ "$_before_revert" != "$_staged" ] \ + || ! wan_log_staged_option_matches_target "$_zone" "$_target" "$_before_revert"; then + logger -t fwlive "WAN log option-scoped revert skipped: staged changes changed before cleanup" 2>/dev/null || true + return 1 + fi + # UCI's CLI has no atomic compare-and-revert: a non-cooperating writer + # can still stage the same option after this read and before revert (tracked separately). + uci -q revert "firewall.${_zone}.log" 2>/dev/null || { + logger -t fwlive "WAN log option-scoped revert failed for firewall.${_zone}.log" 2>/dev/null || true + return 1 + } + # OpenWrt 24.10/25.12 UCI can return success even when its internal + # revert operation fails. Confirm through a fresh delta read that no log + # option changes remain before reporting cleanup success. + if ! _after_revert=$(uci -q changes firewall 2>/dev/null); then + logger -t fwlive "WAN log option-scoped revert could not be verified" 2>/dev/null || true + return 1 + fi + if [ "$(wan_log_count_our_staged_lines "$_zone" "$_after_revert")" -ne 0 ]; then + logger -t fwlive "WAN log option-scoped revert left a staged delta" 2>/dev/null || true + return 1 + fi + return 0 +} + wan_log_baseline_path() { printf '%s' "$WAN_LOG_BASELINE_FILE" } @@ -852,8 +935,8 @@ restore_wan_zone_log() { } # Capture the committed value before staging our rollback. If another # writer stages a firewall delta after this point, the post-stage guard - # below must be able to undo only our rollback staging without reverting - # the other writer's change. + # may revert our option only when its staged log delta is still uniquely + # identifiable; otherwise it preserves the ambiguous same-option change. committed=$(wan_zone_log_value "$zone") # Fail closed if set/delete never staged. Swallowed rc plus an empty # changes list would make `uci commit` succeed as a no-op. @@ -868,25 +951,21 @@ restore_wan_zone_log() { fi _staged=$(uci -q changes firewall 2>/dev/null || true) _foreign=$(wan_log_foreign_staged_lines "$zone" "$_staged") - if [ -n "$_foreign" ]; then - if [ -z "$committed" ]; then - uci delete "firewall.${zone}.log" 2>/dev/null || true - else - uci set "firewall.${zone}.log=${committed}" 2>/dev/null || true + _our_count=$(wan_log_count_our_staged_lines "$zone" "$_staged") + if [ -n "$_foreign" ] || [ "$_our_count" -ne 1 ] \ + || ! wan_log_staged_option_matches_target "$zone" "$previous" "$_staged"; then + if ! wan_log_revert_staged_option_if_ours "$zone" "$previous" "$_staged"; then + logger -t fwlive "WAN log rollback left staged log option after foreign or ambiguous change" 2>/dev/null || true fi logger -t fwlive "WAN log rollback skipped after stage: firewall changes staged by another writer" 2>/dev/null || true return 1 fi if ! uci commit firewall 2>/dev/null; then - # Drop our staged rollback delta so a later toggle is not stuck - # on firewall_changes_pending from this package's own orphaned - # write. Mirror commit_wan_log_change: revert only when the - # remaining staging is entirely our log option. + # Remove only a uniquely identifiable staged rollback option. A + # config-wide revert could discard unrelated or competing UCI writes. _staged=$(uci -q changes firewall 2>/dev/null || true) - _total=$(printf '%s\n' "$_staged" | grep -c . 2>/dev/null || true) - _ours=$(wan_log_count_our_staged_lines "$zone" "$_staged") - if [ "${_total:-0}" -gt 0 ] && [ "${_total:-0}" -eq "${_ours:-0}" ]; then - uci -q revert firewall 2>/dev/null || true + if ! wan_log_revert_staged_option_if_ours "$zone" "$previous" "$_staged"; then + logger -t fwlive "WAN log rollback cleanup failed; staged option may remain" 2>/dev/null || true fi return 1 fi @@ -902,8 +981,8 @@ restore_wan_zone_log() { # Staging and committing therefore live INSIDE this function, gated by: # 1. a pending re-check BEFORE our own delta exists in staging (foreign-only); # 2. a post-stage re-check AFTER our set/delete: if anything besides our -# log option is staged, undo our staging (restore the pre-stage committed -# value) and abort without commit — foreign staging stays intact. +# log option is staged, revert only a single exact log delta and abort; +# preserve ambiguous same-option changes and all foreign staging. # The reload-failure rollback has its own pre/post-stage guard for the same # reason; it must not bypass this invariant merely because it is compensating # for a failed reload. @@ -953,8 +1032,9 @@ commit_wan_log_change() { } WAN_LOG_COMMIT_GENERATION="$_generation" - # Staging is empty here — capture the committed value so a post-stage - # foreign race can undo our delta without `uci revert firewall`. + # Staging is empty here — capture the committed value for verification and + # recovery. A post-stage abort uses option-scoped revert, not a compensating + # set to the old value (which leaves another staged delta in real UCI). previous=$(wan_zone_log_value "$zone") if [ -n "$target" ]; then @@ -969,16 +1049,16 @@ commit_wan_log_change() { fi fi - # Post-stage guard: anything besides our log option is foreign. - # Undo our staging only (set previous / delete to match committed); leave - # foreign deltas untouched and abort without commit. + # Post-stage guard: anything besides our log option is foreign. Revert the + # single expected log delta without touching other options; if the staged + # log state is ambiguous, preserve it rather than discard a same-option edit. _staged=$(uci -q changes firewall 2>/dev/null || true) _foreign=$(wan_log_foreign_staged_lines "$zone" "$_staged") - if [ -n "$_foreign" ]; then - if [ -z "$previous" ]; then - uci delete "firewall.${zone}.log" 2>/dev/null || true - else - uci set "firewall.${zone}.log=${previous}" 2>/dev/null || true + _our_count=$(wan_log_count_our_staged_lines "$zone" "$_staged") + if [ -n "$_foreign" ] || [ "$_our_count" -ne 1 ] \ + || ! wan_log_staged_option_matches_target "$zone" "$target" "$_staged"; then + if ! wan_log_revert_staged_option_if_ours "$zone" "$target" "$_staged"; then + logger -t fwlive "WAN log toggle left staged log option after foreign or ambiguous change" 2>/dev/null || true fi logger -t fwlive "WAN log toggle aborted after stage: firewall changes staged by another writer" 2>/dev/null || true wan_log_error_json "$zone_json" firewall_changes_pending @@ -986,19 +1066,12 @@ commit_wan_log_change() { fi if ! uci commit firewall; then - # Drop our staged log delta so a later toggle is not stuck on - # firewall_changes_pending from this package's own orphaned write — - # but ONLY when nothing foreign is staged: `uci revert firewall` is - # config-wide (uci has no option-level revert), and reverting would - # clobber a concurrent writer's uncommitted delta. With foreign - # staging present, leave it and warn. + # UCI option-scoped revert clears our exact delta without discarding + # unrelated staging. If a competing same-option write makes ownership + # ambiguous, preserve it and leave a diagnostic instead. _staged=$(uci -q changes firewall 2>/dev/null || true) - _total=$(printf '%s\n' "$_staged" | grep -c . 2>/dev/null || true) - _ours=$(wan_log_count_our_staged_lines "$zone" "$_staged") - if [ "${_total:-0}" -gt 0 ] && [ "${_total:-0}" -eq "${_ours:-0}" ]; then - uci -q revert firewall 2>/dev/null || true - else - logger -t fwlive "WAN log commit failed with foreign changes staged — not reverting (uci_commit_failed)" 2>/dev/null || true + if ! wan_log_revert_staged_option_if_ours "$zone" "$target" "$_staged"; then + logger -t fwlive "WAN log commit failed with ambiguous or foreign changes staged — not reverting (uci_commit_failed)" 2>/dev/null || true fi wan_log_error_json "$zone_json" uci_commit_failed return 1 diff --git a/luci-app-netstat/Makefile b/luci-app-netstat/Makefile index a5c7ec862..2d68c1fa8 100644 --- a/luci-app-netstat/Makefile +++ b/luci-app-netstat/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-netstat PKG_VERSION:=1.1.5 -PKG_RELEASE:=3 +PKG_RELEASE:=4 PKG_MAINTAINER:=NoobLK PKG_LICENSE:=GPL-3.0 diff --git a/luci-app-netstat/files/usr/lib/lua/luci/view/netstat/usage.htm b/luci-app-netstat/files/usr/lib/lua/luci/view/netstat/usage.htm index 2c59cfd85..36c09b41d 100644 --- a/luci-app-netstat/files/usr/lib/lua/luci/view/netstat/usage.htm +++ b/luci-app-netstat/files/usr/lib/lua/luci/view/netstat/usage.htm @@ -89,7 +89,37 @@ end local ifaces = get_interfaces() local saved_iface = uci:get("netstats", "@config[0]", "prefer") or "" local saved_mode = uci:get("netstats", "@config[0]", "mode") or "daily" -local cur_iface = http.formvalue("iface") or saved_iface or ifaces[1] or "" + +local function has_db(name) + for _, i in ipairs(ifaces) do if i == name then return true end end + return false +end + +-- Accepts a vnStat netdev name (e.g. "wwan0") or a logical interface name +-- (e.g. "wan") resolved to its l3_device. Returns nil if it has no database. +local function resolve_iface(name) + if not name or name == "" or not name:match("^[%w%-%._]+$") then return nil end + if has_db(name) then return name end + local l3 = sys.exec("ubus call network.interface." .. name .. + " status 2>/dev/null | jsonfilter -e '@.l3_device' 2>/dev/null") or "" + l3 = l3:match("^%s*(.-)%s*$") + if l3 ~= "" and has_db(l3) then return l3 end + return nil +end + +-- Auto detect: the default-route device is the real uplink. +local function default_route_iface() + local out = sys.exec("ip route show default 2>/dev/null") or "" + for dev in out:gmatch("dev%s+(%S+)") do + if has_db(dev) then return dev end + end + return nil +end + +local cur_iface = resolve_iface(http.formvalue("iface")) + or resolve_iface(saved_iface) + or default_route_iface() + or ifaces[1] or "" local view_mode = http.formvalue("mode") or saved_mode if view_mode ~= "daily" and view_mode ~= "monthly" then view_mode = "daily" end diff --git a/luci-app-open-box/Makefile b/luci-app-open-box/Makefile index 11efd4736..16d87a072 100644 --- a/luci-app-open-box/Makefile +++ b/luci-app-open-box/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-open-box -PKG_VERSION:=0.1.313 -PKG_RELEASE:=24 +PKG_VERSION:=0.1.315 +PKG_RELEASE:=25 PKG_MAINTAINER:=liandu2024 PKG_LICENSE:=GPL-3.0-or-later diff --git a/luci-app-vantage/Makefile b/luci-app-vantage/Makefile index 0faf5bb7a..704cee22f 100644 --- a/luci-app-vantage/Makefile +++ b/luci-app-vantage/Makefile @@ -10,8 +10,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-vantage -PKG_VERSION:=1.0.1 -PKG_RELEASE:=7 +PKG_VERSION:=1.0.2 +PKG_RELEASE:=8 PKG_LICENSE:=GPL-3.0-or-later LUCI_TITLE:=Vantage dashboard diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/app.css b/luci-app-vantage/htdocs/luci-static/resources/vantage/app.css index a13d0ffe5..a8d599a28 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/vantage/app.css +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/app.css @@ -277,40 +277,80 @@ html[data-darkmode="true"] .vt-app { /* ------------------------------------------------------------ 3. layout */ -.vt-app .vt-grid { - display: grid; - gap: 14px; - grid-template-columns: minmax(0, 1fr); - grid-template-areas: "clients" "talk" "radios" "hero" "ssids" "chart" "sys"; +/* Tiles are placed by the view (vantage/layout.js): it sets each tile's + column (--c), width in columns (--w) and top (--y), and the grid's + column count (--cols) and height. Widths and columns follow the grid + width here, so only heights wait for script. */ +.vt-app .vt-grid { --vt-gap: 14px; --cols: 1; position: relative; min-height: 200px; } +.vt-app .vt-grid-wait { visibility: hidden; } +.vt-app .vt-grid > .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)); + position: absolute; top: var(--y); box-sizing: border-box; min-width: 0; + left: calc(var(--vt-cw) * var(--c) + var(--vt-gap) * var(--c)); + width: calc(var(--vt-cw) * var(--w) + var(--vt-gap) * (var(--w) - 1)); } -.vt-app .vt-hero { grid-area: hero; } -.vt-app .vt-sys { grid-area: sys; } -.vt-app .vt-chart { grid-area: chart; } -.vt-app .vt-radios { grid-area: radios; } -.vt-app .vt-clients { grid-area: clients; } -.vt-app .vt-side { grid-area: side; display: flex; flex-direction: column; gap: 14px; min-width: 0; } -/* phones: the side column dissolves so Top talkers can follow Clients */ +.vt-app .vt-cell-off { display: none !important; } +.vt-app .vt-drop-ghost { display: none; border: 2px dashed var(--vt-accent-line); border-radius: var(--vt-r-lg); background: var(--vt-accent-soft); } +.vt-app .vt-drop-ghost.vt-on { display: block; } + +/* ----------------------------------------------- 3b. arranging the tiles */ + +.vt-app .vt-layout-btn { flex: none; height: 30px; gap: 6px; font-size: 12px; } +.vt-app .vt-layout-btn .vt-ico { width: 16px; height: 16px; } +.vt-app .vt-layout-btn[aria-pressed="true"] { background: var(--vt-accent-soft); color: var(--vt-text); } +@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; + display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; + margin: 0 0 14px; 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: 13px; font-weight: 650; } +.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-editbar-actions { display: flex; gap: 8px; margin-left: auto; } @container vt (max-width: 699px) { - .vt-app .vt-side { display: contents; } - .vt-app .vt-talk { grid-area: talk; } - .vt-app .vt-ssid-tile { grid-area: ssids; } + .vt-app .vt-editbar { padding: 8px 8px 8px 12px; gap: 8px; } + .vt-app .vt-editbar-text { flex-basis: 0; } + .vt-app .vt-editbar-text .vt-hint { display: none; } } -@container vt (min-width: 700px) { - .vt-app .vt-grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); - grid-template-areas: "hero hero" "radios radios" "clients clients" "chart chart" "sys side"; - } +.vt-app .vt-ov { display: none; } +.vt-app.vt-editing .vt-ov { + display: block; position: absolute; inset: 0; z-index: 4; + border: 2px dashed var(--vt-accent-line); border-radius: var(--vt-r-lg); + background: color-mix(in oklab, var(--vt-surface) 55%, transparent); } -@container vt (min-width: 1100px) { - .vt-app .vt-grid { - grid-template-columns: repeat(4, minmax(0, 1fr)); - grid-template-areas: - "hero hero hero sys" - "chart chart radios radios" - "clients clients clients side"; - } +.vt-app .vt-ov-bar { + display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; + 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: 13px; 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; + width: 30px; height: 30px; min-width: 0; margin: 0; padding: 0; border: 0; border-radius: 8px; + background: transparent; color: var(--vt-text-2); box-shadow: none; cursor: pointer; +} +.vt-app .vt-ov-grip { cursor: grab; touch-action: none; background: var(--vt-surface-3); color: var(--vt-text); } +.vt-app .vt-ov-btn:hover:not([disabled]), .vt-app .vt-ov-grip:hover { background: var(--vt-surface-3); color: var(--vt-text); } +.vt-app .vt-ov-btn[disabled] { opacity: .3; cursor: default; } +.vt-app .vt-ov-btn .vt-ico, .vt-app .vt-ov-grip .vt-ico { width: 16px; height: 16px; } +.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: 11.5px; font-weight: 650; color: var(--vt-text-2); } +.vt-app.vt-edit-1col .vt-ov-col { 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-dragging .vt-ov-grip { cursor: grabbing; } +.vt-app.vt-drag-on { user-select: none; -webkit-user-select: none; } .vt-app .vt-tile { position: relative; @@ -429,6 +469,9 @@ html[data-darkmode="true"] .vt-app { } @container vt (min-width: 700px) { .vt-app .vt-health { grid-template-columns: repeat(3, minmax(0, 1fr)); } } @container vt (min-width: 1100px) { .vt-app .vt-health { grid-template-columns: repeat(6, minmax(0, 1fr)); } } +/* wired-only: four checks */ +@container vt (min-width: 700px) { .vt-app.vt-wired .vt-health { grid-template-columns: repeat(2, minmax(0, 1fr)); } } +@container vt (min-width: 1100px) { .vt-app.vt-wired .vt-health { grid-template-columns: repeat(4, minmax(0, 1fr)); } } .vt-app .vt-chip { display: flex; align-items: flex-start; gap: 10px; min-width: 0; padding: 11px 12px; border-radius: var(--vt-r); @@ -538,6 +581,7 @@ html[data-darkmode="true"] .vt-app { .vt-app .vt-node-ap .vt-node-title { font-size: 14.5px; } .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-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 .vt-node-title { display: flex; align-items: center; gap: 6px; font-size: 13px; } .vt-app .vt-node-ssid .vt-node-title .vt-ico { color: var(--vt-text-3); } @@ -593,10 +637,12 @@ html[data-darkmode="true"] .vt-app { /* ------------------------------------------------------------ 6. system */ -.vt-app .vt-sys { display: flex; flex-direction: column; gap: 16px; } +.vt-app .vt-sys { container: vtsys / inline-size; display: flex; flex-direction: column; gap: 16px; } .vt-app .vt-sys .vt-tile-head { margin-bottom: 0; } .vt-app .vt-sys-cpu { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 16px; align-items: end; } .vt-app .vt-sys-cpu-l { display: flex; flex-direction: column; gap: 3px; } +/* a narrow System column puts the sparkline under the load figures */ +@container vtsys (max-width: 330px) { .vt-app .vt-sys-cpu { grid-template-columns: minmax(0, 1fr); gap: 4px; } } .vt-app .vt-sys-cpu-r { display: flex; align-items: flex-end; gap: 10px; min-width: 0; } .vt-app .vt-spark-box { flex: 1; min-width: 0; padding-top: 12px; } .vt-app .vt-spark-box .vt-spark { height: 38px; } @@ -645,16 +691,6 @@ html[data-darkmode="true"] .vt-app { .vt-app .vt-chart .vt-tile-title { flex-wrap: wrap; row-gap: 0; } .vt-app .vt-chart-sub { font-size: 12px; font-weight: 500; color: var(--vt-text-3); } .vt-app .vt-chart-sub::before { content: "·"; margin: 0 6px 0 0; } -.vt-app .vt-seg-ctl { display: inline-flex; padding: 2px; gap: 2px; border-radius: 8px; background: var(--vt-surface-3); } -.vt-app .vt-seg-btn { - display: inline-flex; align-items: center; gap: 5px; height: 26px; padding: 0 10px; - border: 0; border-radius: 6px; background: transparent; color: var(--vt-text-2); - font-size: 12px; font-weight: 600; cursor: pointer; box-shadow: none; min-width: 0; text-transform: none; -} -.vt-app .vt-seg-btn .vt-ico { width: 13px; height: 13px; stroke-width: 2.2; } -.vt-app .vt-seg-btn:hover { color: var(--vt-text); background: transparent; } -.vt-app .vt-seg-btn[aria-pressed="true"] { background: var(--vt-surface); color: var(--vt-text); box-shadow: 0 1px 2px rgba(0, 0, 0, .12); } - .vt-app .vt-c-up { --vt-sc: var(--vt-series-up); } .vt-app .vt-c-2g { --vt-sc: var(--vt-b2); } .vt-app .vt-c-5g { --vt-sc: var(--vt-b5); } @@ -662,8 +698,8 @@ html[data-darkmode="true"] .vt-app { .vt-app .vt-c-x { --vt-sc: var(--vt-text-3); } .vt-app .vt-lg-key { width: 12px; height: 3px; border-radius: 2px; background: var(--vt-sc); flex: none; } -.vt-app .vt-mult-wrap { position: relative; flex: 1; display: flex; flex-direction: column; min-height: 240px; border-radius: var(--vt-r-sm); outline-offset: 4px; } -.vt-app .vt-mults { flex: 1; display: grid; grid-auto-rows: minmax(64px, 1fr); } +.vt-app .vt-mult-wrap { position: relative; flex: 1; display: flex; flex-direction: column; min-height: 300px; border-radius: var(--vt-r-sm); outline-offset: 4px; } +.vt-app .vt-mults { flex: 1; display: grid; grid-auto-rows: minmax(100px, 1fr); } .vt-app .vt-mult { display: grid; grid-template-columns: var(--vt-mh) minmax(0, 1fr); column-gap: var(--vt-mg); padding: 8px 0; border-top: 1px solid var(--vt-line); min-height: 0; @@ -672,18 +708,25 @@ html[data-darkmode="true"] .vt-app { .vt-app .vt-mult-head { display: flex; flex-direction: column; justify-content: center; gap: 1px; min-width: 0; } .vt-app .vt-mult-name { display: flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 600; color: var(--vt-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .vt-app .vt-mult-now { font-size: 17px; font-weight: 700; letter-spacing: -.01em; line-height: 1.25; white-space: nowrap; } +.vt-app .vt-mult-now-up { font-size: 13px; font-weight: 650; line-height: 1.3; color: var(--vt-text-2); white-space: nowrap; } .vt-app .vt-mult-stats { display: flex; flex-wrap: wrap; gap: 0 8px; font-size: 11px; 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-plot { position: relative; min-height: 48px; margin-top: 12px; border-bottom: 1px solid color-mix(in oklab, var(--vt-chart-axis) 40%, transparent); --vt-sc: inherit; } +.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; } .vt-app .vt-chart-vgrid { fill: none; stroke: var(--vt-chart-grid); stroke-width: 1; stroke-dasharray: 2 4; vector-effect: non-scaling-stroke; } .vt-app .vt-series-line { fill: none; stroke: var(--vt-sc); stroke-width: 1.75; vector-effect: non-scaling-stroke; stroke-linejoin: round; stroke-linecap: round; } .vt-app .vt-series-area { stroke: none; } +/* upload, below the line: the link's colour, quieter */ +.vt-app .vt-series-line.vt-dir-up { stroke-opacity: .6; } +.vt-app .vt-series-area.vt-dir-up { opacity: .55; } +.vt-app .vt-mult-dot.vt-dir-up, .vt-app .vt-sk-dot.vt-dir-up { opacity: .7; } +.vt-app .vt-chart-mid { fill: none; stroke: color-mix(in oklab, var(--vt-chart-axis) 55%, transparent); stroke-width: 1; vector-effect: non-scaling-stroke; } .vt-app .vt-mult-max { position: absolute; right: 0; top: -3px; transform: translateY(-100%); font-size: 10.5px; line-height: 1; color: var(--vt-chart-axis); white-space: nowrap; pointer-events: none; } +.vt-app .vt-mult-max-up { top: auto; bottom: -3px; transform: translateY(100%); } .vt-app .vt-mult-dot { position: absolute; width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; border-radius: 50%; z-index: 2; background: var(--vt-sc); box-shadow: 0 0 0 2px var(--vt-surface); pointer-events: none; @@ -697,15 +740,16 @@ html[data-darkmode="true"] .vt-app { .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; transform: translateX(12px); - min-width: 180px; padding: 8px 10px 7px; border-radius: var(--vt-r); + 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); font-size: 12px; pointer-events: none; } .vt-app .vt-tip-left { transform: translateX(calc(-100% - 12px)); } .vt-app .vt-tip-time { display: flex; justify-content: space-between; gap: 12px; color: var(--vt-text-3); font-size: 11px; margin-bottom: 5px; padding-bottom: 5px; border-bottom: 1px solid var(--vt-line); } -.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; } +.vt-app .vt-tip-row { display: grid; grid-template-columns: 12px auto auto minmax(0, 1fr); align-items: center; column-gap: 8px; line-height: 1.6; } .vt-app .vt-tip-row b { font-weight: 700; color: var(--vt-text); white-space: nowrap; } +.vt-app .vt-tip-row .vt-tip-up { font-weight: 600; color: var(--vt-text-2); } .vt-app .vt-tip-label { color: var(--vt-text-3); white-space: nowrap; text-align: right; } /* ------------------------------------------------------------ 8. radios */ 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 89f5ecfce..7a0f69048 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js @@ -32,6 +32,7 @@ return baseclass.extend({ /* ------------------------------------------------------------ health */ /* model + { cpu: { pct, cores } | null, uplinkRate: { rx, tx } | null } + (model.wired: no Wi-Fi checks) -> [ { id, level, title, value, reason, detail, page } ] value and reason are short enough for a health chip; detail is the full sentence (tooltip / accessible description). */ @@ -79,7 +80,20 @@ return baseclass.extend({ detail: _('%s of %s available (%s in use)').format(fmt.bytes(mem.available), fmt.bytes(mem.total), fmt.pct(mem.usedPct)), page: PAGES.processes }); } - /* radios; an SSID without clients is normal, not a fault */ + /* radios and signal; neither applies to a wired-only device */ + if (!model.wired) this.wifiHealth(model, out); + + /* storage */ + var root = (dev.storage || [])[0]; + if (root) out.push({ id: 'storage', level: root.usedPct >= 95 ? 'err' : root.usedPct >= 85 ? 'warn' : 'ok', title: _('Storage'), value: _('%s used').format(fmt.pct(root.usedPct)), + reason: _('%s free').format(fmt.bytes(root.free)), detail: _('%s free on the overlay (%s used)').format(fmt.bytes(root.free), fmt.pct(root.usedPct)), page: PAGES.mounts }); + + return out; + }, + + /* the Wi-Fi and Signal checks, appended to out; an SSID without + clients is normal, 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; }); @@ -102,13 +116,6 @@ return baseclass.extend({ 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, client: weak[0].mac }); 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 }); - - /* storage */ - var root = (dev.storage || [])[0]; - if (root) out.push({ id: 'storage', level: root.usedPct >= 95 ? 'err' : root.usedPct >= 85 ? 'warn' : 'ok', title: _('Storage'), value: _('%s used').format(fmt.pct(root.usedPct)), - reason: _('%s free').format(fmt.bytes(root.free)), detail: _('%s free on the overlay (%s used)').format(fmt.bytes(root.free), fmt.pct(root.usedPct)), page: PAGES.mounts }); - - return out; }, /* -> { level, count (warn+err), headline } */ diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/layout.js b/luci-app-vantage/htdocs/luci-static/resources/vantage/layout.js new file mode 100644 index 000000000..c3dac3906 --- /dev/null +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/layout.js @@ -0,0 +1,224 @@ +'use strict'; +'require baseclass'; + +/* Dashboard layout: which tiles show, where and how wide, per screen + class. The view measures the tiles and positions them; this module + only holds the rules. Pure functions. + + A layout is a list of { id, c, w, hide } in reading order: the tile + starts in column c and spans w columns. Each tile goes below what + earlier tiles left in its columns, so a column keeps its tiles + whatever their heights, and a short tile never stretches a tall + neighbour. */ + +var TILES = [ 'hero', 'chart', 'radios', 'clients', 'sys', 'talk', 'ssids' ]; + +/* tiles that only exist with Wi-Fi */ +var WIFI = { radios: true, clients: true, talk: true, ssids: true }; + +var COLS = { wide: 4, mid: 2, narrow: 1 }; + +/* narrowest each tile may get, in columns of that screen class */ +var MIN = { + wide: { hero: 3, chart: 2, clients: 2 }, + mid: { hero: 2 } +}; + +/* tiles whose content grows to fill a taller slot */ +var FLEX = { chart: true }; + +/* how far a tile stretches to line up with the tile below it */ +var SNAP = 48; + +/* [ id, column, width ] */ +var DEFAULTS = { + wide: [ [ 'hero', 0, 4 ], [ 'chart', 0, 2 ], [ 'radios', 2, 2 ], [ 'clients', 0, 3 ], [ 'sys', 3, 1 ], [ 'talk', 3, 1 ], [ 'ssids', 3, 1 ] ], + mid: [ [ 'hero', 0, 2 ], [ 'radios', 0, 2 ], [ 'clients', 0, 2 ], [ 'chart', 0, 2 ], [ 'sys', 0, 1 ], [ 'talk', 1, 1 ], [ 'ssids', 1, 1 ] ], + narrow: [ [ 'clients', 0, 1 ], [ 'talk', 0, 1 ], [ 'radios', 0, 1 ], [ 'hero', 0, 1 ], [ 'ssids', 0, 1 ], [ 'chart', 0, 1 ], [ 'sys', 0, 1 ] ] +}; +var DEFAULTS_WIRED = { + wide: [ [ 'hero', 0, 4 ], [ 'chart', 0, 3 ], [ 'sys', 3, 1 ] ], + mid: [ [ 'hero', 0, 2 ], [ 'chart', 0, 2 ], [ 'sys', 0, 2 ] ], + narrow: [ [ 'hero', 0, 1 ], [ 'chart', 0, 1 ], [ 'sys', 0, 1 ] ] +}; + +function own(o, k) { return o != null && Object.prototype.hasOwnProperty.call(o, k); } +function int(v, d) { v = Math.round(+v); return isFinite(v) ? v : d; } + +return baseclass.extend({ + TILES: TILES, + SNAP: SNAP, + + /* screen class for a layout width; the breakpoints match app.css */ + tier: function(width) { + return width >= 1100 ? 'wide' : width >= 700 ? 'mid' : 'narrow'; + }, + + cols: function(tier) { return own(COLS, tier) ? COLS[tier] : 1; }, + + /* the storage key of a layout: Wi-Fi and wired devices differ */ + key: function(tier, wired) { return tier + (wired ? '-wired' : ''); }, + + available: function(id, wired) { return TILES.indexOf(id) >= 0 && !(wired && WIFI[id]); }, + + minW: function(id, tier) { + var m = own(MIN, tier) && own(MIN[tier], id) ? MIN[tier][id] : 1; + return Math.min(m, this.cols(tier)); + }, + + /* a tile with its width in range and its column inside the grid */ + fit: function(e, tier) { + var n = this.cols(tier); + var w = Math.max(this.minW(e.id, tier), Math.min(n, int(e.w, 1))); + var c = Math.max(0, Math.min(n - w, int(e.c, 0))); + return { id: e.id, c: c, w: w, hide: e.hide === true }; + }, + + defaults: function(tier, wired) { + var src = own(DEFAULTS, tier) ? (wired ? DEFAULTS_WIRED : DEFAULTS)[tier] : DEFAULTS.narrow; + var self = this; + return src.map(function(d) { return self.fit({ id: d[0], c: d[1], w: d[2] }, tier); }); + }, + + /* a stored layout made safe: known tiles only, each once, sizes in + range, tiles it does not mention added after the tile that + precedes them by default */ + normalize: function(saved, tier, wired) { + var self = this, seen = Object.create(null), out = []; + var def = this.defaults(tier, wired); + if (!Array.isArray(saved)) return def; + saved.slice(0, 32).forEach(function(e) { + if (!e || typeof e !== 'object' || typeof e.id !== 'string' || seen[e.id] || !self.available(e.id, wired)) return; + seen[e.id] = true; + out.push(self.fit(e, tier)); + }); + if (!out.length) return def; + def.forEach(function(d, i) { + if (seen[d.id]) return; + var at = 0; + for (var j = i - 1; j >= 0; j--) { + var k = self.indexOf(out, def[j].id); + if (k >= 0) { at = k + 1; break; } + } + out.splice(at, 0, d); + }); + if (!out.some(function(e) { return !e.hide; })) out[0].hide = false; + return out; + }, + + /* what is worth storing */ + compact: function(list) { + return list.map(function(e) { var o = { id: e.id, c: e.c, w: e.w }; if (e.hide) o.hide = true; return o; }); + }, + + same: function(a, b) { + return a.length === b.length && a.every(function(e, i) { + return e.id === b[i].id && e.c === b[i].c && e.w === b[i].w && !!e.hide === !!b[i].hide; + }); + }, + + indexOf: function(list, id) { + for (var i = 0; i < list.length; i++) if (list[i].id === id) return i; + return -1; + }, + + copy: function(list) { return list.map(function(e) { return { id: e.id, c: e.c, w: e.w, hide: !!e.hide }; }); }, + + /* swap with the next shown tile before (-1) or after (+1) */ + move: function(list, id, dir) { + var out = this.copy(list), i = this.indexOf(out, id); + if (i < 0) return out; + for (var j = i + dir; j >= 0 && j < out.length; j += dir) { + if (out[j].hide) continue; + var t = out.splice(i, 1)[0]; + out.splice(j, 0, t); + break; + } + return out; + }, + + /* one column left (-1) or right (+1) */ + shift: function(list, id, dc, tier) { + var self = this; + return this.copy(list).map(function(e) { return e.id === id ? self.fit({ id: e.id, c: e.c + dc, w: e.w, hide: e.hide }, tier) : e; }); + }, + + /* wider or narrower; a tile at the right edge grows to the left */ + resize: function(list, id, dw, tier) { + var self = this, n = this.cols(tier); + return this.copy(list).map(function(e) { + if (e.id !== id) return e; + var w = Math.max(self.minW(id, tier), Math.min(n, e.w + dw)); + return self.fit({ id: id, c: Math.min(e.c, n - w), w: w, hide: e.hide }, tier); + }); + }, + + /* dragging: put a tile in column c, before or after another tile */ + drop: function(list, id, c, target, after, tier) { + var out = this.copy(list), i = this.indexOf(out, id); + if (i < 0) return out; + var t = this.fit({ id: id, c: c, w: out[i].w, hide: out[i].hide }, tier); + out.splice(i, 1); + var j = target != null && target !== id ? this.indexOf(out, target) : -1; + if (j < 0) out.splice(i, 0, t); + else out.splice(after ? j + 1 : j, 0, t); + return out; + }, + + /* hiding keeps the tile's place, so showing it again restores it; + the last shown tile cannot be hidden */ + setHidden: function(list, id, hide) { + var out = this.copy(list), i = this.indexOf(out, id); + if (i < 0) return out; + if (hide && out.filter(function(e) { return !e.hide; }).length <= 1) return out; + out[i].hide = !!hide; + return out; + }, + + /* a tile's height between polls: it grows at once but shrinks only + after its content stayed smaller for HOLD_MS, so a talker or a + client dropping out for one poll doesn't move the page. prev is + the last { h, since } (or null); returns the next one */ + HOLD_MS: 30000, + settle: function(prev, natural, now) { + if (!prev || natural >= prev.h) return { h: natural, since: null }; + var since = prev.since == null ? now : prev.since; + if (now - since >= this.HOLD_MS) return { h: natural, since: null }; + return { h: prev.h, since: since }; + }, + + /* where shown tiles go. items: [{ id, c, w, h }] in order, h measured; + returns { rects: { id: { c, w, top, h } }, height }. A tile that + ends a little above the next one in its columns stretches to meet + it (any amount for FLEX tiles), so neighbours line up. */ + pack: function(items, cols, gap) { + var bottoms = [], last = [], rects = Object.create(null), c, i; + for (c = 0; c < cols; c++) { bottoms.push(0); last.push(null); } + + /* only a tile with nothing under it in any of its columns, or it + would grow over that tile */ + function stretch(col, top) { + var id = last[col], r = id && rects[id]; + if (!r) return; + var g = top - bottoms[col]; + if (g <= 0 || !(FLEX[id] || g <= SNAP)) return; + for (var j = r.c; j < r.c + r.w; j++) if (last[j] !== id) return; + r.h += g; + for (var k = r.c; k < r.c + r.w; k++) + if (last[k] === id) bottoms[k] = r.top + r.h + gap; + } + + items.forEach(function(it) { + var w = Math.max(1, Math.min(cols, it.w | 0)), at = Math.max(0, Math.min(cols - w, it.c | 0)), top = 0; + for (i = at; i < at + w; i++) top = Math.max(top, bottoms[i]); + for (i = at; i < at + w; i++) stretch(i, top); + rects[it.id] = { c: at, w: w, top: top, h: Math.max(0, +it.h || 0) }; + for (i = at; i < at + w; i++) { bottoms[i] = top + rects[it.id].h + gap; last[i] = it.id; } + }); + + var end = Math.max.apply(null, bottoms); + for (c = 0; c < cols; c++) stretch(c, end); + end = Math.max.apply(null, bottoms); + return { rects: rects, height: Math.max(0, end - gap) }; + } +}); 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 8c4158e01..376a7b65f 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/vantage/model.js +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/model.js @@ -227,6 +227,34 @@ return baseclass.extend({ }; }, + /* The device's other networks (lan, guest, a VPN, ...): every + interface except loopback and the uplink (wan6 shares wan's device). + One entry per device, by interface name. + -> [ { name, proto, dev, up, ipv4 } ] */ + networks: function(ifaces, uplink) { + var seen = Object.create(null); + return arr(ifaces).filter(function(i) { + return i && typeof i.interface === 'string' && i.interface !== 'loopback'; + }).sort(function(a, b) { + return a.interface < b.interface ? -1 : a.interface > b.interface ? 1 : 0; + }).map(function(i) { + var dev = i.l3_device || i.device; + var a4 = arr(i['ipv4-address']).filter(function(a) { return a && a.address; })[0]; + return { + name: fmt.safeText(i.interface, 32), + proto: typeof i.proto === 'string' ? fmt.safeText(i.proto, 24) : null, + dev: typeof dev === 'string' && dev ? dev : null, + up: !!i.up, + ipv4: a4 ? a4.address + '/' + a4.mask : null + }; + }).filter(function(n) { + if (uplink && (n.name === uplink.iface || (n.dev && n.dev === uplink.l3dev))) return false; + if (n.dev && seen[n.dev]) return false; + if (n.dev) seen[n.dev] = true; + return true; + }); + }, + /* The device tree model is sometimes the SoC reference design ("Qualcomm Technologies, Inc. IPQ5332/RDP442/..."); board_name ("zyxel,nwa50be") names the actual product then. */ @@ -463,6 +491,7 @@ return baseclass.extend({ storage: [ this.mount(info.root, _('Root (overlay)')), this.mount(info.tmp, _('Temporary (RAM)')) ].filter(Boolean) }, uplink: uplink, + networks: this.networks(raw.ifaces, uplink), radios: radios, ssids: ssids, clients: clients 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 cfb825db3..76cc490f1 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 @@ -10,6 +10,7 @@ 'require vantage.model as model'; 'require vantage.insight as insight'; 'require vantage.series as series'; +'require vantage.layout as layout'; /* Vantage dashboard (luci-app-vantage): a live, read-only overview of the device, its uplink, radios, SSIDs and stations. The only write is the @@ -104,7 +105,13 @@ var ICONS = { watch: [ 'M8.5 6h7A1.5 1.5 0 0 1 17 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-7A1.5 1.5 0 0 1 7 16.5v-9A1.5 1.5 0 0 1 8.5 6Z', 'M9 6l.5-3h5l.5 3M9 18l.5 3h5l.5-3' ], iot: [ 'M9 18h6', 'M10 21h4', 'M12 3a6 6 0 0 0-3.5 10.9V16h7v-2.1A6 6 0 0 0 12 3Z' ], router: [ 'M4.5 13h15a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-15a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1Z', 'M7 16h.01M10 16h.01', 'M8 13 6 6.5M16 13l2-6.5' ], - device: [ 'M7 3.5h10A1.5 1.5 0 0 1 18.5 5v14a1.5 1.5 0 0 1-1.5 1.5H7A1.5 1.5 0 0 1 5.5 19V5A1.5 1.5 0 0 1 7 3.5Z', 'M10 17.5h4', 'M9 7.5h6' ] + device: [ 'M7 3.5h10A1.5 1.5 0 0 1 18.5 5v14a1.5 1.5 0 0 1-1.5 1.5H7A1.5 1.5 0 0 1 5.5 19V5A1.5 1.5 0 0 1 7 3.5Z', 'M10 17.5h4', 'M9 7.5h6' ], + layout: [ 'M4.5 4.5h6v7h-6zM13.5 4.5h6v4h-6zM13.5 11.5h6v8h-6zM4.5 14.5h6v5h-6z' ], + grip: [ 'M9 6h.01M15 6h.01M9 12h.01M15 12h.01M9 18h.01M15 18h.01' ], + left: [ 'M14.5 6l-6 6 6 6' ], + plus: [ 'M12 5.5v13M5.5 12h13' ], + minus: [ 'M5.5 12h13' ], + hide: [ 'M3.5 12s3-6 8.5-6 8.5 6 8.5 6-3 6-8.5 6-8.5-6-8.5-6Z', 'M12 9.5a2.5 2.5 0 1 0 0 5a2.5 2.5 0 1 0 0-5Z', 'M4.5 19.5l15-15' ] }; function svgRoot(cls, viewBox) { @@ -150,16 +157,17 @@ function signalGlyph(sig) { } /* vertical fade for area fills: the series colour (--vt-sc) at the - chart fill opacity at the top, transparent at the baseline. Returns the - paint reference for the fill attribute. */ + chart fill opacity at the top, transparent at the baseline (flip: an + area hanging down from its baseline). Returns the paint reference for + the fill attribute. */ var gradSeq = 0; -function fadeFill(svg) { +function fadeFill(svg, flip) { var id = 'vt-fade-' + (++gradSeq); var defs = document.createElementNS(SVGNS, 'defs'); var lg = document.createElementNS(SVGNS, 'linearGradient'); lg.setAttribute('id', id); - lg.setAttribute('x1', '0'); lg.setAttribute('y1', '0'); - lg.setAttribute('x2', '0'); lg.setAttribute('y2', '1'); + lg.setAttribute('x1', '0'); lg.setAttribute('y1', flip ? '1' : '0'); + lg.setAttribute('x2', '0'); lg.setAttribute('y2', flip ? '0' : '1'); [ [ '0', 'vt-fade-top' ], [ '1', 'vt-fade-end' ] ].forEach(function(st) { var stop = document.createElementNS(SVGNS, 'stop'); stop.setAttribute('offset', st[0]); @@ -265,6 +273,14 @@ function kv(label, value, mono) { ]); } +/* one of the four numbers under the network path */ +function kpi(label, value, sub, tone, onclick) { + var body = [ E('span', { 'class': 'vt-kpi-label' }, [ label ]), E('span', { 'class': 'vt-kpi-value vt-tn' }, [ value ]), E('span', { 'class': 'vt-kpi-sub' }, [ sub ]) ]; + return onclick + ? E('button', { 'type': 'button', 'class': 'vt-kpi vt-kpi-' + (tone || 'plain'), 'click': onclick }, body) + : E('div', { 'class': 'vt-kpi vt-kpi-' + (tone || 'plain') }, body); +} + function tileHead(ic, title, extra) { return E('header', { 'class': 'vt-tile-head' }, [ E('h3', { 'class': 'vt-tile-title' }, [ icon(ic), E('span', {}, [ title ]) ]), @@ -320,6 +336,26 @@ function writeFolds(v) { try { window.localStorage.setItem(FOLD_KEY, JSON.stringify(v)); } catch (e) {} } +/* Tile layouts the viewer arranged, per screen class, in this browser; + vantage.layout validates whatever comes back */ +var LAYOUT_KEY = 'vantage.layout.v1'; + +function readLayouts() { + var v = null; + try { v = JSON.parse(window.localStorage.getItem(LAYOUT_KEY) || 'null'); } catch (e) { v = null; } + var out = Object.create(null); + if (v && typeof v === 'object' && !Array.isArray(v)) + Object.keys(v).forEach(function(k) { if (/^(wide|mid|narrow)(-wired)?$/.test(k) && Array.isArray(v[k])) out[k] = v[k]; }); + return out; +} + +function writeLayouts(v) { + try { + if (Object.keys(v).length) window.localStorage.setItem(LAYOUT_KEY, JSON.stringify(v)); + else window.localStorage.removeItem(LAYOUT_KEY); + } catch (e) {} +} + /* ================================================================= view */ return view.extend({ @@ -361,12 +397,13 @@ return view.extend({ L.resolveDefault(callRead('/proc/stat'), ''), L.resolveDefault(callIfDump(), []), L.resolveDefault(callDevs(), {}), - L.resolveDefault(callWifi(), {}), + /* null when the call fails: no answer is not "no radios" */ + L.resolveDefault(callWifi(), null), L.resolveDefault(callHints(), {}) ]).then(function(r) { - var wifiDevs = (r[4] && typeof r[4] === 'object') ? r[4] : {}; + var wifiDevs = (r[4] && typeof r[4] === 'object') ? r[4] : null; var ifnames = []; - Object.keys(wifiDevs).forEach(function(rn) { + Object.keys(wifiDevs || {}).forEach(function(rn) { var ifs = (wifiDevs[rn] && Array.isArray(wifiDevs[rn].interfaces)) ? wifiDevs[rn].interfaces : []; ifs.forEach(function(i) { if (i && typeof i.ifname === 'string' && HOSTAPD_OBJ.test(i.ifname) && ifnames.indexOf(i.ifname) < 0) ifnames.push(i.ifname); @@ -423,12 +460,16 @@ return view.extend({ rdns: Object.create(null), rdnsBusy: false, rdnsOff: !data.canRdns, mdns: Object.create(null), mdnsOff: true, mdnsAt: 0, oui: null, ouiLoading: false, + wireless: null, lastOk: 0, lastErr: null, paused: false }; - this.ui = { sort: 'live', dir: -1, filter: '', chip: 'all', chart: 'down', drawer: null, editing: null, hover: null }; + this.ui = { sort: 'live', dir: -1, filter: '', chip: 'all', drawer: null, editing: null, hover: null }; this.folds = readFolds(); this.foldEls = {}; this.foldBtns = {}; + this.layouts = readLayouts(); + this.editing = false; + this.drag = null; this.applyMdns(data.mdns); this.aliases = this.aliases || {}; }, @@ -461,6 +502,7 @@ return view.extend({ aliases: this.aliases, rdns: st.rdns, mdns: st.mdns, vendor: st.oui ? function(k) { return k ? st.oui.lookup(k) : null; } : null }); + this.markWired(m, raw); if (m.device.memory) series.push(st.hist.mem, [ at, m.device.memory.usedPct ], WINDOW_MS, HIST_MAX); /* interface counters */ @@ -530,6 +572,18 @@ return view.extend({ return m; }, + /* Wired-only: the wireless status answered and lists no radios. A + failed call proves nothing, and radios seen once keep the Wi-Fi + layout for the session, so one bad poll cannot reshuffle the page. */ + markWired: function(m, raw) { + var st = this.st; + if (raw && raw.wifi) { + if (m.radios.length) st.wireless = true; + else if (st.wireless !== true) st.wireless = false; + } + m.wired = st.wireless === false; + }, + /* The generation shown is the best standard a station used this session: single frames (management, retries) go out at legacy rates and would make the badge flicker. */ @@ -592,6 +646,7 @@ return view.extend({ aliases: this.aliases, rdns: st.rdns, mdns: st.mdns, vendor: st.oui ? function(k) { return k ? st.oui.lookup(k) : null; } : null }); + this.markWired(m, null); this.stickyGen(m); m.clients.forEach(function(c) { c.exp = insight.experience(c); c.firstSeen = st.presence && st.presence.firstSeen[c.mac]; c.isNew = !!st.isNew[c.mac]; }); st.talkers = insight.topTalkers(m.clients, st.staRates, 5); @@ -631,14 +686,8 @@ return view.extend({ E('div', { 'class': 'vt-body' }, [ this.buildHead(), this.el.health = E('div', { 'class': 'vt-health', 'role': 'list', 'aria-label': _('Health checks') }), - E('div', { 'class': 'vt-grid' }, [ - this.buildHero(), - this.buildSystem(), - this.buildChart(), - this.buildRadios(), - this.buildClients(), - E('div', { 'class': 'vt-side' }, [ this.buildTalkers(), this.buildSsids() ]) - ]) + this.buildEditBar(), + this.el.grid = E('div', { 'class': 'vt-grid vt-grid-wait' }, this.buildTiles()) ]), this.buildDrawer() ]); @@ -654,12 +703,19 @@ return view.extend({ document.addEventListener('keydown', L.bind(this.handleKey, this)); window.setInterval(function() { self.paintLive(); }, 1000); if (window.ResizeObserver) new ResizeObserver(function() { self.scheduleWires(); }).observe(this.el.path); + if (window.ResizeObserver) { + var ro = new ResizeObserver(function() { self.scheduleLayout(); }); + ro.observe(this.el.grid); + layout.TILES.forEach(function(id) { ro.observe(self.tiles[id]); }); + } + window.addEventListener('resize', function() { self.scheduleLayout(); }); window.addEventListener('hashchange', function() { self.openFromHash(); }); window.requestAnimationFrame(function() { self.drawWires(); self.openFromHash(); }); return root; }, paint: function() { + this.el.root.classList.toggle('vt-wired', !!this.m.wired); this.paintHead(); this.paintHealth(); this.paintHero(); @@ -672,6 +728,7 @@ return view.extend({ this.paintDrawer(); this.paintLive(); this.scheduleWires(); + this.scheduleLayout(); }, /* ------------------------------------------------------------ folds */ @@ -701,10 +758,338 @@ return view.extend({ this.folds[key] = !this.folds[key]; writeFolds(this.folds); this.applyFold(key); + if (this.held) delete this.held[key]; if (key === 'hero') this.scheduleWires(); if (key === 'chart') this.paintChart(); }, + /* ----------------------------------------------------------- layout */ + + /* the tiles in a fixed set; vantage.layout decides order and size */ + buildTiles: function() { + var self = this; + this.tiles = { + hero: this.buildHero(), chart: this.buildChart(), radios: this.buildRadios(), clients: this.buildClients(), + sys: this.buildSystem(), talk: this.buildTalkers(), ssids: this.buildSsids() + }; + this.tileNames = { + hero: _('Network path'), chart: _('Throughput'), radios: _('Radios'), clients: _('Clients'), + sys: _('System'), talk: _('Top talkers'), ssids: _('Wireless networks') + }; + this.ov = {}; + this.el.ghost = E('div', { 'class': 'vt-drop-ghost', 'aria-hidden': 'true' }); + return [ this.el.ghost ].concat(layout.TILES.map(function(id) { + var t = self.tiles[id]; + t.classList.add('vt-cell'); + t.appendChild(self.buildOverlay(id)); + return t; + })); + }, + + /* the stored layout for this screen class, or the default */ + layoutFor: function(tier, wired) { + var k = layout.key(tier, wired); + return layout.normalize(this.layouts[k] || null, tier, wired); + }, + + scheduleLayout: function() { + if (this.layoutRaf || !this.el || !this.el.grid) return; + var self = this; + this.layoutRaf = window.requestAnimationFrame(function() { self.layoutRaf = null; self.doLayout(); }); + }, + + /* measure the shown tiles at their widths, pack them, place them; + widths and columns come from CSS (--c, --w, --cols), only the + vertical positions from here */ + doLayout: function() { + var self = this, grid = this.el.grid, tiles = this.tiles; + var width = grid.clientWidth; + if (!width || !this.m) return; + var tier = layout.tier(width), cols = layout.cols(tier), wired = !!this.m.wired; + var list = this.drag ? this.drag.list : this.layoutFor(tier, wired); + var gap = parseFloat(window.getComputedStyle(grid).getPropertyValue('--vt-gap')) || 14; + var shown = list.filter(function(e) { return !e.hide; }); + var on = Object.create(null); + shown.forEach(function(e) { on[e.id] = true; }); + + /* keep what the viewer is reading in place when tiles above change */ + var sc = document.scrollingElement || document.documentElement, anchor = null, before = 0; + if (sc.scrollTop > 0 && !this.drag) { + for (var i = 0; i < shown.length && !anchor; i++) { + var r0 = tiles[shown[i].id].getBoundingClientRect(); + if (r0.height && r0.bottom > 0) { anchor = tiles[shown[i].id]; before = r0.top; } + } + } + + grid.style.setProperty('--cols', cols.toFixed(0)); + layout.TILES.forEach(function(id) { tiles[id].classList.toggle('vt-cell-off', !on[id]); }); + shown.forEach(function(e) { + var t = tiles[e.id]; + t.style.setProperty('--c', Math.min(e.c, cols - 1).toFixed(0)); + t.style.setProperty('--w', Math.min(e.w, cols).toFixed(0)); + t.style.minHeight = ''; + }); + /* live content changes hold a tile's height for a while; a new + width or an edit shows true sizes at once */ + if (this.heldWidth !== width || this.drag) { this.held = Object.create(null); this.heldWidth = width; } + var held = this.held, now = Date.now(); + var items = shown.map(function(e) { + var nat = tiles[e.id].getBoundingClientRect().height; + held[e.id] = layout.settle(held[e.id], nat, now); + return { id: e.id, c: e.c, w: e.w, h: held[e.id].h, nat: nat }; + }); + var p = layout.pack(items, cols, gap); + items.forEach(function(it) { + var r = p.rects[it.id], t = tiles[it.id]; + if (r.h > it.nat + 0.5) t.style.minHeight = r.h.toFixed(1) + 'px'; + t.style.setProperty('--y', r.top.toFixed(1) + 'px'); + }); + grid.style.height = p.height.toFixed(1) + 'px'; + var g = this.drag && p.rects[this.drag.id], ghost = this.el.ghost; + ghost.classList.toggle('vt-on', !!g); + if (g) { + ghost.style.setProperty('--c', g.c.toFixed(0)); + ghost.style.setProperty('--w', g.w.toFixed(0)); + ghost.style.setProperty('--y', g.top.toFixed(1) + 'px'); + ghost.style.height = g.h.toFixed(1) + 'px'; + } + this.lay = { tier: tier, cols: cols, wired: wired, list: list, rects: p.rects, gap: gap, width: width }; + + /* reading and tab order follow the layout; not while dragging, + moving the dragged tile would end the drag */ + if (!this.drag) { + var want = shown.map(function(e) { return tiles[e.id]; }); + var have = Array.prototype.filter.call(grid.children, function(c) { return c.classList.contains('vt-cell') && !c.classList.contains('vt-cell-off'); }); + if (want.some(function(t, k) { return have[k] !== t; })) { + var focus = document.activeElement; + want.forEach(function(t) { grid.appendChild(t); }); + if (focus && focus !== document.activeElement && grid.contains(focus)) focus.focus(); + } + } + if (anchor) { + var d = anchor.getBoundingClientRect().top - before; + if (Math.abs(d) > 0.5) sc.scrollTop += d; + } + grid.classList.remove('vt-grid-wait'); + if (this.editing) this.paintEdit(); + }, + + setLayout: function(list) { + var l = this.lay; + if (!l) return; + var k = layout.key(l.tier, l.wired); + if (layout.same(list, layout.defaults(l.tier, l.wired))) delete this.layouts[k]; + else this.layouts[k] = layout.compact(list); + writeLayouts(this.layouts); + this.held = Object.create(null); + this.doLayout(); + }, + + editTile: function(id, fn, say) { + var l = this.lay; + if (!l) return; + var next = fn(l.list); + if (layout.same(next, l.list)) return; + this.setLayout(next); + if (say) this.announce(say); + }, + + announce: function(text) { + var s = this.el.editSay; + dom.content(s, []); + window.setTimeout(function() { txt(s, text); }, 30); + }, + + setEditing: function(on) { + this.editing = !!on; + this.el.root.classList.toggle('vt-editing', this.editing); + this.el.layoutBtn.setAttribute('aria-pressed', String(this.editing)); + this.el.editBar.hidden = !this.editing; + if (this.editing) { + this.doLayout(); + this.el.editDone.focus(); + } + else this.el.layoutBtn.focus(); + }, + + buildEditBar: function() { + var self = this, el = this.el; + el.editHint = E('span', { 'class': 'vt-hint' }); + el.editHidden = E('div', { 'class': 'vt-edit-hidden' }); + el.editSay = E('span', { 'class': 'vt-sr', 'role': 'status', 'aria-live': 'polite' }); + el.editBar = E('div', { 'class': 'vt-editbar', 'role': 'region', 'aria-label': _('Arrange the dashboard'), 'hidden': 'hidden' }, [ + E('div', { 'class': 'vt-editbar-text' }, [ E('strong', {}, [ _('Arrange the dashboard') ]), el.editHint ]), + el.editHidden, + E('div', { 'class': 'vt-editbar-actions' }, [ + E('button', { 'type': 'button', 'class': 'vt-btn', 'click': function() { + var l = self.lay; + if (!l) return; + delete self.layouts[layout.key(l.tier, l.wired)]; + writeLayouts(self.layouts); + self.held = Object.create(null); + self.doLayout(); + self.announce(_('Layout reset')); + } }, [ _('Reset') ]), + el.editDone = E('button', { 'type': 'button', 'class': 'vt-btn vt-btn-primary', 'click': function() { self.setEditing(false); } }, [ _('Done') ]) + ]), + el.editSay + ]); + return el.editBar; + }, + + /* the controls laid over a tile while arranging */ + buildOverlay: function(id) { + var self = this, name = this.tileNames[id], o = {}; + function btn(cls, ic, label, fn) { + return E('button', { 'type': 'button', 'class': 'vt-ov-btn ' + cls, 'aria-label': label, 'title': label, 'click': fn }, [ icon(ic) ]); + } + o.grip = E('button', { 'type': 'button', 'class': 'vt-ov-grip', 'aria-label': _('Move %s: drag, or use the arrow keys').format(name), 'title': _('Drag to move') }, [ icon('grip') ]); + o.grip.addEventListener('pointerdown', function(ev) { self.dragStart(id, ev); }); + o.grip.addEventListener('keydown', function(ev) { + var k = ev.key, act = k === 'ArrowLeft' ? o.left : k === 'ArrowRight' ? o.right : k === 'ArrowUp' ? o.up : k === 'ArrowDown' ? o.down : null; + if (!act) return; + ev.preventDefault(); + if (!act.disabled) act.click(); + }); + o.left = btn('vt-ov-col', 'left', _('Move %s left').format(name), function() { + self.editTile(id, function(l) { return layout.shift(l, id, -1, self.lay.tier); }, _('%s moved left').format(name)); + }); + o.right = btn('vt-ov-col vt-ov-flip', 'left', _('Move %s right').format(name), function() { + self.editTile(id, function(l) { return layout.shift(l, id, 1, self.lay.tier); }, _('%s moved right').format(name)); + }); + o.up = btn('', 'up', _('Move %s up').format(name), function() { + self.editTile(id, function(l) { return layout.move(l, id, -1); }, _('%s moved up').format(name)); + }); + o.down = btn('', 'down', _('Move %s down').format(name), function() { + self.editTile(id, function(l) { return layout.move(l, id, 1); }, _('%s moved down').format(name)); + }); + o.narrow = btn('vt-ov-col', 'minus', _('Make %s narrower').format(name), function() { + self.editTile(id, function(l) { return layout.resize(l, id, -1, self.lay.tier); }, _('%s is narrower').format(name)); + }); + o.wide = btn('vt-ov-col', 'plus', _('Make %s wider').format(name), function() { + self.editTile(id, function(l) { return layout.resize(l, id, 1, self.lay.tier); }, _('%s is wider').format(name)); + }); + o.size = E('span', { 'class': 'vt-ov-size vt-ov-col vt-tn' }); + o.hide = btn('vt-ov-hide', 'hide', _('Hide %s').format(name), function() { + self.editTile(id, function(l) { return layout.setHidden(l, id, true); }, _('%s hidden').format(name)); + self.el.editDone.focus(); + }); + o.root = E('div', { 'class': 'vt-ov vt-fold-keep', 'role': 'group', 'aria-label': name }, [ + E('div', { 'class': 'vt-ov-bar' }, [ + o.grip, + E('span', { 'class': 'vt-ov-name' }, [ name ]), + E('span', { 'class': 'vt-ov-btns' }, [ o.up, o.down, o.left, o.right, o.narrow, o.size, o.wide, o.hide ]) + ]) + ]); + this.ov[id] = o; + return o.root; + }, + + /* button states, sizes and the hidden-tile list for the current layout */ + paintEdit: function() { + var self = this, l = this.lay; + if (!l) return; + var shown = l.list.filter(function(e) { return !e.hide; }); + txt(this.el.editHint, l.tier === 'wide' ? _('Drag a tile by its handle or use its buttons. Saved in this browser for wide screens.') + : l.tier === 'mid' ? _('Drag a tile by its handle or use its buttons. Saved in this browser for medium screens.') + : _('Drag a tile by its handle or use its buttons. Saved in this browser for narrow screens.')); + this.el.root.classList.toggle('vt-edit-1col', l.cols === 1); + shown.forEach(function(e, i) { + var o = self.ov[e.id]; + o.up.disabled = i === 0; + o.down.disabled = i === shown.length - 1; + o.left.disabled = e.c <= 0; + o.right.disabled = e.c + e.w >= l.cols; + o.narrow.disabled = e.w <= layout.minW(e.id, l.tier); + o.wide.disabled = e.w >= l.cols; + o.hide.disabled = shown.length <= 1; + txt(o.size, e.w + '/' + l.cols); + o.size.setAttribute('title', _('%d of %d columns').format(e.w, l.cols)); + }); + var hidden = l.list.filter(function(e) { return e.hide; }); + dom.content(this.el.editHidden, hidden.length ? [ E('span', { 'class': 'vt-label' }, [ _('Hidden') ]) ].concat(hidden.map(function(e) { + var name = self.tileNames[e.id]; + return E('button', { 'type': 'button', 'class': 'vt-fchip', 'title': _('Show %s').format(name), 'click': function() { + self.editTile(e.id, function(list) { return layout.setHidden(list, e.id, false); }, _('%s shown').format(name)); + } }, [ icon('plus'), E('span', {}, [ name ]) ]); + })) : []); + }, + + /* dragging by the handle: the tile follows the pointer, the others + make room where it would land */ + dragStart: function(id, ev) { + if (ev.button !== 0 || !this.lay || this.drag) return; + ev.preventDefault(); + var self = this, t = this.tiles[id], grip = this.ov[id].grip, tr = t.getBoundingClientRect(); + try { grip.setPointerCapture(ev.pointerId); } catch (e) {} + this.drag = { id: id, list: layout.copy(this.lay.list), start: layout.copy(this.lay.list), gx: ev.clientX - tr.left, gy: ev.clientY - tr.top, x: ev.clientX, y: ev.clientY, raf: null }; + t.classList.add('vt-dragging'); + this.el.root.classList.add('vt-drag-on'); + function move(e) { self.drag.x = e.clientX; self.drag.y = e.clientY; self.dragMove(); } + function end(e) { + grip.removeEventListener('pointermove', move); + grip.removeEventListener('pointerup', end); + grip.removeEventListener('pointercancel', end); + self.dragEnd(e.type === 'pointercancel'); + } + grip.addEventListener('pointermove', move); + grip.addEventListener('pointerup', end); + grip.addEventListener('pointercancel', end); + this.dragMove(); + this.dragScroll(); + }, + + dragMove: function() { + var d = this.drag, l = this.lay; + if (!d || !l) return; + var t = this.tiles[d.id], gr = this.el.grid.getBoundingClientRect(); + var x = d.x - gr.left - d.gx, y = d.y - gr.top - d.gy; + t.style.left = x.toFixed(1) + 'px'; + t.style.top = y.toFixed(1) + 'px'; + + var step = (l.width + l.gap) / l.cols, me = d.list[layout.indexOf(d.list, d.id)]; + var c = Math.max(0, Math.min(l.cols - me.w, Math.round(x / step))); + var px = d.x - gr.left, py = d.y - gr.top, target = null, after = false; + d.list.forEach(function(e) { + var r = l.rects[e.id]; + if (e.hide || e.id === d.id || !r) return; + var rx = r.c * step, rw = r.w * step - l.gap; + if (px >= rx && px <= rx + rw && py >= r.top && py <= r.top + r.h) { + target = e.id; + after = py > r.top + r.h / 2; + } + }); + var next = layout.drop(d.list, d.id, c, target, after, l.tier); + if (!layout.same(next, d.list)) { d.list = next; this.doLayout(); } + }, + + /* scroll while the pointer rests near the top or bottom edge */ + dragScroll: function() { + var self = this, d = this.drag; + if (!d) return; + var edge = 64, v = d.y < edge ? -(edge - d.y) / 4 : d.y > window.innerHeight - edge ? (d.y - window.innerHeight + edge) / 4 : 0; + if (v) { window.scrollBy(0, Math.round(v)); this.dragMove(); } + d.raf = window.requestAnimationFrame(function() { self.dragScroll(); }); + }, + + dragEnd: function(cancel) { + var d = this.drag; + if (!d) return; + if (d.raf) window.cancelAnimationFrame(d.raf); + var t = this.tiles[d.id]; + t.classList.remove('vt-dragging'); + this.el.root.classList.remove('vt-drag-on'); + t.style.left = ''; + t.style.top = ''; + var list = cancel ? d.start : d.list; + this.drag = null; + if (!layout.same(list, d.start)) { + this.setLayout(list); + this.announce(_('%s moved').format(this.tileNames[d.id])); + } + else this.doLayout(); + }, + /* ------------------------------------------------------------- head */ buildHead: function() { @@ -718,6 +1103,10 @@ return view.extend({ el.live = E('div', { 'class': 'vt-livepill', 'role': 'status', 'aria-live': 'off' }, [ E('span', { 'class': 'vt-live-beat' }), el.liveText = E('span', { 'class': 'vt-live-text' }) + ]), + el.layoutBtn = E('button', { 'type': 'button', 'class': 'vt-btn vt-btn-ghost vt-layout-btn', 'aria-pressed': 'false', + 'title': _('Arrange the dashboard'), 'click': L.bind(function() { this.setEditing(!this.editing); }, this) }, [ + icon('layout'), E('span', {}, [ _('Layout') ]) ]) ]); }, @@ -728,7 +1117,7 @@ return view.extend({ 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, - clients === 1 ? _('1 client') : _('%d clients').format(clients) ].filter(Boolean).join(' · ')); + this.m.wired ? null : clients === 1 ? _('1 client') : _('%d clients').format(clients) ].filter(Boolean).join(' · ')); }, paintLive: function() { @@ -809,7 +1198,7 @@ return view.extend({ var ap = E('button', { 'type': 'button', 'class': 'vt-node vt-node-ap', 'click': function() { self.openDrawer('device', 'device'); } }, [ E('span', { 'class': 'vt-node-ico' }, [ icon('ap') ]), E('span', { 'class': 'vt-node-body' }, [ - E('span', { 'class': 'vt-node-kicker' }, [ _('This access point') ]), + E('span', { 'class': 'vt-node-kicker' }, [ m.wired ? _('This device') : _('This access point') ]), E('span', { 'class': 'vt-node-title' }, [ d.model ]), E('span', { 'class': 'vt-node-sub vt-mono' }, [ up && up.ipv4[0] ? up.ipv4[0].split('/')[0] : fmt.DASH ]), E('span', { 'class': 'vt-node-sub' }, [ d.uptime != null ? _('up %s').format(fmt.duration(d.uptime)) : '' ]) @@ -850,7 +1239,8 @@ return view.extend({ self.nodes.radios.push({ el: rnode, ssids: ssNodes, active: !!(rr && rr.rx + rr.tx > 50e3), rate: rr ? rr.rx + rr.tx : 0 }); branches.appendChild(E('div', { 'class': 'vt-branch' }, [ rnode, ssidCol ])); }); - if (!m.radios.length) branches.appendChild(E('div', { 'class': 'vt-empty-inline' }, [ _('No radios reported') ])); + if (m.wired) this.netBranches(branches); + else if (!m.radios.length) branches.appendChild(E('div', { 'class': 'vt-empty-inline' }, [ _('No radios reported') ])); this.nodes.upActive = !!(up_r && up_r.rx + up_r.tx > 50e3); this.nodes.upRate = up_r ? up_r.rx + up_r.tx : 0; @@ -861,10 +1251,33 @@ return view.extend({ this.paintKpis(); }, + /* wired-only: the device's other networks take the radios' place, + wired into the path the same way (nodes.radios) */ + netBranches: function(branches) { + var st = this.st, self = this; + var nets = this.m.networks.filter(function(n) { return n.up; }).slice(0, 8); + nets.forEach(function(n) { + var r = n.dev ? st.devRates[n.dev] : null; + var node = E('a', { 'class': 'vt-node vt-node-radio vt-node-net', 'href': L.url.apply(L, insight.PAGES.network), + 'title': [ n.name, n.dev, n.ipv4 ].filter(Boolean).join(' · ') }, [ + E('span', { 'class': 'vt-node-body' }, [ + E('span', { 'class': 'vt-node-kicker' }, [ n.proto || _('Interface') ]), + E('span', { 'class': 'vt-node-title' }, [ n.name ]), + E('span', { 'class': 'vt-node-sub vt-mono' }, [ n.ipv4 ? n.ipv4.split('/')[0] : (n.dev || fmt.DASH) ]), + E('span', { 'class': 'vt-node-sub vt-tn' }, [ r ? '↓ ' + fmt.bitsShort(r.tx) + ' ↑ ' + fmt.bitsShort(r.rx) : fmt.DASH ]) + ]) + ]); + self.nodes.radios.push({ el: node, ssids: [], active: !!(r && r.rx + r.tx > 50e3), rate: r ? r.rx + r.tx : 0 }); + branches.appendChild(E('div', { 'class': 'vt-branch' }, [ node ])); + }); + if (!nets.length) branches.appendChild(E('div', { 'class': 'vt-empty-inline' }, [ _('No other interfaces are up') ])); + }, + /* four numbers under the path: who is here, what flows, where, and who is worst off */ paintKpis: function() { var self = this, m = this.m, st = this.st, up = st.uplinkRate; + if (m.wired) return this.paintNetKpis(); 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(' · '); @@ -872,12 +1285,6 @@ return view.extend({ 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]; - function kpi(label, value, sub, tone, onclick) { - var body = [ E('span', { 'class': 'vt-kpi-label' }, [ label ]), E('span', { 'class': 'vt-kpi-value vt-tn' }, [ value ]), E('span', { 'class': 'vt-kpi-sub' }, [ sub ]) ]; - return onclick - ? E('button', { 'type': 'button', 'class': 'vt-kpi vt-kpi-' + (tone || 'plain'), 'click': onclick }, body) - : E('div', { 'class': 'vt-kpi vt-kpi-' + (tone || 'plain') }, body); - } dom.content(this.el.kpis, [ kpi(_('Clients'), String(m.clients.length), bandText || _('none connected'), 'plain', function() { self.el.clients.scrollIntoView({ behavior: reducedMotion() ? 'auto' : 'smooth', block: 'start' }); }), kpi(_('Traffic now'), up ? '↓ ' + fmt.bits(up.rx) : fmt.DASH, up ? _('↑ %s · via %s').format(fmt.bits(up.tx), m.uplink ? m.uplink.dev : '') : _('measuring'), 'plain', function() { self.openDrawer('uplink', 'uplink'); }), @@ -888,6 +1295,26 @@ return view.extend({ ]); }, + /* wired-only: what flows, how long the uplink has held, which + networks are up and which is busiest */ + paintNetKpis: 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); } + dom.content(this.el.kpis, [ + kpi(_('Traffic now'), up ? '↓ ' + fmt.bits(up.rx) : fmt.DASH, up ? _('↑ %s · via %s').format(fmt.bits(up.tx), link ? link.dev : '') : _('measuring'), 'plain', function() { self.openDrawer('uplink', 'uplink'); }), + kpi(_('Connected for'), link && link.uptime != null ? fmt.duration(link.uptime) : fmt.DASH, link ? [ link.iface, link.proto ].filter(Boolean).join(' · ') : _('no uplink'), 'plain', function() { self.openDrawer('uplink', 'uplink'); }), + kpi(_('Networks'), String(upNets.length), nets.length > upNets.length ? _('%d down').format(nets.length - upNets.length) : _('all up'), 'plain', toNetwork), + busiest ? kpi(_('Busiest network'), busiest.n.name, '↓ ' + fmt.bits(busiest.r.tx) + ' ↑ ' + fmt.bits(busiest.r.rx), 'plain', toNetwork) + : kpi(_('Busiest network'), fmt.DASH, _('no traffic yet'), 'plain') + ]); + }, + scheduleWires: function() { var self = this; if (this.wirePending) return; @@ -1055,13 +1482,8 @@ return view.extend({ el.chartTip = E('div', { 'class': 'vt-tip', 'hidden': 'hidden' }); el.chartOver = E('div', { 'class': 'vt-mult-over', 'aria-hidden': 'true' }, [ el.chartCursor, el.chartTip ]); el.chartX = E('div', { 'class': 'vt-mult-x', 'aria-hidden': 'true' }); - el.chartBtns = {}; - var seg = E('div', { 'class': 'vt-seg-ctl', 'role': 'group', 'aria-label': _('Direction') }, [ 'down', 'up' ].map(function(k) { - return el.chartBtns[k] = E('button', { 'type': 'button', 'class': 'vt-seg-btn', 'aria-pressed': 'false', - 'click': function() { self.ui.chart = k; self.paintChart(); } }, [ icon(k), E('span', {}, [ k === 'down' ? _('Download') : _('Upload') ]) ]); - })); var plot = E('div', { 'class': 'vt-mult-wrap', 'tabindex': '0', 'role': 'group', - 'aria-label': _('Throughput per link; arrow keys read the values over time') }, [ el.chartRows, el.chartOver, el.chartX ]); + 'aria-label': _('Throughput per link, download above the line and upload below; arrow keys read the values over time') }, [ el.chartRows, el.chartOver, el.chartX ]); plot.addEventListener('pointermove', function(ev) { self.chartPointer(ev); }); plot.addEventListener('pointerleave', function() { if (!self.ui.hover || self.ui.hover.x != null) self.chartHide(); }); plot.addEventListener('keydown', function(ev) { self.chartKey(ev); }); @@ -1071,27 +1493,33 @@ return view.extend({ return this.foldable('chart', E('section', { 'class': 'vt-tile vt-chart', 'aria-label': _('Throughput') }, [ E('header', { 'class': 'vt-tile-head' }, [ E('h3', { 'class': 'vt-tile-title' }, [ icon('pulse'), E('span', {}, [ _('Throughput') ]), el.chartSub ]), - E('div', { 'class': 'vt-tile-extra' }, [ seg, this.foldButton('chart', _('Show or hide the throughput chart')) ]) + E('div', { 'class': 'vt-tile-extra' }, [ this.foldButton('chart', _('Show or hide the throughput chart')) ]) ]), plot, el.chartLive ])); }, - /* one small multiple per link: the uplink, then each radio. Each has - its own y scale (a busy uplink would flatten an idle radio), labelled - with its unit, on a shared time axis and crosshair. */ + /* one small multiple per link: the uplink, then each radio. Download + (towards the clients) rises above the middle line, upload hangs + below it; each half has its own y scale (upload is often a hundredth + of download, and a busy uplink would flatten an idle radio), labelled + with its unit, on a shared time axis and crosshair. Columns of a + history point [ t, rx, tx ]: the uplink receives what clients + download, a radio sends it. */ chartSeries: function() { - var m = this.m, down = this.ui.chart === 'down'; - var list = [ { key: 'uplink', label: m.uplink ? _('Uplink %s').format(m.uplink.dev) : _('Uplink'), cls: 'vt-c-up', col: down ? 1 : 2 } ]; - m.radios.forEach(function(r) { list.push({ key: r.id, label: _('%s radio').format(r.bandLabel), cls: 'vt-c-' + (r.band || 'x'), col: down ? 2 : 1 }); }); + var m = this.m; + var list = [ { key: 'uplink', label: m.uplink ? _('Uplink %s').format(m.uplink.dev) : _('Uplink'), cls: 'vt-c-up', dn: 1, up: 2 } ]; + m.radios.forEach(function(r) { list.push({ key: r.id, label: _('%s radio').format(r.bandLabel), cls: 'vt-c-' + (r.band || 'x'), dn: 2, up: 1 }); }); return list; }, paintChart: function() { - var self = this, el = this.el, net = this.st.hist.net, W = 600, H = 100, now = Date.now(); - var list = this.chartSeries(), down = this.ui.chart === 'down'; - Object.keys(el.chartBtns).forEach(function(k) { el.chartBtns[k].setAttribute('aria-pressed', String(self.ui.chart === k)); }); + var el = this.el, net = this.st.hist.net, W = 600, H = 100, M = H / 2, now = Date.now(); + var list = this.chartSeries(); + /* sample times follow the device's clock (model.sampleClock) and + 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); var ticks = []; @@ -1101,42 +1529,54 @@ return view.extend({ dom.content(el.chartRows, list.map(function(s) { var d = (net[s.key] || []).filter(function(p) { return p[0] >= dm.t0 - POLL_S * 1000; }); - var st = series.stats(d, s.col, dm.t0); + 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 vmax = series.niceCeil(Math.max((st.peak || 0) * 1.05, 1000)); - samples = Math.max(samples, st.n); + var vd = series.niceCeil(Math.max((sd.peak || 0) * 1.05, 1000)), vu = series.niceCeil(Math.max((su.peak || 0) * 1.05, 1000)); + samples = Math.max(samples, sd.n); var svg = svgRoot('vt-mult-svg', '0 0 ' + W + ' ' + H); svg.setAttribute('preserveAspectRatio', 'none'); - svg.appendChild(svgPath('M0 0.5H' + W + 'M0 ' + (H / 2) + 'H' + W, 'vt-chart-grid')); + svg.appendChild(svgPath('M0 0.5H' + W + 'M0 ' + (H - 0.5) + 'H' + W, 'vt-chart-grid')); ticks.forEach(function(k) { var x = (1 - k * 60000 / dm.span) * W; svg.appendChild(svgPath('M' + x.toFixed(1) + ' 0V' + H, 'vt-chart-vgrid')); }); - var segs = series.segments(d, s.col, dm.t0, dm.t1, vmax, W, H, POLL_S * 3500); - var area = svgPath(series.areaPath(segs, H), 'vt-series-area'); - area.setAttribute('fill', fadeFill(svg)); - svg.appendChild(area); - svg.appendChild(svgPath(series.linePath(segs), 'vt-series-line')); + /* download: y in [0, M] with 0 at the line; upload mirrored below */ + var segD = series.segments(d, s.dn, dm.t0, dm.t1, vd, W, M, POLL_S * 3500); + var segU = series.segments(d, s.up, dm.t0, dm.t1, vu, W, M, POLL_S * 3500).map(function(seg) { + return seg.map(function(pt) { return [ pt[0], H - pt[1] ]; }); + }); + [ [ segD, false, '' ], [ segU, true, ' vt-dir-up' ] ].forEach(function(h) { + var area = svgPath(series.areaPath(h[0], M), 'vt-series-area' + h[2]); + area.setAttribute('fill', fadeFill(svg, h[1])); + svg.appendChild(area); + svg.appendChild(svgPath(series.linePath(h[0]), 'vt-series-line' + h[2])); + }); + svg.appendChild(svgPath('M0 ' + M + 'H' + W, 'vt-chart-mid')); - var tail = segs.length ? segs[segs.length - 1] : null, pt = tail && tail[tail.length - 1]; - var dot = E('span', { 'class': 'vt-mult-dot', 'hidden': 'hidden' }); - rows.push({ s: s, d: d, vmax: vmax, dot: dot }); + function tailDot(segs, cls) { + var tail = segs.length ? segs[segs.length - 1] : null, pt = tail && tail[tail.length - 1]; + return pt && fresh ? pos(E('span', { 'class': 'vt-sk-dot' + cls }), pt[0] / W * 100, pt[1] / H * 100) : ''; + } + var dotD = E('span', { 'class': 'vt-mult-dot', 'hidden': 'hidden' }), dotU = E('span', { 'class': 'vt-mult-dot vt-dir-up', 'hidden': 'hidden' }); + rows.push({ s: s, d: d, vd: vd, vu: vu, dotD: dotD, dotU: dotU }); return E('div', { 'class': 'vt-mult ' + s.cls }, [ E('div', { 'class': 'vt-mult-head' }, [ E('span', { 'class': 'vt-mult-name' }, [ E('span', { 'class': 'vt-lg-key' }), E('span', {}, [ s.label ]) ]), - E('b', { 'class': 'vt-mult-now vt-tn' }, [ fresh && st.now != null ? fmt.bits(last[s.col]) : fmt.DASH ]), - E('span', { 'class': 'vt-mult-stats vt-tn' }, st.n > 1 ? [ - E('span', {}, [ _('peak'), ' ', E('b', {}, [ fmt.bits(st.peak) ]) ]), - E('span', {}, [ _('avg'), ' ', E('b', {}, [ fmt.bits(st.avg) ]) ]) + E('b', { 'class': 'vt-mult-now vt-tn', 'title': _('Download') }, [ '↓ ', fresh && sd.now != null ? fmt.bits(last[s.dn]) : fmt.DASH ]), + E('b', { 'class': 'vt-mult-now-up vt-tn', 'title': _('Upload') }, [ '↑ ', 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'), ' ', E('b', {}, [ '↓ ' + fmt.bitsShort(sd.peak) ]), ' ', E('b', {}, [ '↑ ' + fmt.bitsShort(su.peak) ]) ]) ] : [ E('span', {}, [ _('measuring…') ]) ]) ]), E('div', { 'class': 'vt-mult-plot' }, [ svg, - st.n ? E('span', { 'class': 'vt-mult-max vt-tn' }, [ bitsLabel(vmax) ]) : '', - st.n < 2 ? E('span', { 'class': 'vt-sk-note' }, [ _('collecting…') ]) : '', - pt && fresh ? pos(E('span', { 'class': 'vt-sk-dot' }), pt[0] / W * 100, pt[1] / H * 100) : '', - dot + sd.n ? E('span', { 'class': 'vt-mult-max vt-tn' }, [ '↓ ' + bitsLabel(vd) ]) : '', + sd.n ? E('span', { 'class': 'vt-mult-max vt-mult-max-up vt-tn' }, [ '↑ ' + bitsLabel(vu) ]) : '', + sd.n < 2 ? E('span', { 'class': 'vt-sk-note' }, [ _('collecting…') ]) : '', + tailDot(segD, ''), + tailDot(segU, ' vt-dir-up'), + dotD, dotU ]) ]); })); @@ -1152,8 +1592,8 @@ return view.extend({ })).concat([ E('span', { 'class': 'vt-mx vt-mx-1' }, [ _('now') ]) ])); var age = dm.age; - txt(el.chartSub, (down ? _('to clients') : _('from clients')) + ' · ' + (dm.full ? _('last 5 min') - : samples < 2 ? _('collecting · first samples') : _('collecting · %s of data').format(spanShort(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); }, @@ -1184,10 +1624,16 @@ return view.extend({ el.chartCursor.hidden = false; el.chartCursor.style.left = x.toFixed(2) + '%'; var tipRows = meta.rows.map(function(r) { - var j = series.nearest(r.d, tp), v = (j >= 0 && Math.abs(r.d[j][0] - tp) < POLL_S * 1000) ? r.d[j][r.s.col] : null; - r.dot.hidden = v == null; - if (v != null) pos(r.dot, x, (1 - Math.min(1, v / r.vmax)) * 100); - return E('div', { 'class': 'vt-tip-row ' + r.s.cls }, [ E('span', { 'class': 'vt-lg-key' }), E('b', { 'class': 'vt-tn' }, [ v == null ? fmt.DASH : fmt.bits(v) ]), E('span', { 'class': 'vt-tip-label' }, [ r.s.label ]) ]); + var j = series.nearest(r.d, tp), p = (j >= 0 && Math.abs(r.d[j][0] - tp) < POLL_S * 1000) ? r.d[j] : null; + var vd = p ? p[r.s.dn] : null, vu = p ? p[r.s.up] : null; + r.dotD.hidden = vd == null; + r.dotU.hidden = vu == null; + if (vd != null) pos(r.dotD, x, (1 - Math.min(1, vd / r.vd)) * 50); + if (vu != null) pos(r.dotU, x, 50 + Math.min(1, vu / r.vu) * 50); + return E('div', { 'class': 'vt-tip-row ' + r.s.cls }, [ E('span', { 'class': 'vt-lg-key' }), + E('b', { 'class': 'vt-tn' }, [ '↓ ' + (vd == null ? fmt.DASH : fmt.bits(vd)) ]), + E('b', { 'class': 'vt-tn vt-tip-up' }, [ '↑ ' + (vu == null ? fmt.DASH : fmt.bits(vu)) ]), + E('span', { 'class': 'vt-tip-label' }, [ r.s.label ]) ]); }); dom.content(el.chartTip, [ E('div', { 'class': 'vt-tip-time vt-tn' }, [ new Date(tp).toLocaleTimeString(), E('span', {}, [ fmt.ago(Date.now() - tp) ]) ]) ].concat(tipRows)); el.chartTip.hidden = false; @@ -1201,7 +1647,7 @@ return view.extend({ this.ui.hover = null; el.chartCursor.hidden = true; el.chartTip.hidden = true; - (this.chartMeta ? this.chartMeta.rows : []).forEach(function(r) { r.dot.hidden = true; }); + (this.chartMeta ? this.chartMeta.rows : []).forEach(function(r) { r.dotD.hidden = true; r.dotU.hidden = true; }); }, chartKey: function(ev) { @@ -1957,8 +2403,12 @@ return view.extend({ this.closeDrawer(); return; } + if (ev.key === 'Escape' && this.editing && !this.drag) { + this.setEditing(false); + return; + } /* 'f' focuses the client filter; '/' and Ctrl+K belong to the theme */ - if ((ev.key === 'f' || ev.key === 'F') && !typing && !ev.ctrlKey && !ev.metaKey && !ev.altKey && !this.ui.drawer) { + if ((ev.key === 'f' || ev.key === 'F') && !typing && !ev.ctrlKey && !ev.metaKey && !ev.altKey && !this.ui.drawer && !this.m.wired) { ev.preventDefault(); this.el.filter.focus(); this.el.filter.select(); diff --git a/luci-app-vantage/po/templates/vantage.pot b/luci-app-vantage/po/templates/vantage.pot index fbe7eee86..bdd53d1ae 100644 --- a/luci-app-vantage/po/templates/vantage.pot +++ b/luci-app-vantage/po/templates/vantage.pot @@ -1,42 +1,43 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1874 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2320 msgid "%d MHz (%d–%d MHz)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:107 msgid "%d SSIDs broadcasting" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:107 msgid "%d SSIDs broadcasting; %d without clients, which is fine" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:92 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106 msgid "%d SSIDs on air" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:92 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106 msgid "%d SSIDs · %d idle" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:731 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:843 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1250 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1120 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1232 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1696 msgid "%d clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1442 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1888 msgid "%d connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:87 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:101 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1312 msgid "%d down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1918 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1919 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2364 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2365 msgid "%d errors" msgstr "" @@ -44,77 +45,81 @@ msgstr "" msgid "%d h ago" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1920 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2366 msgid "%d in · %d out" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:294 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:310 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:288 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:304 msgid "%d min ago" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1442 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1888 msgid "%d of %d" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:89 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1007 +msgid "%d of %d columns" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:103 msgid "%d off" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:236 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:243 msgid "%d older devices (Wi-Fi 4 or earlier) slow airtime" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:870 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1283 msgid "%d on %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1242 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1688 msgid "%d radios" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:294 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:310 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:288 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:304 msgid "%d s ago" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1732 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2178 msgid "%d sent · %s retried · %s failed" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:121 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:128 msgid "%d things need attention" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:91 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 msgid "%d up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:114 msgid "%d weak" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1261 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1707 msgid "%d–%d MHz of the %d–%d MHz band" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:90 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:104 msgid "%s (%s) is disabled" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:88 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:102 msgid "%s (%s) is enabled but not up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1727 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2173 msgid "%s (new this session)" msgstr "" @@ -125,34 +130,34 @@ msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:131 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:103 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1268 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1282 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1486 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1867 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1714 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1728 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1932 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2313 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:50 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51 #: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:168 msgid "%s Mbit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1726 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2172 msgid "%s ago" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:102 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:116 msgid "%s at %s; below %s roaming and throughput suffer" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:77 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1011 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:78 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1438 msgid "%s available" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1287 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1875 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1733 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2321 msgid "%s dBm" msgstr "" @@ -160,146 +165,182 @@ msgstr "" msgid "%s device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:152 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:159 msgid "%s device on a newer radio; uses more airtime per byte" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1694 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2140 msgid "%s experience" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:109 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:89 msgid "%s free" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:109 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:89 msgid "%s free on the overlay (%s used)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 +#: 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/vantage/insight.js:89 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:974 +msgid "%s hidden" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:103 msgid "%s is disabled" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:87 -msgid "%s is not up" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:55 -msgid "%s link" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:49 -msgid "%s negotiated half duplex; check the cable and switch port" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51 -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:78 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1012 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1030 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1946 -msgid "%s of %s" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:79 -msgid "%s of %s available (%s in use)" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:884 -msgid "%s of Wi-Fi traffic" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:147 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:148 -msgid "%s of frames fail" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:148 -msgid "%s of frames to the device fail" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:147 -msgid "%s of frames to the device fail; interference likely" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1944 -msgid "%s over %d cores" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1087 -msgid "%s radio" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:58 -msgid "%s up" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:58 -msgid "%s up at %s" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108 -msgid "%s used" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1038 -msgid "%s used of %s" +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:967 +msgid "%s is narrower" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:101 -msgid "%s · %s" +msgid "%s is not up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1724 -msgid "%s · channel %d · %d MHz" +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:970 +msgid "%s is wider" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:48 -msgid "%s · check cable" +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:56 +msgid "%s link" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1088 +msgid "%s moved" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:964 +msgid "%s moved down" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:955 +msgid "%s moved left" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:958 +msgid "%s moved right" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:961 +msgid "%s moved up" msgstr "" #: 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: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:79 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1439 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1457 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2392 +msgid "%s of %s" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:80 +msgid "%s of %s available (%s in use)" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1291 +msgid "%s of Wi-Fi traffic" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:154 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:155 +msgid "%s of frames fail" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:155 +msgid "%s of frames to the device fail" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:154 +msgid "%s of frames to the device fail; interference likely" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2390 +msgid "%s over %d cores" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1513 +msgid "%s radio" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1013 +msgid "%s shown" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:59 +msgid "%s up" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:59 +msgid "%s up at %s" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:88 +msgid "%s used" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1465 +msgid "%s used of %s" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:115 +msgid "%s · %s" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2170 +msgid "%s · channel %d · %d MHz" +msgstr "" + +#: 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:51 msgid "%s · slow link" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:46 +#: 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:1875 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2321 msgid "(configured %d dBm, limited by regulatory rules)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:842 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1565 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1231 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2011 msgid "(hidden)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:731 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:843 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1250 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1120 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1232 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1696 msgid "1 client" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1442 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1888 msgid "1 connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:236 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:243 msgid "1 older device (Wi-Fi 4 or earlier) slows airtime" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1242 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1688 msgid "1 radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:121 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:128 msgid "1 thing needs attention" msgstr "" @@ -319,19 +360,19 @@ msgstr "" msgid "60 GHz" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1377 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1823 msgid "Active" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1736 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2182 msgid "Address type" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1911 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2357 msgid "Addresses" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1289 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1735 msgid "Airtime" msgstr "" @@ -339,51 +380,62 @@ msgstr "" msgid "Alias" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1373 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1819 msgid "All" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:104 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:118 msgid "All %d clients above %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:103 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 msgid "All above %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:103 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 msgid "All good" msgstr "" +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:920 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:921 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1108 +msgid "Arrange the dashboard" +msgstr "" + #: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 msgid "B" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:884 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1313 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1314 +msgid "Busiest network" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1291 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1292 msgid "Busiest radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:235 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:242 msgid "Busiest radio: %s of Wi-Fi traffic" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:982 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1409 msgid "Busy share of each CPU core" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:69 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:70 msgid "Busy · load %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:70 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:71 msgid "Busy; load %s on %d cores; see the busiest processes" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:67 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:68 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:976 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1944 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:69 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1403 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2390 msgid "CPU" msgstr "" @@ -391,91 +443,93 @@ msgstr "" msgid "Cache (reclaimable)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1812 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2258 msgid "Cancel" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1719 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2165 msgid "Capabilities" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1906 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2352 msgid "Carrier" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1874 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2320 msgid "Centre frequency" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1281 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1727 msgid "Ch %d" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:827 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1249 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1216 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1695 msgid "Ch %d · %d MHz" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1867 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2313 msgid "Channel" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:827 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1216 msgid "Channel —" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1313 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1759 msgid "Clear filter" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:775 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1164 msgid "Click any node for details" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:882 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1286 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1321 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1322 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:776 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1289 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1732 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1767 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1768 msgid "Clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1879 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2325 msgid "Clients on this radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1582 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2028 msgid "Close" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1501 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1947 msgid "Connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1463 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1909 msgid "Connected after you opened this page" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1725 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1311 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2171 msgid "Connected for" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1722 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2168 msgid "Connection" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1004 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1431 msgid "Core %d: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1795 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2241 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:1917 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2363 msgid "Counters since boot" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1877 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2323 msgid "Country" msgstr "" @@ -483,16 +537,16 @@ msgstr "" msgid "DHCP" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2196 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:1915 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2361 msgid "DNS" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:795 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1184 msgid "DNS %s" msgstr "" @@ -501,60 +555,82 @@ 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:1390 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1468 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1935 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1914 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2381 msgid "Device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1779 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2225 msgid "Device name" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1808 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2254 msgid "Device type" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1059 -msgid "Direction" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:828 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1251 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1276 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1872 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1217 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1697 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1722 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318 msgid "Disabled" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1688 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2134 msgid "Disconnected %s; shown from the last sample." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:44 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:828 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1251 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1276 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1872 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:933 +msgid "Done" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:45 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1217 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1697 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1722 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318 msgid "Down" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1061 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566 msgid "Download" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:256 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:264 msgid "Download (to clients)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1730 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2176 msgid "Downloaded" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1920 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:994 +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:995 +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:993 +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:946 +msgid "Drag to move" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2366 msgid "Dropped" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1545 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1991 msgid "Edit" msgstr "" @@ -562,46 +638,46 @@ msgstr "" msgid "Enhanced Open (OWE)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:121 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:128 msgid "Everything looks healthy" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:117 msgid "Excellent" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1495 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1941 msgid "Experience" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:119 msgid "Fair" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:136 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:143 msgid "Fair signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:136 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:143 msgid "Fair signal %s; lower rates at range" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1310 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1756 msgid "Filter by name, address, SSID…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1311 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1757 msgid "Filter clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1938 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2384 msgid "Firmware" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1732 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2178 msgid "Frames to device" msgstr "" @@ -609,20 +685,20 @@ msgstr "" msgid "Free" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1717 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2163 msgid "From device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1484 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1930 msgid "From device: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1901 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2347 msgid "From network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:793 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1914 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1182 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2360 msgid "Gateway" msgstr "" @@ -630,7 +706,7 @@ msgstr "" msgid "Gbit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1718 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2164 msgid "Generation" msgstr "" @@ -638,52 +714,57 @@ msgstr "" msgid "GiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1736 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2182 msgid "Globally unique" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1736 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2182 msgid "Globally unique · %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:118 msgid "Good" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:137 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:144 msgid "Good signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:137 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:144 msgid "Good signal %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:48 +#: 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:633 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:688 msgid "Health checks" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1565 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1010 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2011 msgid "Hidden" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1737 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:973 +msgid "Hide %s" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2183 msgid "IP addresses" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1912 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2358 msgid "IPv4" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1913 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2359 msgid "IPv6" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1734 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2180 msgid "Identity" msgstr "" @@ -691,23 +772,27 @@ msgstr "" msgid "In use" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1909 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1264 +msgid "Interface" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2355 msgid "Interface up for" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1899 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2345 msgid "Interfaces" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:793 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1182 msgid "Internet" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1939 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2385 msgid "Kernel" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1044 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1471 msgid "Kernel %s" msgstr "" @@ -715,68 +800,76 @@ msgstr "" msgid "KiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1726 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2172 msgid "Last activity" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1462 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1109 +msgid "Layout" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:931 +msgid "Layout reset" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1908 msgid "Left %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:152 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1464 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:159 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1910 msgid "Legacy" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1715 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1905 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2161 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2351 msgid "Link" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1483 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1929 msgid "Link rate" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:739 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1488 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1934 msgid "Live" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1943 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2389 msgid "Load" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:70 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:71 msgid "Load %s on %d cores" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:69 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:70 msgid "Load %s · %d cores" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1945 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2391 msgid "Load average" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:965 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1392 msgid "Load average over 1, 5 and 15 minutes" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:999 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1426 msgid "Load avg %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1941 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2387 msgid "Local time" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:142 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:149 msgid "Low link rate %s despite good signal; interference or an old device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:142 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:149 msgid "Low link rate for its signal" msgstr "" @@ -784,7 +877,7 @@ msgstr "" msgid "MAC" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1735 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2181 msgid "MAC address" msgstr "" @@ -792,7 +885,15 @@ msgstr "" msgid "MCS %d" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1752 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:966 +msgid "Make %s narrower" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:969 +msgid "Make %s wider" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2198 msgid "Manufacturer of the network adapter" msgstr "" @@ -800,20 +901,20 @@ msgstr "" msgid "Mbit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:67 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:68 msgid "Measuring over the next poll" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:67 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:68 msgid "Measuring…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:77 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:986 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:78 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1413 msgid "Memory" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1946 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2392 msgid "Memory in use" msgstr "" @@ -821,34 +922,54 @@ msgstr "" msgid "MiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1873 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2319 msgid "Mode" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1936 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2382 msgid "Model" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1807 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:963 +msgid "Move %s down" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:954 +msgid "Move %s left" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:957 +msgid "Move %s right" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:960 +msgid "Move %s up" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:946 +msgid "Move %s: drag, or use the arrow keys" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2253 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:1845 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2291 msgid "Name contains invisible or control characters" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1738 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2184 msgid "Name from" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1473 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1919 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:1846 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2292 msgid "Name is longer than %d characters" msgstr "" @@ -856,86 +977,95 @@ msgstr "" msgid "Name must be text" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1679 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2125 msgid "Name this device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1480 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1723 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1926 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2169 msgid "Network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:774 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:775 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:776 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1163 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1164 msgid "Network path" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1379 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1463 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1312 +msgid "Networks" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1825 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1909 msgid "New" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:849 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1238 msgid "No SSIDs" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:99 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:113 msgid "No clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1447 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1893 msgid "No clients connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1518 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1964 msgid "No clients connected." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1450 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1896 msgid "No clients in this view" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1450 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1896 msgid "No clients match “%s”" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1884 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2330 msgid "No clients; an idle radio is fine." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:238 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:245 msgid "No clients; idle radios are fine" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:794 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1183 msgid "No default route" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:44 +#: 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:1891 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2337 msgid "No interface with a route is up." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:46 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1906 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2352 msgid "No link" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:45 +#: 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/vantage/insight.js:161 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:163 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1273 +msgid "No other interfaces are up" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:168 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:170 msgid "No problems detected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:86 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:853 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1243 msgid "No radios reported" msgstr "" @@ -943,64 +1073,64 @@ msgstr "" msgid "No signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:99 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:113 msgid "No stations are associated right now" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1554 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2000 msgid "No wireless networks configured." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1256 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1702 msgid "No wireless radios are reported by this device." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:99 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:113 msgid "Nobody associated" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1518 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1964 msgid "Nobody is moving data right now." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1288 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1734 msgid "Noise" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1720 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2166 msgid "Noise / SNR" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1876 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2322 msgid "Noise floor" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:237 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:244 msgid "Noise floor not reported by the driver" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:86 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 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:1844 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2290 msgid "Not a station MAC address" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1661 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2107 msgid "Not connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1024 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1451 msgid "Not reported" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1755 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2201 msgid "Nothing better known" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1753 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2199 msgid "Nothing better known; the address is randomised" msgstr "" @@ -1008,15 +1138,15 @@ msgstr "" msgid "OWE" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:153 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:160 msgid "Older %s device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1464 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1910 msgid "Older Wi-Fi generation than the radio; uses more airtime" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 msgid "Online" msgstr "" @@ -1024,7 +1154,7 @@ msgstr "" msgid "Open" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1430 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1876 msgid "Open details of %s" msgstr "" @@ -1032,15 +1162,15 @@ msgstr "" msgid "Open network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:451 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:479 msgid "OpenWrt device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1719 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2165 msgid "PMF" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:737 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1126 msgid "Paused while hidden" msgstr "" @@ -1048,11 +1178,11 @@ msgstr "" msgid "PiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1937 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2383 msgid "Platform" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164 msgid "Poor" msgstr "" @@ -1060,7 +1190,7 @@ msgstr "" msgid "Private" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1736 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2182 msgid "Private Wi-Fi address (randomised by the device)" msgstr "" @@ -1068,174 +1198,184 @@ msgstr "" msgid "Private device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1934 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2380 msgid "Processes" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1908 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2354 msgid "Protocol" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1315 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1761 msgid "Quick filters" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1724 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1871 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2170 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2317 msgid "Radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1277 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1723 msgid "Radio details" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:233 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:240 msgid "Radio is disabled" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:234 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:241 msgid "Radio is enabled but not up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1300 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1865 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1746 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2311 msgid "Radio settings" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1229 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1231 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:776 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1675 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1677 msgid "Radios" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:795 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1184 msgid "Reachability not probed" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1899 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2345 msgid "Realtime graphs" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1918 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2364 msgid "Received" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:738 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1127 msgid "Reconnecting…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1813 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2259 msgid "Remove name" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1679 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2125 msgid "Rename" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1748 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:932 +msgid "Reset" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2194 msgid "Reverse DNS of its address" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:463 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:491 msgid "Root (overlay)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1805 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2251 msgid "Save" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1727 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2173 msgid "Seen since" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1919 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2365 msgid "Sent" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1451 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1012 +msgid "Show %s" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1897 msgid "Show all clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:973 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1400 msgid "Show or hide system details" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:775 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1164 msgid "Show or hide the network path" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1232 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1678 msgid "Show or hide the radio details" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1074 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1496 msgid "Show or hide the throughput chart" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1545 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1991 msgid "Show or hide the wireless networks" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:839 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1561 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1228 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2007 msgid "Show the clients of %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:99 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:103 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1477 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1703 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:113 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:114 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1923 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2149 msgid "Signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:133 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:140 msgid "Signal not reported" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1907 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2353 msgid "Speed" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1448 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1894 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:1872 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318 msgid "Status" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:989 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:88 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1416 msgid "Storage" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1814 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2260 msgid "Stored on this device in /etc/config/vantage" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:163 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:170 msgid "Strong signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:161 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:168 msgid "Strong signal %s, %s link" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:163 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:170 msgid "Strong signal, %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1029 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1456 msgid "Swap" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:972 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:973 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:777 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1399 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1400 msgid "System" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1934 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2380 msgid "System settings" msgstr "" @@ -1243,20 +1383,20 @@ msgstr "" msgid "Tbit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:463 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:491 msgid "Temporary (RAM)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1849 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2295 msgid "The device could not write /etc/config/vantage." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1288 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1734 msgid "" "The driver reports a placeholder value, so no noise floor or SNR is shown" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1751 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2197 msgid "The name the device announces (WPS)" msgstr "" @@ -1264,130 +1404,139 @@ msgstr "" msgid "The stored name has an invalid section id" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:812 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1201 msgid "This access point" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1848 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1201 +msgid "This device" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2294 msgid "This device already stores %d names; remove some first." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:86 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 msgid "This device reports no radios" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1856 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2302 msgid "This radio is not reported any more." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1661 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2107 msgid "This station is not associated right now." msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1071 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1073 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1709 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:776 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1493 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1495 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2155 msgid "Throughput" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1064 -msgid "Throughput per link; arrow keys read the values over time" +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1486 +msgid "" +"Throughput per link, download above the line and upload below; arrow keys " +"read the values over time" msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 msgid "TiB" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1716 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2162 msgid "To device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1492 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1533 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1938 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1979 msgid "To device %s, from device %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1484 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1930 msgid "To device: %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1902 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2348 msgid "To network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1509 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1510 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:777 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1955 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1956 msgid "Top talkers" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1729 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1868 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2175 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2314 msgid "Traffic" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:883 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1290 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1310 msgid "Traffic now" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1287 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1875 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1733 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2321 msgid "Tx power" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1660 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2106 msgid "Unknown device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1847 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2293 msgid "Unknown device type" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1856 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2302 msgid "Unknown radio" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:56 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1276 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1872 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1906 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1722 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2352 msgid "Up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:996 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1423 msgid "Up %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:44 -#: 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:56 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1086 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1891 +#: 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:1512 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2337 msgid "Uplink" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1086 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1512 msgid "Uplink %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1895 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2341 msgid "Uplink · %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1061 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567 msgid "Upload" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:257 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:265 msgid "Upload (from clients)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1731 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2177 msgid "Uploaded" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1940 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2386 msgid "Uptime" msgstr "" @@ -1413,11 +1562,11 @@ msgstr "" msgid "Vendor" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:134 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:141 msgid "Very weak signal %s; expect drops" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:134 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:141 msgid "Very weak signal; expect drops" msgstr "" @@ -1513,7 +1662,7 @@ msgstr "" msgid "WPS" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1739 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2185 msgid "WPS device name" msgstr "" @@ -1521,49 +1670,50 @@ msgstr "" msgid "Weak" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:135 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1378 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:142 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1824 msgid "Weak signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:135 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:142 msgid "Weak signal %s; may roam poorly" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:886 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:887 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1293 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1294 msgid "Weakest signal" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:86 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:87 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:89 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:91 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:101 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:103 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 msgid "Wi-Fi" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1544 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1545 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:777 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1990 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1991 msgid "Wireless networks" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1689 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2135 msgid "Wireless settings" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1747 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2193 msgid "Your name for this device" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1282 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1312 +msgid "all up" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1728 msgid "auto" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1131 -msgid "avg" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1727 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2173 msgid "before this page opened" msgstr "" @@ -1571,16 +1721,16 @@ msgstr "" msgid "bit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1156 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1596 msgid "collecting · %s of data" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1156 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1596 msgid "collecting · first samples" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:197 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1137 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1576 msgid "collecting…" msgstr "" @@ -1588,19 +1738,15 @@ msgstr "" msgid "dBm" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1779 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2225 msgid "e.g. Living room TV" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1155 -msgid "from clients" -msgstr "" - #: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:169 msgid "full duplex" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:59 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:60 msgid "gateway %s" msgstr "" @@ -1608,7 +1754,7 @@ msgstr "" msgid "half duplex" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1570 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2016 msgid "idle" msgstr "" @@ -1620,14 +1766,14 @@ msgstr "" msgid "kbit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:981 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1155 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1408 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1595 msgid "last 5 min" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:153 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:160 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:104 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1486 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1932 msgid "legacy" msgstr "" @@ -1635,83 +1781,89 @@ msgstr "" msgid "mDNS" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1749 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2195 msgid "mDNS announcement" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:883 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1711 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1290 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1310 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2157 msgid "measuring" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1132 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1570 msgid "measuring…" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1292 msgid "no Wi-Fi traffic yet" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:887 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1294 msgid "no clients" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:804 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1314 +msgid "no traffic yet" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1193 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1311 msgid "no uplink" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:882 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1289 msgid "none connected" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1737 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2183 msgid "not known to this AP" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1288 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1289 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1876 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1734 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1735 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2322 msgid "not reported" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1876 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2322 msgid "not reported (driver placeholder %s)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1720 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2166 msgid "not reported by the driver" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1152 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1726 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1592 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2172 msgid "now" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:60 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:61 msgid "now %s down, %s up" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1718 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2164 msgid "older than the radio (%s)" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1130 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1569 msgid "peak" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:982 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1409 msgid "per core" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1705 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2151 msgid "range %s … %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1901 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2347 msgid "received on %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1902 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2348 msgid "sent on %s" msgstr "" @@ -1719,22 +1871,19 @@ msgstr "" msgid "short GI" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1155 -msgid "to clients" -msgstr "" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:815 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1204 msgid "up %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1510 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1956 msgid "who uses the bandwidth" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:883 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1290 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1310 msgid "↑ %s · via %s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1589 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 6aee847eb..bfe8fc291 100644 --- a/luci-app-vantage/po/zh_Hans/vantage.po +++ b/luci-app-vantage/po/zh_Hans/vantage.po @@ -12,42 +12,43 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1874 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2320 msgid "%d MHz (%d–%d MHz)" msgstr "%d MHz(%d–%d MHz)" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:107 msgid "%d SSIDs broadcasting" msgstr "正在广播 %d 个 SSID" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:107 msgid "%d SSIDs broadcasting; %d without clients, which is fine" msgstr "正在广播 %d 个 SSID,%d 个无客户端(正常)" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:92 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106 msgid "%d SSIDs on air" msgstr "%d 个 SSID 正在广播" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:92 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106 msgid "%d SSIDs · %d idle" msgstr "%d 个 SSID · %d 个空闲" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:731 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:843 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1250 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1120 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1232 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1696 msgid "%d clients" msgstr "%d 个客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1442 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1888 msgid "%d connected" msgstr "已连接 %d 个" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:87 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:101 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1312 msgid "%d down" msgstr "%d 个已关闭" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1918 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1919 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2364 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2365 msgid "%d errors" msgstr "%d 个错误" @@ -55,77 +56,81 @@ msgstr "%d 个错误" msgid "%d h ago" msgstr "%d 小时前" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1920 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2366 msgid "%d in · %d out" msgstr "%d 入 · %d 出" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:294 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:310 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:288 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:304 msgid "%d min ago" msgstr "%d 分钟前" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1442 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1888 msgid "%d of %d" msgstr "%d/%d" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:89 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1007 +msgid "%d of %d columns" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:103 msgid "%d off" msgstr "%d 个关闭" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:236 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:243 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:870 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1283 msgid "%d on %s" msgstr "%d 个在 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1242 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1688 msgid "%d radios" msgstr "%d 个射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:294 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:310 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:288 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:304 msgid "%d s ago" msgstr "%d 秒前" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1732 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2178 msgid "%d sent · %s retried · %s failed" msgstr "发送 %d · 重传 %s · 失败 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:121 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:128 msgid "%d things need attention" msgstr "%d 项需要关注" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:91 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 msgid "%d up" msgstr "%d 个已启用" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:114 msgid "%d weak" msgstr "%d 个信号弱" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1261 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1707 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:90 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:104 msgid "%s (%s) is disabled" msgstr "%s(%s)已禁用" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:88 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:102 msgid "%s (%s) is enabled but not up" msgstr "%s(%s)已启用但未上线" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1727 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2173 msgid "%s (new this session)" msgstr "%s(本次新增)" @@ -136,34 +141,34 @@ msgstr "%s Gbit/s" #: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:131 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:103 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1268 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1282 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1486 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1867 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1714 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1728 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1932 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2313 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:50 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51 #: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:168 msgid "%s Mbit/s" msgstr "%s Mbit/s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1726 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2172 msgid "%s ago" msgstr "%s 前" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:102 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:116 msgid "%s at %s; below %s roaming and throughput suffer" msgstr "%s(%s);低于 %s 时漫游和吞吐量会受影响" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:77 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1011 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:78 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1438 msgid "%s available" msgstr "可用 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1287 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1875 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1733 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2321 msgid "%s dBm" msgstr "%s dBm" @@ -171,146 +176,182 @@ msgstr "%s dBm" msgid "%s device" msgstr "%s 设备" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:152 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:159 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:1694 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2140 msgid "%s experience" msgstr "%s 体验" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:109 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:89 msgid "%s free" msgstr "空闲 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:109 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:89 msgid "%s free on the overlay (%s used)" msgstr "overlay 空闲 %s(已用 %s)" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 +#: 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/vantage/insight.js:89 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:974 +msgid "%s hidden" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:103 msgid "%s is disabled" msgstr "%s 已禁用" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:87 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:967 +msgid "%s is narrower" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:101 msgid "%s is not up" msgstr "%s 未上线" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:55 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:970 +msgid "%s is wider" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:56 msgid "%s link" msgstr "%s 链路" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:49 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1088 +msgid "%s moved" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:964 +msgid "%s moved down" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:955 +msgid "%s moved left" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:958 +msgid "%s moved right" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:961 +msgid "%s moved up" +msgstr "" + +#: 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:51 +#: 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:78 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1012 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1030 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1946 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:79 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1439 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1457 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2392 msgid "%s of %s" msgstr "%s / %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:79 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:80 msgid "%s of %s available (%s in use)" msgstr "可用 %s / 共 %s(已用 %s)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:884 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1291 msgid "%s of Wi-Fi traffic" msgstr "占 Wi-Fi 流量的 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:147 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:148 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:154 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:155 msgid "%s of frames fail" msgstr "帧失败率:%s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:148 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:155 msgid "%s of frames to the device fail" msgstr "发往设备的帧失败率:%s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:147 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:154 msgid "%s of frames to the device fail; interference likely" msgstr "发往设备的帧失败率:%s,可能存在干扰" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1944 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2390 msgid "%s over %d cores" msgstr "%s / %d 核" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1087 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1513 msgid "%s radio" msgstr "%s 射频" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:58 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1013 +msgid "%s shown" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:59 msgid "%s up" msgstr "%s 已连接" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:58 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:59 msgid "%s up at %s" msgstr "%s 协商速率为 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:88 msgid "%s used" msgstr "已用 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1038 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1465 msgid "%s used of %s" msgstr "已用 %s / 共 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:101 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:115 msgid "%s · %s" msgstr "%s · %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1724 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2170 msgid "%s · channel %d · %d MHz" msgstr "%s · 信道 %d · %d MHz" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:48 +#: 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:50 +#: 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:46 +#: 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:1875 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2321 msgid "(configured %d dBm, limited by regulatory rules)" msgstr "(配置 %d dBm,受监管规则限制)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:842 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1565 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1231 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2011 msgid "(hidden)" msgstr "(隐藏)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:731 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:843 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1250 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1120 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1232 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1696 msgid "1 client" msgstr "1 个客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1442 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1888 msgid "1 connected" msgstr "已连接 1 个" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:236 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:243 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:1242 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1688 msgid "1 radio" msgstr "1 个射频" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:121 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:128 msgid "1 thing needs attention" msgstr "1 项需要关注" @@ -330,19 +371,19 @@ msgstr "6 GHz" msgid "60 GHz" msgstr "60 GHz" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1377 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1823 msgid "Active" msgstr "活跃" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1736 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2182 msgid "Address type" msgstr "地址类型" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1911 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2357 msgid "Addresses" msgstr "地址" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1289 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1735 msgid "Airtime" msgstr "空口时间" @@ -350,51 +391,62 @@ msgstr "空口时间" msgid "Alias" msgstr "别名" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1373 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1819 msgid "All" msgstr "全部" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:104 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:118 msgid "All %d clients above %s" msgstr "全部 %d 个客户端高于 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:103 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 msgid "All above %s" msgstr "全部高于 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:103 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 msgid "All good" msgstr "全部正常" +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:920 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:921 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1108 +msgid "Arrange the dashboard" +msgstr "" + #: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 msgid "B" msgstr "B" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:884 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1313 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1314 +msgid "Busiest network" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1291 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1292 msgid "Busiest radio" msgstr "最繁忙射频" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:235 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:242 msgid "Busiest radio: %s of Wi-Fi traffic" msgstr "最繁忙射频:占 Wi-Fi 流量的 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:982 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1409 msgid "Busy share of each CPU core" msgstr "每个 CPU 核心的繁忙占比" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:69 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:70 msgid "Busy · load %s" msgstr "繁忙 · 负载 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:70 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:71 msgid "Busy; load %s on %d cores; see the busiest processes" msgstr "繁忙;负载 %s(%d 核);查看最繁忙进程" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:67 #: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:68 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:976 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1944 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:69 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1403 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2390 msgid "CPU" msgstr "CPU" @@ -402,91 +454,93 @@ msgstr "CPU" msgid "Cache (reclaimable)" msgstr "缓存(可回收)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1812 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2258 msgid "Cancel" msgstr "取消" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1719 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2165 msgid "Capabilities" msgstr "能力" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1906 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2352 msgid "Carrier" msgstr "链路状态" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1874 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2320 msgid "Centre frequency" msgstr "中心频率" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1281 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1727 msgid "Ch %d" msgstr "信道 %d" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:827 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1249 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1216 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1695 msgid "Ch %d · %d MHz" msgstr "信道 %d · %d MHz" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1867 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2313 msgid "Channel" msgstr "信道" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:827 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1216 msgid "Channel —" msgstr "信道 —" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1313 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1759 msgid "Clear filter" msgstr "清除筛选" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:775 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1164 msgid "Click any node for details" msgstr "点击任意节点查看详情" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:882 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1286 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1321 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1322 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:776 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1289 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1732 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1767 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1768 msgid "Clients" msgstr "客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1879 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2325 msgid "Clients on this radio" msgstr "此射频上的客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1582 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2028 msgid "Close" msgstr "关闭" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1501 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1947 msgid "Connected" msgstr "已连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1463 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1909 msgid "Connected after you opened this page" msgstr "打开本页面后连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1725 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1311 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2171 msgid "Connected for" msgstr "已连接时长" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1722 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2168 msgid "Connection" msgstr "连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1004 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1431 msgid "Core %d: %s" msgstr "核心 %d:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1795 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2241 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:1917 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2363 msgid "Counters since boot" msgstr "自启动以来的计数器" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1877 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2323 msgid "Country" msgstr "国家" @@ -494,16 +548,16 @@ msgstr "国家" msgid "DHCP" msgstr "DHCP" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1750 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2196 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:1915 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2361 msgid "DNS" msgstr "DNS" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:795 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1184 msgid "DNS %s" msgstr "DNS %s" @@ -512,60 +566,82 @@ 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:1390 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1468 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1935 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1914 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2381 msgid "Device" msgstr "设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1779 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2225 msgid "Device name" msgstr "设备名" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1808 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2254 msgid "Device type" msgstr "设备类型" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1059 -msgid "Direction" -msgstr "方向" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:828 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1251 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1276 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1872 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1217 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1697 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1722 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318 msgid "Disabled" msgstr "已禁用" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1688 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2134 msgid "Disconnected %s; shown from the last sample." msgstr "断开于 %s;显示来自最后一次采样。" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:44 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:828 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1251 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1276 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1872 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:933 +msgid "Done" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:45 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1217 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1697 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1722 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318 msgid "Down" msgstr "断开" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1061 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566 msgid "Download" msgstr "下载" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:256 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:264 msgid "Download (to clients)" msgstr "下载(到客户端)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1730 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2176 msgid "Downloaded" msgstr "已下载" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1920 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:994 +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:995 +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:993 +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:946 +msgid "Drag to move" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2366 msgid "Dropped" msgstr "已丢弃" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1545 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1991 msgid "Edit" msgstr "编辑" @@ -573,46 +649,46 @@ msgstr "编辑" msgid "Enhanced Open (OWE)" msgstr "增强开放 (OWE)" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:121 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:128 msgid "Everything looks healthy" msgstr "一切看起来正常" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:117 msgid "Excellent" msgstr "极好" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1495 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1941 msgid "Experience" msgstr "体验" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:119 msgid "Fair" msgstr "一般" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:136 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:143 msgid "Fair signal" msgstr "信号一般" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:136 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:143 msgid "Fair signal %s; lower rates at range" msgstr "信号一般 %s;远距离速率较低" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1310 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1756 msgid "Filter by name, address, SSID…" msgstr "按名称、地址、SSID…筛选" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1311 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1757 msgid "Filter clients" msgstr "筛选客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1938 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2384 msgid "Firmware" msgstr "固件" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1732 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2178 msgid "Frames to device" msgstr "发往设备的帧" @@ -620,20 +696,20 @@ msgstr "发往设备的帧" msgid "Free" msgstr "空闲" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1717 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2163 msgid "From device" msgstr "来自设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1484 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1930 msgid "From device: %s" msgstr "来自设备:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1901 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2347 msgid "From network" msgstr "来自网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:793 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1914 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1182 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2360 msgid "Gateway" msgstr "网关" @@ -641,7 +717,7 @@ msgstr "网关" msgid "Gbit/s" msgstr "Gbit/s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1718 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2164 msgid "Generation" msgstr "代际" @@ -649,52 +725,57 @@ msgstr "代际" msgid "GiB" msgstr "GiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1736 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2182 msgid "Globally unique" msgstr "全局唯一" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1736 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2182 msgid "Globally unique · %s" msgstr "全局唯一 · %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:118 msgid "Good" msgstr "良好" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:137 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:144 msgid "Good signal" msgstr "信号良好" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:137 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:144 msgid "Good signal %s" msgstr "信号良好 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:48 +#: 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:633 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:688 msgid "Health checks" msgstr "健康检查" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1565 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1010 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2011 msgid "Hidden" msgstr "隐藏" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1737 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:973 +msgid "Hide %s" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2183 msgid "IP addresses" msgstr "IP 地址" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1912 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2358 msgid "IPv4" msgstr "IPv4" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1913 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2359 msgid "IPv6" msgstr "IPv6" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1734 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2180 msgid "Identity" msgstr "身份" @@ -702,23 +783,27 @@ msgstr "身份" msgid "In use" msgstr "使用中" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1909 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1264 +msgid "Interface" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2355 msgid "Interface up for" msgstr "接口已启用时长" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1899 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2345 msgid "Interfaces" msgstr "接口" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:793 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1182 msgid "Internet" msgstr "互联网" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1939 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2385 msgid "Kernel" msgstr "内核" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1044 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1471 msgid "Kernel %s" msgstr "内核 %s" @@ -726,68 +811,76 @@ msgstr "内核 %s" msgid "KiB" msgstr "KiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1726 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2172 msgid "Last activity" msgstr "最后活动" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1462 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1109 +msgid "Layout" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:931 +msgid "Layout reset" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1908 msgid "Left %s" msgstr "离开于 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:152 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1464 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:159 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1910 msgid "Legacy" msgstr "旧版" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1715 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1905 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2161 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2351 msgid "Link" msgstr "链路" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1483 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1929 msgid "Link rate" msgstr "链路速率" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:739 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1488 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1128 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1934 msgid "Live" msgstr "实时" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1943 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2389 msgid "Load" msgstr "负载" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:70 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:71 msgid "Load %s on %d cores" msgstr "负载 %s(%d 核)" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:69 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:70 msgid "Load %s · %d cores" msgstr "负载 %s · %d 核" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1945 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2391 msgid "Load average" msgstr "平均负载" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:965 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1392 msgid "Load average over 1, 5 and 15 minutes" msgstr "1、5、15 分钟平均负载" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:999 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1426 msgid "Load avg %s" msgstr "平均负载 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1941 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2387 msgid "Local time" msgstr "本地时间" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:142 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:149 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:142 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:149 msgid "Low link rate for its signal" msgstr "相对其信号链路速率偏低" @@ -795,7 +888,7 @@ msgstr "相对其信号链路速率偏低" msgid "MAC" msgstr "MAC" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1735 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2181 msgid "MAC address" msgstr "MAC 地址" @@ -803,7 +896,15 @@ msgstr "MAC 地址" msgid "MCS %d" msgstr "MCS %d" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1752 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:966 +msgid "Make %s narrower" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:969 +msgid "Make %s wider" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2198 msgid "Manufacturer of the network adapter" msgstr "网卡制造商" @@ -811,20 +912,20 @@ msgstr "网卡制造商" msgid "Mbit/s" msgstr "Mbit/s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:67 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:68 msgid "Measuring over the next poll" msgstr "下次轮询中测量" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:67 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:68 msgid "Measuring…" msgstr "测量中…" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:77 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:986 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:78 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1413 msgid "Memory" msgstr "内存" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1946 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2392 msgid "Memory in use" msgstr "已用内存" @@ -832,34 +933,54 @@ msgstr "已用内存" msgid "MiB" msgstr "MiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1873 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2319 msgid "Mode" msgstr "模式" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1936 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2382 msgid "Model" msgstr "型号" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1807 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:963 +msgid "Move %s down" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:954 +msgid "Move %s left" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:957 +msgid "Move %s right" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:960 +msgid "Move %s up" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:946 +msgid "Move %s: drag, or use the arrow keys" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2253 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:1845 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2291 msgid "Name contains invisible or control characters" msgstr "名称包含不可见或控制字符" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1738 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2184 msgid "Name from" msgstr "名称来源" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1473 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1919 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:1846 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2292 msgid "Name is longer than %d characters" msgstr "名称超过 %d 个字符" @@ -867,86 +988,95 @@ msgstr "名称超过 %d 个字符" msgid "Name must be text" msgstr "名称必须是文本" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1679 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2125 msgid "Name this device" msgstr "命名此设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1480 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1723 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1926 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2169 msgid "Network" msgstr "网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:774 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:775 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:776 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1163 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1164 msgid "Network path" msgstr "网络路径" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1379 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1463 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1312 +msgid "Networks" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1825 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1909 msgid "New" msgstr "新增" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:849 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1238 msgid "No SSIDs" msgstr "无 SSID" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:99 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:113 msgid "No clients" msgstr "无客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1447 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1893 msgid "No clients connected" msgstr "无客户端连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1518 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1964 msgid "No clients connected." msgstr "没有客户端连接。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1450 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1896 msgid "No clients in this view" msgstr "此视图中没有客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1450 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1896 msgid "No clients match “%s”" msgstr "没有匹配“%s”的客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1884 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2330 msgid "No clients; an idle radio is fine." msgstr "无客户端;空闲的射频是正常的。" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:238 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:245 msgid "No clients; idle radios are fine" msgstr "无客户端;空闲的射频是正常的" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:794 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1183 msgid "No default route" msgstr "无默认路由" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:44 +#: 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:1891 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2337 msgid "No interface with a route is up." msgstr "没有带路由的接口处于启用状态。" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:46 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1906 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2352 msgid "No link" msgstr "无链路" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:45 +#: 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/vantage/insight.js:161 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:163 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1273 +msgid "No other interfaces are up" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:168 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:170 msgid "No problems detected" msgstr "未检测到问题" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:86 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:853 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1243 msgid "No radios reported" msgstr "未报告射频" @@ -954,64 +1084,64 @@ msgstr "未报告射频" msgid "No signal" msgstr "无信号" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:99 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:113 msgid "No stations are associated right now" msgstr "当前没有站点关联" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1554 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2000 msgid "No wireless networks configured." msgstr "未配置无线网络。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1256 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1702 msgid "No wireless radios are reported by this device." msgstr "此设备未报告任何无线射频。" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:99 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:113 msgid "Nobody associated" msgstr "无关联站点" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1518 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1964 msgid "Nobody is moving data right now." msgstr "当前没有设备在传输数据。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1288 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1734 msgid "Noise" msgstr "噪声" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1720 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2166 msgid "Noise / SNR" msgstr "噪声 / 信噪比" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1876 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2322 msgid "Noise floor" msgstr "噪声底" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:237 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:244 msgid "Noise floor not reported by the driver" msgstr "驱动未报告噪声底" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:86 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 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:1844 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2290 msgid "Not a station MAC address" msgstr "不是站点 MAC 地址" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1661 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2107 msgid "Not connected" msgstr "未连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1024 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1451 msgid "Not reported" msgstr "未报告" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1755 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2201 msgid "Nothing better known" msgstr "无更多信息" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1753 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2199 msgid "Nothing better known; the address is randomised" msgstr "无更多信息;地址已随机化" @@ -1019,15 +1149,15 @@ msgstr "无更多信息;地址已随机化" msgid "OWE" msgstr "OWE" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:153 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:160 msgid "Older %s device" msgstr "较旧的 %s 设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1464 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1910 msgid "Older Wi-Fi generation than the radio; uses more airtime" msgstr "比射频支持的 Wi-Fi 代际更旧;占用更多空口时间" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 msgid "Online" msgstr "在线" @@ -1035,7 +1165,7 @@ msgstr "在线" msgid "Open" msgstr "开放" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1430 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1876 msgid "Open details of %s" msgstr "打开 %s 的详情" @@ -1043,15 +1173,15 @@ msgstr "打开 %s 的详情" msgid "Open network" msgstr "开放网络" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:451 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:479 msgid "OpenWrt device" msgstr "OpenWrt 设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1719 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2165 msgid "PMF" msgstr "PMF" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:737 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1126 msgid "Paused while hidden" msgstr "隐藏时暂停" @@ -1059,11 +1189,11 @@ msgstr "隐藏时暂停" msgid "PiB" msgstr "PiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1937 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2383 msgid "Platform" msgstr "平台" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164 msgid "Poor" msgstr "较差" @@ -1071,7 +1201,7 @@ msgstr "较差" msgid "Private" msgstr "私有" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1736 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2182 msgid "Private Wi-Fi address (randomised by the device)" msgstr "私有 Wi-Fi 地址(设备随机化)" @@ -1079,174 +1209,184 @@ msgstr "私有 Wi-Fi 地址(设备随机化)" msgid "Private device" msgstr "私有设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1934 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2380 msgid "Processes" msgstr "进程" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1908 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2354 msgid "Protocol" msgstr "协议" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1315 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1761 msgid "Quick filters" msgstr "快速筛选" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1724 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1871 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2170 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2317 msgid "Radio" msgstr "射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1277 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1723 msgid "Radio details" msgstr "射频详情" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:233 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:240 msgid "Radio is disabled" msgstr "射频已禁用" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:234 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:241 msgid "Radio is enabled but not up" msgstr "射频已启用但未上线" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1300 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1865 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1746 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2311 msgid "Radio settings" msgstr "射频设置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1229 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1231 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:776 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1675 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1677 msgid "Radios" msgstr "射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:795 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1184 msgid "Reachability not probed" msgstr "未探测可达性" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1899 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2345 msgid "Realtime graphs" msgstr "实时图表" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1918 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2364 msgid "Received" msgstr "已接收" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:738 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1127 msgid "Reconnecting…" msgstr "重新连接中…" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1813 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2259 msgid "Remove name" msgstr "移除名称" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1679 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2125 msgid "Rename" msgstr "重命名" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1748 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:932 +msgid "Reset" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2194 msgid "Reverse DNS of its address" msgstr "其地址的反向 DNS" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:463 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:491 msgid "Root (overlay)" msgstr "Root(overlay)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1805 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2251 msgid "Save" msgstr "保存" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1727 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2173 msgid "Seen since" msgstr "首次出现" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1919 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2365 msgid "Sent" msgstr "已发送" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1451 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1012 +msgid "Show %s" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1897 msgid "Show all clients" msgstr "显示全部客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:973 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1400 msgid "Show or hide system details" msgstr "显示/隐藏系统详情" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:775 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1164 msgid "Show or hide the network path" msgstr "显示/隐藏网络路径" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1232 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1678 msgid "Show or hide the radio details" msgstr "显示/隐藏射频详情" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1074 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1496 msgid "Show or hide the throughput chart" msgstr "显示/隐藏吞吐量图表" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1545 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1991 msgid "Show or hide the wireless networks" msgstr "显示/隐藏无线网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:839 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1561 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1228 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2007 msgid "Show the clients of %s" msgstr "显示 %s 的客户端" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:99 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:103 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1477 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1703 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:113 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:114 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:117 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1836 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1923 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2149 msgid "Signal" msgstr "信号强度" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:133 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:140 msgid "Signal not reported" msgstr "未报告信号" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1907 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2353 msgid "Speed" msgstr "速率" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1448 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1894 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:1872 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318 msgid "Status" msgstr "状态" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:989 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:88 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1416 msgid "Storage" msgstr "存储" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1814 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2260 msgid "Stored on this device in /etc/config/vantage" msgstr "保存在本设备 /etc/config/vantage 中" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:163 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:170 msgid "Strong signal" msgstr "信号强" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:161 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:168 msgid "Strong signal %s, %s link" msgstr "信号强 %s,链路 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:163 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:170 msgid "Strong signal, %s" msgstr "信号强,%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1029 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1456 msgid "Swap" msgstr "交换分区" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:972 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:973 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:777 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1399 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1400 msgid "System" msgstr "系统" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1934 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2380 msgid "System settings" msgstr "系统设置" @@ -1254,20 +1394,20 @@ msgstr "系统设置" msgid "Tbit/s" msgstr "Tbit/s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:463 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:491 msgid "Temporary (RAM)" msgstr "临时(RAM)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1849 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2295 msgid "The device could not write /etc/config/vantage." msgstr "设备无法写入 /etc/config/vantage。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1288 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1734 msgid "" "The driver reports a placeholder value, so no noise floor or SNR is shown" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1751 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2197 msgid "The name the device announces (WPS)" msgstr "设备广播的名称(WPS)" @@ -1275,130 +1415,139 @@ msgstr "设备广播的名称(WPS)" msgid "The stored name has an invalid section id" msgstr "保存的名称包含无效的节 ID" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:812 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1201 msgid "This access point" msgstr "此接入点" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1848 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1201 +msgid "This device" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2294 msgid "This device already stores %d names; remove some first." msgstr "此设备已存储 %d 个名称;请先移除部分。" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:86 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 msgid "This device reports no radios" msgstr "此设备未报告任何射频" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1856 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2302 msgid "This radio is not reported any more." msgstr "此射频不再被报告。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1661 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2107 msgid "This station is not associated right now." msgstr "此站点当前未关联。" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1071 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1073 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1709 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:776 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1493 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1495 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2155 msgid "Throughput" msgstr "吞吐量" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1064 -msgid "Throughput per link; arrow keys read the values over time" -msgstr "每条链路的吞吐量;方向键可查看历史值" +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1486 +msgid "" +"Throughput per link, download above the line and upload below; arrow keys " +"read the values over time" +msgstr "" #: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:53 msgid "TiB" msgstr "TiB" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1716 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2162 msgid "To device" msgstr "到设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1492 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1533 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1938 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1979 msgid "To device %s, from device %s" msgstr "到设备 %s,来自设备 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1484 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1930 msgid "To device: %s" msgstr "到设备:%s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1902 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2348 msgid "To network" msgstr "发往网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1509 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1510 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:777 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1955 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1956 msgid "Top talkers" msgstr "流量大户" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1729 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1868 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2175 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2314 msgid "Traffic" msgstr "流量" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:883 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1290 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1310 msgid "Traffic now" msgstr "当前流量" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1287 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1875 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1733 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2321 msgid "Tx power" msgstr "发射功率" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1660 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2106 msgid "Unknown device" msgstr "未知设备" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1847 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2293 msgid "Unknown device type" msgstr "未知设备类型" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1856 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2302 msgid "Unknown radio" msgstr "未知射频" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:56 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1276 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1872 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1906 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1722 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2352 msgid "Up" msgstr "正常" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:996 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1423 msgid "Up %s" msgstr "已运行 %s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:44 -#: 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:56 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1086 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1891 +#: 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:1512 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2337 msgid "Uplink" msgstr "上行链路" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1086 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1512 msgid "Uplink %s" msgstr "上行 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1895 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2341 msgid "Uplink · %s" msgstr "上行 · %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1061 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567 msgid "Upload" msgstr "上传" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:257 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:265 msgid "Upload (from clients)" msgstr "上传(来自客户端)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1731 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2177 msgid "Uploaded" msgstr "已上传" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1940 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2386 msgid "Uptime" msgstr "运行时间" @@ -1424,11 +1573,11 @@ msgstr "" msgid "Vendor" msgstr "供应商" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:134 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:141 msgid "Very weak signal %s; expect drops" msgstr "信号极弱 %s;可能出现掉线" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:134 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:141 msgid "Very weak signal; expect drops" msgstr "信号极弱;可能出现掉线" @@ -1524,7 +1673,7 @@ msgstr "WPA3 个人版" msgid "WPS" msgstr "WPS" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1739 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2185 msgid "WPS device name" msgstr "WPS 设备名称" @@ -1532,49 +1681,50 @@ msgstr "WPS 设备名称" msgid "Weak" msgstr "弱" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:135 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1378 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:142 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1824 msgid "Weak signal" msgstr "信号弱" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:135 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:142 msgid "Weak signal %s; may roam poorly" msgstr "信号弱 %s;漫游可能不佳" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:886 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:887 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1293 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1294 msgid "Weakest signal" msgstr "最弱信号" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:86 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:87 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:89 -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:91 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:100 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:101 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:103 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105 msgid "Wi-Fi" msgstr "Wi-Fi" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1544 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1545 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:777 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1990 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1991 msgid "Wireless networks" msgstr "无线网络" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1689 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2135 msgid "Wireless settings" msgstr "无线设置" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1747 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2193 msgid "Your name for this device" msgstr "你为此设备设置的名称" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1282 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1312 +msgid "all up" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1728 msgid "auto" msgstr "自动" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1131 -msgid "avg" -msgstr "平均" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1727 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2173 msgid "before this page opened" msgstr "打开本页之前" @@ -1582,16 +1732,16 @@ msgstr "打开本页之前" msgid "bit/s" msgstr "bit/s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1156 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1596 msgid "collecting · %s of data" msgstr "采集中 · 已采集 %s 数据" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1156 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1596 msgid "collecting · first samples" msgstr "采集中 · 首个样本" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:197 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1137 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:205 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1576 msgid "collecting…" msgstr "采集中…" @@ -1599,19 +1749,15 @@ msgstr "采集中…" msgid "dBm" msgstr "dBm" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1779 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2225 msgid "e.g. Living room TV" msgstr "例如:客厅电视" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1155 -msgid "from clients" -msgstr "来自客户端" - #: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:169 msgid "full duplex" msgstr "全双工" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:59 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:60 msgid "gateway %s" msgstr "网关 %s" @@ -1619,7 +1765,7 @@ msgstr "网关 %s" msgid "half duplex" msgstr "半双工" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1570 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2016 msgid "idle" msgstr "空闲" @@ -1631,14 +1777,14 @@ msgstr "刚刚" msgid "kbit/s" msgstr "kbit/s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:981 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1155 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1408 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1595 msgid "last 5 min" msgstr "最近 5 分钟" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:153 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:160 #: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:104 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1486 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1932 msgid "legacy" msgstr "旧版" @@ -1646,83 +1792,89 @@ msgstr "旧版" msgid "mDNS" msgstr "mDNS" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1749 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2195 msgid "mDNS announcement" msgstr "mDNS 广播" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:883 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1711 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1290 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1310 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2157 msgid "measuring" msgstr "测量中" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1132 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1570 msgid "measuring…" msgstr "测量中…" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:885 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1292 msgid "no Wi-Fi traffic yet" msgstr "尚无 Wi-Fi 流量" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:887 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1294 msgid "no clients" msgstr "无客户端" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:804 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1314 +msgid "no traffic yet" +msgstr "" + +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1193 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1311 msgid "no uplink" msgstr "无上行链路" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:882 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1289 msgid "none connected" msgstr "无连接" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1737 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2183 msgid "not known to this AP" msgstr "此 AP 未知" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1288 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1289 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1876 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1734 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1735 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2322 msgid "not reported" msgstr "未报告" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1876 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2322 msgid "not reported (driver placeholder %s)" msgstr "未报告(驱动占位 %s)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1720 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2166 msgid "not reported by the driver" msgstr "驱动未报告" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1152 -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1726 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1592 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2172 msgid "now" msgstr "现在" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:60 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:61 msgid "now %s down, %s up" msgstr "当前下行 %s,上行 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1718 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2164 msgid "older than the radio (%s)" msgstr "比射频支持的标准更旧(%s)" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1130 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1569 msgid "peak" msgstr "峰值" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:982 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1409 msgid "per core" msgstr "每核" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1705 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2151 msgid "range %s … %s" msgstr "范围 %s … %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1901 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2347 msgid "received on %s" msgstr "在 %s 上接收" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1902 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2348 msgid "sent on %s" msgstr "在 %s 上发送" @@ -1730,26 +1882,38 @@ msgstr "在 %s 上发送" msgid "short GI" msgstr "短 GI" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1155 -msgid "to clients" -msgstr "发往客户端" - -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:815 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1204 msgid "up %s" msgstr "已运行 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1510 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1956 msgid "who uses the bandwidth" msgstr "带宽使用者" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:883 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1290 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1310 msgid "↑ %s · via %s" msgstr "↑ %s · 经 %s" -#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149 +#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1589 msgid "−%d min" msgstr "−%d 分钟" +#~ msgid "Direction" +#~ msgstr "方向" + +#~ msgid "Throughput per link; arrow keys read the values over time" +#~ msgstr "每条链路的吞吐量;方向键可查看历史值" + +#~ msgid "avg" +#~ msgstr "平均" + +#~ msgid "from clients" +#~ msgstr "来自客户端" + +#~ msgid "to clients" +#~ msgstr "发往客户端" + #, javascript-format #~ msgid "%d MHz" #~ msgstr "%d MHz" diff --git a/luci-theme-vantage/Makefile b/luci-theme-vantage/Makefile index ab0d843db..20ab00287 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.1 -PKG_RELEASE:=14 +PKG_VERSION:=1.0.2 +PKG_RELEASE:=15 PKG_LICENSE:=GPL-3.0-or-later LUCI_TITLE:=Vantage theme diff --git a/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css b/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css index eb749e6f2..0f0478287 100644 --- a/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css +++ b/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css @@ -140,6 +140,8 @@ html[data-darkmode="true"] { --v-r: var(--r); --v-r-lg: var(--r-lg); --v-shadow: 0 1px 2px rgba(20, 23, 26, .06), 0 1px 0 rgba(20, 23, 26, .03); + /* where sticky content may start: below the top bar and page tabs */ + --v-stick-top: var(--stick-top); /* charts (stock realtime graphs, channel analysis, the dashboard app). Categorical, fixed order, never cycled by rank: lime (the accent, series 1