diff --git a/clashoo/Makefile b/clashoo/Makefile
index 8f838e117..83140a310 100644
--- a/clashoo/Makefile
+++ b/clashoo/Makefile
@@ -6,13 +6,13 @@ PKG_UPSTREAM_TAG:=v$(PKG_UPSTREAM_VERSION)
PKG_SHORT_SHA:=3f27ef3
PKG_VERSION:=2026.11.04.$(PKG_UPSTREAM_VERSION)
-PKG_RELEASE:=24
+PKG_RELEASE:=25
PKG_SOURCE:=$(PKG_NAME)-stable-$(PKG_UPSTREAM_TAG)-$(PKG_SHORT_SHA).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-stable-$(PKG_UPSTREAM_TAG)-$(PKG_SHORT_SHA)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_SOURCE_SUBDIR)
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-clashoo/releases/download/mihomo-src
-PKG_SOURCE_VERSION:=f03c662c952072d2e7bdae30e6ab5a0360606266
+PKG_SOURCE_VERSION:=3b0c0d7f9e5fa5d086fcd45cc211380ad6ccb077
PKG_HASH:=skip
PKG_BUILD_VERSION:=$(PKG_UPSTREAM_TAG)
diff --git a/dae/Makefile b/dae/Makefile
index 59bde7c20..8d62c0f85 100644
--- a/dae/Makefile
+++ b/dae/Makefile
@@ -5,10 +5,10 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=dae
-PKG_VERSION:=2026.10.30
-PKG_RELEASE:=53
+PKG_VERSION:=2026.11.05
+PKG_RELEASE:=54
-PKG_SOURCE:=dae-src-2026.10.30-55c59e68c059.tar.gz
+PKG_SOURCE:=dae-src-2026.11.05-7cf97ff42dc6.tar.gz
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/dae-src
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_HASH:=skip
diff --git a/daed/Makefile b/daed/Makefile
index 04e221940..ae25fad28 100644
--- a/daed/Makefile
+++ b/daed/Makefile
@@ -5,10 +5,10 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=daed
-PKG_VERSION:=2026.10.30
-PKG_RELEASE:=65
+PKG_VERSION:=2026.11.05
+PKG_RELEASE:=66
-PKG_SOURCE:=daed-src-2026.10.30-1850c01d032c.tar.gz
+PKG_SOURCE:=daed-src-2026.11.05-b1e30bc02200.tar.gz
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_HASH:=skip
diff --git a/istoreenhance/Makefile b/istoreenhance/Makefile
index f573495a0..1d9af408b 100644
--- a/istoreenhance/Makefile
+++ b/istoreenhance/Makefile
@@ -11,8 +11,8 @@ PKG_ARCH_ISTOREENHANCE:=$(ARCH)
PKG_NAME:=istoreenhance
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
-PKG_SOURCE_DATE:=0.8.5
-PKG_RELEASE:=14
+PKG_SOURCE_DATE:=0.8.8
+PKG_RELEASE:=15
ARCH_HEXCODE:=
ifeq ($(ARCH),x86_64)
ARCH_HEXCODE=8664
@@ -88,11 +88,8 @@ define Package/$(PKG_NAME)/install
$(INSTALL_BIN) ./files/istoreenhance.init $(1)/etc/init.d/istoreenhance
$(INSTALL_BIN) ./files/istoreenhance.uci-default $(1)/etc/uci-defaults/istoreenhance
$(INSTALL_DATA) ./files/kspeeder-plugin.json $(1)/usr/share/kspeeder/kspeeder-plugin.json
- if [ -d "$(KSPEEDER_WEB_ROOT)" ] && [ -f "$(KSPEEDER_WEB_ROOT)/desktop-entry.js" ]; then \
+ if [ -d "$(KSPEEDER_WEB_ROOT)" ] && [ -f "$(KSPEEDER_WEB_ROOT)/index.html" ]; then \
$(CP) $(KSPEEDER_WEB_ROOT)/* $(1)/usr/share/kspeeder/www/; \
- else \
- $(INSTALL_DATA) ./files/www/desktop-entry.js $(1)/usr/share/kspeeder/www/desktop-entry.js; \
- $(INSTALL_DATA) ./files/www/index.html $(1)/usr/share/kspeeder/www/index.html; \
fi
$(INSTALL_DATA) ./files/logo.png $(1)/usr/share/kspeeder/www/logo.png
ln -sf /usr/share/kspeeder/kspeeder-plugin.json $(1)/usr/share/linkeasefull/desktop-apps.d/20-kspeeder.json
diff --git a/istoreenhance/files/kspeeder-plugin.json b/istoreenhance/files/kspeeder-plugin.json
index e61e486b7..bd2fcf73b 100644
--- a/istoreenhance/files/kspeeder-plugin.json
+++ b/istoreenhance/files/kspeeder-plugin.json
@@ -5,9 +5,23 @@
"icon": "logo.png",
"staticRoot": "/usr/share/kspeeder/www",
"desktop": {
- "mode": "module",
- "entry": "desktop-entry.js",
- "isolation": "shadow-dom"
+ "mode": "iframe",
+ "target": {
+ "scheme": "http",
+ "hostMode": "request-host",
+ "port": {
+ "default": 5003,
+ "keys": {
+ "uci": "istoreenhance.@istoreenhance[0].adminport"
+ }
+ },
+ "path": "/"
+ },
+ "access": {
+ "scope": "lan",
+ "blockedTitle": "请在局域网内打开 KSpeeder",
+ "blockedMessage": "KSpeeder 运行在设备的独立服务端口,请连接设备所在局域网后再打开。"
+ }
},
"standalone": {
"entry": "index.html",
@@ -21,6 +35,14 @@
"path": "/"
}
},
+ "config": {
+ "providerOrder": ["uci"],
+ "providers": {
+ "uci": {
+ "type": "uci"
+ }
+ }
+ },
"backend": {
"type": "http",
"scheme": "http",
diff --git a/istoreenhance/files/www/desktop-entry.js b/istoreenhance/files/www/desktop-entry.js
deleted file mode 100644
index 143d60afe..000000000
--- a/istoreenhance/files/www/desktop-entry.js
+++ /dev/null
@@ -1,260 +0,0 @@
-const stateByElement = new WeakMap();
-
-function normalizeBasePath(path) {
- const value = typeof path === "string" && path.trim() ? path.trim() : "/apps/kspeeder/";
- return value.endsWith("/") ? value : `${value}/`;
-}
-
-function normalizeAPIBase(context) {
- if (context && typeof context.apiBase === "string" && context.apiBase.trim()) {
- return context.apiBase.endsWith("/") ? context.apiBase : `${context.apiBase}/`;
- }
- return `${normalizeBasePath(context && context.basePath)}api/`;
-}
-
-function escapeHTML(value) {
- return String(value == null ? "" : value).replace(/[&<>"']/g, (char) => ({
- "&": "&",
- "<": "<",
- ">": ">",
- '"': """,
- "'": "'",
- })[char]);
-}
-
-async function fetchJSON(url, options) {
- const response = await fetch(url, {
- credentials: "same-origin",
- headers: { Accept: "application/json" },
- ...options,
- });
- const text = await response.text();
- let payload = null;
- if (text) {
- try {
- payload = JSON.parse(text);
- } catch (error) {
- throw new Error(`API returned non-JSON response (${response.status})`);
- }
- }
- if (!response.ok) {
- const message = payload && (payload.message || payload.error || payload.details);
- throw new Error(message || `API request failed (${response.status})`);
- }
- return payload || {};
-}
-
-function mirrorCounts(overview) {
- const mirrorsByProfile = overview && typeof overview.mirrors === "object" ? overview.mirrors : {};
- const result = { online: 0, total: 0, servedSpeed: "", servedDownload: "" };
- Object.values(mirrorsByProfile).forEach((profile) => {
- const mirrors = Array.isArray(profile && profile.mirrors) ? profile.mirrors : [];
- result.total += mirrors.length;
- result.online += mirrors.filter((mirror) => mirror && mirror.status === "online").length;
- if (!result.servedSpeed && profile && profile.served_speed) {
- result.servedSpeed = profile.served_speed;
- }
- if (!result.servedDownload && profile && profile.served_download) {
- result.servedDownload = profile.served_download;
- }
- });
- return result;
-}
-
-function profileRows(overview) {
- const mirrorsByProfile = overview && typeof overview.mirrors === "object" ? overview.mirrors : {};
- return Object.entries(mirrorsByProfile).map(([profile, status]) => {
- const mirrors = Array.isArray(status && status.mirrors) ? status.mirrors : [];
- const online = mirrors.filter((mirror) => mirror && mirror.status === "online").length;
- const best = mirrors.find((mirror) => mirror && mirror.status === "online") || mirrors[0] || {};
- return `
-
- | ${escapeHTML(profile)} |
- ${online}/${mirrors.length} |
- ${escapeHTML(best.current_speed || best.test_speed || "-")} |
- ${escapeHTML(best.name || "-")} |
- ${escapeHTML(best.error_info || "-")} |
-
- `;
- }).join("");
-}
-
-function render(root, model) {
- const counts = mirrorCounts(model.overview);
- const source = model.overview && model.overview.source ? model.overview.source : "-";
- const error = model.error ? `${escapeHTML(model.error)}
` : "";
- const refreshing = model.refreshing ? "disabled" : "";
- const rows = profileRows(model.overview);
- root.innerHTML = `
-
-
-
-
-
-
KSpeeder
-
Docker 镜像下载加速状态
-
-
-
-
-
-
- ${error}
-
-
版本
${escapeHTML(model.summary.version || "-")}
-
可用节点
${counts.online}/${counts.total}
-
当前下发
${escapeHTML(counts.servedSpeed || "-")}
-
累计下发
${escapeHTML(counts.servedDownload || "-")}
-
-
-
镜像节点${escapeHTML(source)}
- ${rows ? `
-
-
-
- | 类型 |
- 在线 |
- 速度 |
- 节点 |
- 错误 |
-
-
- ${rows}
-
- ` : '
暂无镜像状态,确认 iStoreEnhance 服务已启动并已配置缓存目录。
'}
-
-
-
- `;
-}
-
-async function loadModel(state) {
- const [summary, overview] = await Promise.all([
- fetchJSON(`${state.apiBase}summary`),
- fetchJSON(`${state.apiBase}mirrors/overview`),
- ]);
- state.model.summary = summary;
- state.model.overview = overview;
- state.model.error = "";
-}
-
-async function reload(state) {
- try {
- await loadModel(state);
- } catch (error) {
- state.model.error = error instanceof Error ? error.message : "加载失败";
- } finally {
- render(state.root, state.model);
- }
-}
-
-async function refreshMirrors(state) {
- state.model.refreshing = true;
- state.model.error = "";
- render(state.root, state.model);
- try {
- await fetchJSON(`${state.apiBase}mirrors/refresh`, { method: "POST" });
- await loadModel(state);
- if (state.hostAdapter && state.hostAdapter.toast) {
- state.hostAdapter.toast.success("KSpeeder 测速已刷新");
- }
- } catch (error) {
- state.model.error = error instanceof Error ? error.message : "刷新测速失败";
- if (state.hostAdapter && state.hostAdapter.toast) {
- state.hostAdapter.toast.error(state.model.error);
- }
- } finally {
- state.model.refreshing = false;
- render(state.root, state.model);
- }
-}
-
-export async function bootstrap() {}
-
-export async function mount(props) {
- const root = props && props.domElement;
- if (!root) {
- return;
- }
- const context = props.context || {};
- const state = {
- root,
- apiBase: normalizeAPIBase(context),
- hostAdapter: props.hostAdapter,
- model: {
- summary: {},
- overview: {},
- error: "",
- refreshing: false,
- },
- };
- stateByElement.set(root, state);
- root.addEventListener("click", handleClick);
- render(root, state.model);
- await reload(state);
-}
-
-export async function unmount(props) {
- const root = props && props.domElement;
- if (!root) {
- return;
- }
- root.removeEventListener("click", handleClick);
- root.innerHTML = "";
- stateByElement.delete(root);
-}
-
-function handleClick(event) {
- const target = event.target && event.target.closest ? event.target.closest("[data-action]") : null;
- if (!target) {
- return;
- }
- const root = event.currentTarget;
- const state = stateByElement.get(root);
- if (!state) {
- return;
- }
- const action = target.getAttribute("data-action");
- if (action === "reload") {
- void reload(state);
- } else if (action === "refresh-mirrors") {
- void refreshMirrors(state);
- }
-}
-
-export default { bootstrap, mount, unmount };
diff --git a/istoreenhance/files/www/index.html b/istoreenhance/files/www/index.html
deleted file mode 100644
index bae0337c1..000000000
--- a/istoreenhance/files/www/index.html
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
- KSpeeder
-
-
-
-
-
-
-
diff --git a/ks-cli/Makefile b/ks-cli/Makefile
index 0edd76959..98eeb886f 100644
--- a/ks-cli/Makefile
+++ b/ks-cli/Makefile
@@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk
PKG_ARCH_KS_CLI:=$(ARCH)
PKG_NAME:=ks-cli
-PKG_VERSION:=0.8.7
-PKG_RELEASE:=4
+PKG_VERSION:=0.8.8
+PKG_RELEASE:=5
PKG_SOURCE:=ks-cli-binary-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/kspeeder/docker_kspeeder/releases/download/v$(PKG_VERSION)/
diff --git a/luci-app-ipsec-server/Makefile b/luci-app-ipsec-server/Makefile
index 087812f25..58415dac1 100644
--- a/luci-app-ipsec-server/Makefile
+++ b/luci-app-ipsec-server/Makefile
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-ipsec-server
PKG_VERSION:=20260807
-PKG_RELEASE:=3
+PKG_RELEASE:=5
PKG_MAINTAINER:=Lienol
diff --git a/luci-app-istoreenhance/Makefile b/luci-app-istoreenhance/Makefile
index 929aac162..f50d0755a 100644
--- a/luci-app-istoreenhance/Makefile
+++ b/luci-app-istoreenhance/Makefile
@@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI support for KSpeeder
LUCI_DEPENDS:=+istoreenhance +luci-lib-linkeaseauth +linkease-app-entry
LUCI_PKGARCH:=all
-PKG_VERSION:=0.8.5-r1
-PKG_RELEASE:=8
+PKG_VERSION:=0.8.8-r1
+PKG_RELEASE:=9
include $(TOPDIR)/feeds/luci/luci.mk
diff --git a/luci-app-open-box/Makefile b/luci-app-open-box/Makefile
index 9ccdc5090..978956cf6 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.411
-PKG_RELEASE:=66
+PKG_VERSION:=0.1.412
+PKG_RELEASE:=67
PKG_MAINTAINER:=liandu2024
PKG_LICENSE:=GPL-3.0-or-later
diff --git a/luci-app-vantage/Makefile b/luci-app-vantage/Makefile
index 12ddc2db6..4e3c3adb9 100644
--- a/luci-app-vantage/Makefile
+++ b/luci-app-vantage/Makefile
@@ -11,7 +11,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-vantage
PKG_VERSION:=1.0.15
-PKG_RELEASE:=27
+PKG_RELEASE:=28
PKG_LICENSE:=GPL-3.0-or-later
LUCI_TITLE:=Vantage dashboard
diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/layout.js b/luci-app-vantage/htdocs/luci-static/resources/vantage/layout.js
index 074739dae..da9337e61 100644
--- a/luci-app-vantage/htdocs/luci-static/resources/vantage/layout.js
+++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/layout.js
@@ -106,6 +106,45 @@ return baseclass.extend({
return out;
},
+ /* the option of a layout in /etc/config/vantage_theme */
+ option: function(key) { return 'layout_' + key.replace('-', '_'); },
+
+ /* a layout as that option's value: 'hero:0:4 chart:0:2:h' */
+ encode: function(list) {
+ return list.map(function(e) { return e.id + ':' + e.c + ':' + e.w + (e.hide ? ':h' : ''); }).join(' ');
+ },
+
+ /* the template's data-vt-look-layout, 'wide=hero:0:4 chart:0:2:h;mid=default',
+ as { wide: [ ... ], mid: null }: null is the default layout. Lists go
+ through normalize like any stored layout. */
+ decode: function(text) {
+ var out = Object.create(null);
+ String(text || '').split(';').forEach(function(part) {
+ var m = /^(wide|mid|narrow)(_wired)?=(.+)$/.exec(part);
+ if (!m) return;
+ out[m[1] + (m[2] ? '-wired' : '')] = m[3] === 'default' ? null : m[3].split(' ').map(function(t) {
+ var f = t.split(':'), e = { id: f[0], c: int(f[1], 0), w: int(f[2], 1) };
+ if (f[3] === 'h') e.hide = true;
+ return e;
+ });
+ });
+ return out;
+ },
+
+ /* this browser's layouts with the router's (decode): the router's
+ first for a login that may save there, for any other only where
+ this browser has none */
+ merge: function(mine, saved, first) {
+ var out = Object.create(null);
+ Object.keys(mine).forEach(function(k) { out[k] = mine[k]; });
+ Object.keys(saved).forEach(function(k) {
+ if (!first && own(out, k)) return;
+ if (saved[k]) out[k] = saved[k];
+ else delete out[k];
+ });
+ 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; });
diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/series.js b/luci-app-vantage/htdocs/luci-static/resources/vantage/series.js
index af8b65c8f..08aa99d15 100644
--- a/luci-app-vantage/htdocs/luci-static/resources/vantage/series.js
+++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/series.js
@@ -123,6 +123,14 @@ return baseclass.extend({
Linear scales never go below CHART_FLOOR, so an idle link stays a
flat line, and round up with niceCeil. */
CHART_STYLES: [ 'overlay', 'log', 'mirror', 'mirror-split', 'lanes' ],
+
+ /* the style in force: the router's first for a login that may save
+ there, for any other only where this browser has none */
+ chartPick: function(saved, mine, first) {
+ var ok = this.CHART_STYLES;
+ if (ok.indexOf(saved) >= 0 && (first || ok.indexOf(mine) < 0)) return saved;
+ return ok.indexOf(mine) >= 0 ? mine : ok[0];
+ },
CHART_FLOOR: 1e4,
chartGeom: function(style, peakDn, peakUp) {
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 d18f03102..f521c5b3b 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
@@ -490,8 +490,25 @@ 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 */
+/* What the Vantage theme's template hands over (data-vt-look-*): under it
+ the router keeps the layouts and the chart style with the Appearance */
+function lookAttr(name) {
+ var root = typeof document !== 'undefined' ? document.documentElement : null;
+ return (root && root.getAttribute ? root.getAttribute(name) : null) || '';
+}
+
+function lookSaves() { return lookAttr('data-vt-look-save') === 'yes'; }
+
+/* Done hands the theme what changed; true if it took it (a login that may
+ save). Without it, or for any other login, it stays in this browser. */
+function offerView(values, done) {
+ var ev = null;
+ try { ev = new CustomEvent('vantage:view-save', { detail: { values: values, done: done }, cancelable: true }); } catch (e) { ev = null; }
+ return !!ev && typeof window.dispatchEvent === 'function' && !window.dispatchEvent(ev);
+}
+
+/* Tile layouts the viewer arranged, per screen class, this browser's copy
+ of them and the router's; vantage.layout validates whatever comes back */
var LAYOUT_KEY = 'vantage.layout.v1';
function readLayouts() {
@@ -500,7 +517,7 @@ function readLayouts() {
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;
+ return layout.merge(out, layout.decode(lookAttr('data-vt-look-layout')), lookSaves());
}
function writeLayouts(v) {
@@ -511,33 +528,42 @@ function writeLayouts(v) {
}
/* The throughput chart style the viewer picked (series.CHART_STYLES),
- in this browser */
+ this browser's copy of it and the router's */
var CHART_KEY = 'vantage.chart.v1';
function readChartStyle() {
var v = null;
try { v = window.localStorage.getItem(CHART_KEY); } catch (e) { v = null; }
- return series.CHART_STYLES.indexOf(v) >= 0 ? v : series.CHART_STYLES[0];
+ return series.chartPick(lookAttr('data-vt-look-chart'), v, lookSaves());
}
function writeChartStyle(v) {
try {
- if (v === series.CHART_STYLES[0]) window.localStorage.removeItem(CHART_KEY);
+ /* the default needs no entry, unless the router has another */
+ if (v === series.CHART_STYLES[0] && !lookAttr('data-vt-look-chart')) window.localStorage.removeItem(CHART_KEY);
else window.localStorage.setItem(CHART_KEY, v);
} catch (e) {}
}
-/* The network path's backdrop the viewer picked (backdrop.STYLES), in
- this browser */
+/* The network path's backdrop the viewer picked (backdrop.STYLES). Under
+ the Vantage theme its Appearance decides (saved for every browser on
+ the router where the viewer may) and keeps the one in force in
+ data-vt-backdrop; elsewhere this browser keeps it. */
var BACKDROP_KEY = 'vantage.backdrop.v1';
function readBackdrop() {
- var v = null;
+ var root = typeof document !== 'undefined' ? document.documentElement : null;
+ var v = root && root.getAttribute ? root.getAttribute('data-vt-backdrop') : null;
+ if (backdrop.STYLES.indexOf(v) >= 0) return v;
try { v = window.localStorage.getItem(BACKDROP_KEY); } catch (e) { v = null; }
return backdrop.STYLES.indexOf(v) >= 0 ? v : backdrop.STYLES[0];
}
function writeBackdrop(v) {
+ /* the theme takes it (and cancels the event) */
+ var ev = null;
+ try { ev = new CustomEvent('vantage:backdrop-set', { detail: v, cancelable: true }); } catch (e) { ev = null; }
+ if (ev && typeof window.dispatchEvent === 'function' && !window.dispatchEvent(ev)) return;
try {
if (v === backdrop.STYLES[0]) window.localStorage.removeItem(BACKDROP_KEY);
else window.localStorage.setItem(BACKDROP_KEY, v);
@@ -728,7 +754,7 @@ return view.extend({
this.backdropStyle = readBackdrop();
/* picked under the theme's Appearance (menu-vantage.js), here or
in another tab */
- var self = this, follow = function() { self.setBackdrop(readBackdrop()); };
+ var self = this, follow = function() { self.showBackdrop(readBackdrop()); };
if (window.addEventListener) {
window.addEventListener('vantage:backdrop', follow);
window.addEventListener('storage', function(ev) { if (ev.key === BACKDROP_KEY) follow(); });
@@ -1283,6 +1309,7 @@ return view.extend({
},
setEditing: function(on) {
+ if (!on && this.editing && this.saveView()) return;
this.editing = !!on;
this.el.root.classList.toggle('vt-editing', this.editing);
this.el.layoutBtn.setAttribute('aria-pressed', String(this.editing));
@@ -1291,10 +1318,48 @@ return view.extend({
at once, nothing held from the other mode */
this.held = Object.create(null);
this.doLayout();
- if (this.editing) this.el.editDone.focus();
+ if (this.editing) {
+ this.viewStart = this.viewValues();
+ this.editNote(lookAttr('data-vt-look-save') === 'relogin' ? _('Log in again to save this for every browser.') : '');
+ this.el.editDone.focus();
+ }
else this.el.layoutBtn.focus();
},
+ editNote: function(text) {
+ this.el.editNote.hidden = !text;
+ txt(this.el.editNote, text);
+ },
+
+ /* the options of /etc/config/vantage_theme this dashboard stands for */
+ viewValues: function() {
+ var self = this, out = { chart: this.chartStyle };
+ [ 'wide', 'mid', 'narrow' ].forEach(function(tier) {
+ [ false, true ].forEach(function(wired) {
+ var k = layout.key(tier, wired);
+ out[layout.option(k)] = self.layouts[k] ? layout.encode(self.layouts[k]) : 'default';
+ });
+ });
+ return out;
+ },
+
+ /* Done: what changed goes to the theme in one write. True while that
+ runs: Customize closes when it is saved, and stays open with a note
+ if it was not, so the pick can be saved again. */
+ saveView: function() {
+ var self = this, now = this.viewValues(), then = this.viewStart || {}, out = {};
+ if (this.viewSaving) return true;
+ Object.keys(now).forEach(function(k) { if (now[k] !== then[k]) out[k] = now[k]; });
+ if (!Object.keys(out).length) return false;
+ this.viewSaving = offerView(out, function(ok) {
+ self.viewSaving = false;
+ if (!ok) { self.editNote(_('Could not save this for every browser. Try again.')); return; }
+ self.viewStart = now;
+ self.setEditing(false);
+ });
+ return this.viewSaving;
+ },
+
/* the throughput chart style, picked under Customize */
buildChartPick: function() {
var self = this, names = {
@@ -1322,10 +1387,18 @@ return view.extend({
return E('div', { 'class': 'vt-edit-field' }, [ E('label', { 'for': 'vt-backdrop-style' }, [ _('Network path background') ]), pick ]);
},
+ /* picked here (Customize): saved, and shown */
setBackdrop: function(v) {
if (backdrop.STYLES.indexOf(v) < 0 || v === this.backdropStyle) return;
- this.backdropStyle = v;
writeBackdrop(v);
+ this.showBackdrop(v);
+ },
+
+ /* picked elsewhere (the theme's Appearance, another tab): shown only,
+ never saved back */
+ showBackdrop: function(v) {
+ if (backdrop.STYLES.indexOf(v) < 0 || v === this.backdropStyle) return;
+ this.backdropStyle = v;
if (this.backdrop) this.backdrop.style(v);
if (this.backdropPick && this.backdropPick.value !== v) this.backdropPick.value = v;
},
@@ -1341,10 +1414,11 @@ return view.extend({
buildEditBar: function() {
var self = this, el = this.el;
el.editHint = E('span', { 'class': 'vt-hint' });
+ el.editNote = E('span', { 'class': 'vt-hint', 'role': 'status', 'hidden': 'hidden' });
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': _('Customize the dashboard'), 'hidden': 'hidden' }, [
- E('div', { 'class': 'vt-editbar-text' }, [ E('strong', {}, [ _('Customize the dashboard') ]), el.editHint ]),
+ E('div', { 'class': 'vt-editbar-text' }, [ E('strong', {}, [ _('Customize the dashboard') ]), el.editHint, el.editNote ]),
el.editHidden,
E('div', { 'class': 'vt-edit-picks' }, [ this.buildChartPick(), this.buildBackdropPick() ]),
E('div', { 'class': 'vt-editbar-actions' }, [
@@ -1417,9 +1491,10 @@ return view.extend({
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.'));
+ var every = lookSaves();
+ txt(this.el.editHint, l.tier === 'wide' ? (every ? _('Drag a tile by its handle or use its buttons. Done saves it for wide screens in every browser.') : _('Drag a tile by its handle or use its buttons. Saved in this browser for wide screens.'))
+ : l.tier === 'mid' ? (every ? _('Drag a tile by its handle or use its buttons. Done saves it for medium screens in every browser.') : _('Drag a tile by its handle or use its buttons. Saved in this browser for medium screens.'))
+ : every ? _('Drag a tile by its handle or use its buttons. Done saves it for narrow screens in every browser.') : _('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];
diff --git a/luci-app-vantage/po/templates/vantage.pot b/luci-app-vantage/po/templates/vantage.pot
index 5e94bf2dc..19861a5b8 100644
--- a/luci-app-vantage/po/templates/vantage.pot
+++ b/luci-app-vantage/po/templates/vantage.pot
@@ -1,7 +1,7 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3446
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3521
msgid "%d MHz (%d–%d MHz)"
msgstr ""
@@ -29,19 +29,19 @@ msgid_plural "%d SSIDs · %d idle"
msgstr[0] ""
msgstr[1] ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1547
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2015
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2566
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1622
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2090
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2641
msgid "%d clients"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2903
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2978
msgid "%d connected"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2042
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2046
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2902
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2117
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2121
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2977
msgid "%d devices"
msgstr ""
@@ -67,11 +67,11 @@ msgctxt "vantage"
msgid "%d min ago"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2901
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2976
msgid "%d of %d"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1434
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1509
msgid "%d of %d columns"
msgstr ""
@@ -101,7 +101,7 @@ msgid_plural "%d radios up"
msgstr[0] ""
msgstr[1] ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2633
msgid "%d radios"
msgstr ""
@@ -125,7 +125,7 @@ msgstr ""
msgid "%d weak"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2577
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2652
msgid "%d–%d MHz of the %d–%d MHz band"
msgstr ""
@@ -143,7 +143,7 @@ msgstr ""
msgid "%s (IPv%d)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3268
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3343
msgid "%s (new this session)"
msgstr ""
@@ -154,10 +154,10 @@ msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:166
#: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:103
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2584
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2598
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3000
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3439
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2659
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2673
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3075
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3514
msgid "%s MHz"
msgstr ""
@@ -176,13 +176,13 @@ msgid "%s at %s; below %s roaming and throughput suffer"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:83
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2259
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2334
msgctxt "vantage"
msgid "%s available"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2604
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3447
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2679
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3522
msgid "%s dBm"
msgstr ""
@@ -194,13 +194,13 @@ msgstr ""
msgid "%s device on a newer radio; uses more airtime per byte"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3473
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3548
msgid "%s error"
msgid_plural "%s errors"
msgstr[0] ""
msgstr[1] ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3235
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3310
msgid "%s experience"
msgstr ""
@@ -216,11 +216,11 @@ msgstr ""
msgid "%s has no carrier: cable unplugged or switch port down"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1401
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1475
msgid "%s hidden"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3517
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3592
msgid "%s in · %s out"
msgstr ""
@@ -236,7 +236,7 @@ msgstr ""
msgid "%s is in no zone and accepts every connection"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1394
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1468
msgid "%s is narrower"
msgstr ""
@@ -244,17 +244,17 @@ msgstr ""
msgid "%s is not up"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2959
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3034
msgid ""
"%s is shared by %d devices (a switch or another access point behind it); its "
"%s link is not theirs"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2958
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3033
msgid "%s is shared by %d devices behind the switch"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1397
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1471
msgid "%s is wider"
msgstr ""
@@ -270,23 +270,23 @@ msgstr ""
msgid "%s may open the router's admin"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1515
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1590
msgid "%s moved"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1391
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1465
msgid "%s moved down"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1382
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1456
msgid "%s moved left"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1385
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1459
msgid "%s moved right"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1388
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1462
msgid "%s moved up"
msgstr ""
@@ -299,9 +299,9 @@ msgid "%s negotiated only %d Mbit/s; a cable pair or port may be faulty"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:84
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2260
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2289
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3543
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2335
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2364
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3618
msgid "%s of %s"
msgstr ""
@@ -322,21 +322,21 @@ msgstr ""
msgid "%s of frames to the device fail; interference likely"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3541
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3616
msgid "%s over %d core"
msgid_plural "%s over %d cores"
msgstr[0] ""
msgstr[1] ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2353
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2428
msgid "%s radio"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3273
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3348
msgid "%s sent · %s retried · %s failed"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1440
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1515
msgid "%s shown"
msgstr ""
@@ -352,11 +352,11 @@ msgstr ""
msgid "%s used"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2297
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2372
msgid "%s used of %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2956
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3031
msgid "%s · %d devices"
msgstr ""
@@ -364,7 +364,7 @@ msgstr ""
msgid "%s · %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3265
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3340
msgid "%s · channel %d · %d MHz"
msgstr ""
@@ -380,27 +380,27 @@ msgstr ""
msgid "%s: no carrier"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3447
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3522
msgid "(configured %d dBm, limited by regulatory rules)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2014
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3092
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2089
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3167
msgid "(hidden)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1547
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2015
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2566
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1622
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2090
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2641
msgid "1 client"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2903
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2978
msgid "1 connected"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2046
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2902
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2121
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2977
msgid "1 device"
msgstr ""
@@ -408,7 +408,7 @@ msgstr ""
msgid "1 older device (Wi-Fi 4 or earlier) slows airtime"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2633
msgid "1 radio"
msgstr ""
@@ -436,20 +436,20 @@ msgstr ""
msgid "60 GHz"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2766
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2841
msgid "Active"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3277
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3309
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384
msgid "Address type"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3506
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3581
msgid "Addresses"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2606
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2681
msgid "Airtime"
msgstr ""
@@ -458,8 +458,8 @@ msgctxt "vantage"
msgid "Alias"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2757
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2763
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2832
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2838
msgid "All"
msgstr ""
@@ -488,7 +488,7 @@ msgstr ""
msgid "Busiest radio: %s of Wi-Fi traffic"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2224
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2299
msgid "Busy share of each CPU core"
msgstr ""
@@ -504,8 +504,8 @@ msgstr[1] ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:71
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:72
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2217
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3541
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2292
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3616
msgctxt "vantage"
msgid "CPU"
msgstr ""
@@ -514,78 +514,78 @@ msgstr ""
msgid "Cache (reclaimable)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3382
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3457
msgid "Cancel"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3260
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3335
msgctxt "vantage"
msgid "Capabilities"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3498
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3573
msgid "Carrier"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3446
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3521
msgid "Centre frequency"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2597
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2672
msgid "Ch %d"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1995
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2565
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2070
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2640
msgid "Ch %d · %d MHz"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3439
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3514
msgid "Channel"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1995
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2070
msgid "Channel —"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2630
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2705
msgctxt "vantage"
msgid "Clear filter"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2603
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2648
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2649
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1175
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2678
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2723
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2724
msgid "Clients"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3453
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3528
msgid "Clients on this radio"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3109
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3184
msgid "Close"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3015
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3090
msgid "Connected"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2985
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3060
msgid "Connected after you opened this page"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3266
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3341
msgid "Connected for"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3263
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3294
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3338
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3369
msgid "Connection"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2251
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2326
msgid "Core %d: %s"
msgstr ""
@@ -593,15 +593,19 @@ msgstr ""
msgid "Could not read the firewall configuration"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3365
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3440
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:3514
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1356
+msgid "Could not save this for every browser. Try again."
+msgstr ""
+
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3589
msgid "Counters since boot"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3451
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3526
msgid "Country"
msgstr ""
@@ -610,13 +614,13 @@ msgid ""
"Custom rule files are configured (%s); rules in them are not listed here."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1536
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1611
msgid "Customize"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1346
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1347
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1535
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1420
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1421
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1610
msgid "Customize the dashboard"
msgstr ""
@@ -624,16 +628,16 @@ msgstr ""
msgid "DHCP"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3322
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3397
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:3512
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3587
msgid "DNS"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1927
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2002
msgid "DNS %s"
msgstr ""
@@ -642,55 +646,55 @@ msgstr ""
msgid "Dashboard"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2838
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2930
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3532
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3005
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3607
msgid "Device"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3349
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3424
msgid "Device name"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3378
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3453
msgid "Device type"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2916
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2991
msgid ""
"Devices on the Ethernet ports appear here once they send traffic; the bridge "
"forgets quiet ones after about five minutes."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1996
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2567
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2592
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3444
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2071
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2642
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2667
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3519
msgid "Disabled"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3229
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3304
msgid "Disconnected %s; shown from the last sample."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1360
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1434
msgctxt "vantage"
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:1996
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2567
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2592
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3444
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2071
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2642
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2667
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3519
msgctxt "vantage"
msgid "Down"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2330
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2425
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2405
#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2500
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2575
msgid "Download"
msgstr ""
@@ -698,39 +702,57 @@ msgstr ""
msgid "Download (to clients)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3271
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3346
msgctxt "vantage"
msgid "Downloaded"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1421
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1496
+msgid ""
+"Drag a tile by its handle or use its buttons. Done saves it for medium "
+"screens in every browser."
+msgstr ""
+
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1497
+msgid ""
+"Drag a tile by its handle or use its buttons. Done saves it for narrow "
+"screens in every browser."
+msgstr ""
+
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1495
+msgid ""
+"Drag a tile by its handle or use its buttons. Done saves it for wide screens "
+"in every browser."
+msgstr ""
+
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1496
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:1422
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1497
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:1420
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1495
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:1373
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1447
msgid "Drag to move"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3517
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3592
msgctxt "vantage"
msgid "Dropped"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3071
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3146
msgid "Edit"
msgstr ""
@@ -738,7 +760,7 @@ msgstr ""
msgid "Enhanced Open (OWE)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1599
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1674
msgid "Error"
msgstr ""
@@ -752,8 +774,8 @@ msgctxt "vantage"
msgid "Excellent"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3009
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3084
msgid "Experience"
msgstr ""
@@ -771,20 +793,20 @@ msgstr ""
msgid "Fair signal %s; lower rates at range"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2627
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2828
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2702
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2903
msgid "Filter by name, address, SSID…"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2828
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2903
msgid "Filter by name, address, port…"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2628
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2703
msgid "Filter clients"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3535
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3610
msgctxt "vantage"
msgid "Firmware"
msgstr ""
@@ -797,7 +819,7 @@ msgstr ""
msgid "Forwarding is accepted by default"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3273
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3348
msgid "Frames to device"
msgstr ""
@@ -806,15 +828,15 @@ msgctxt "vantage"
msgid "Free"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3258
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3333
msgid "From device"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2998
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3073
msgid "From device: %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3493
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3568
msgid "From network"
msgstr ""
@@ -824,9 +846,9 @@ msgid ""
"files are not shown."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1925
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2950
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3509
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2000
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3025
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3584
msgid "Gateway"
msgstr ""
@@ -839,7 +861,7 @@ msgstr ""
msgid "General Settings"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3259
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3334
msgctxt "vantage"
msgid "Generation"
msgstr ""
@@ -849,13 +871,13 @@ msgctxt "vantage"
msgid "GiB"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3277
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3309
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384
msgid "Globally unique"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3277
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3309
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384
msgid "Globally unique · %s"
msgstr ""
@@ -873,7 +895,7 @@ msgstr ""
msgid "Good signal %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1382
msgid "Grid packets"
msgstr ""
@@ -889,36 +911,36 @@ msgstr ""
msgid "Half duplex"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1045
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1071
msgctxt "vantage"
msgid "Health checks"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1437
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3092
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1512
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3167
msgctxt "vantage"
msgid "Hidden"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1400
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1474
msgid "Hide %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3278
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3310
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3353
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3385
msgid "IP addresses"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3507
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3582
msgid "IPv4"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3508
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3583
msgid "IPv6"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3275
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3307
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3350
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3382
msgid "Identity"
msgstr ""
@@ -926,7 +948,7 @@ msgstr ""
msgid "In no zone: the default policies apply."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3504
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3579
msgid "In the tunnel"
msgstr ""
@@ -940,21 +962,21 @@ msgctxt "vantage"
msgid "Input"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1974
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2049
msgid "Interface"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3501
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3576
msgid "Interface up for"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3292
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3479
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3491
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3367
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3554
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3566
msgid "Interfaces"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1925
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2000
msgid "Internet"
msgstr ""
@@ -980,11 +1002,11 @@ msgid ""
"itself."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3536
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3611
msgid "Kernel"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2303
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2378
msgid "Kernel %s"
msgstr ""
@@ -993,58 +1015,58 @@ msgctxt "vantage"
msgid "KiB"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2642
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2717
msgid "Kind of client"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3267
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3342
msgctxt "vantage"
msgid "Last activity"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2839
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2974
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3305
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2914
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3049
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3380
msgid "Last heard"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1358
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1432
msgid "Layout reset"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2984
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3059
msgid "Left %s"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:174
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2986
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3061
msgctxt "vantage"
msgid "Legacy"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2838
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2954
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3256
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3296
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3497
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3029
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3331
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3371
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3572
msgctxt "vantage"
msgid "Link"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2997
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3072
msgid "Link rate"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2838
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2965
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3002
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1642
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3040
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3077
msgid "Live"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3540
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3615
msgid "Load"
msgstr ""
@@ -1060,23 +1082,27 @@ msgid_plural "Load %s · %d cores"
msgstr[0] ""
msgstr[1] ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3542
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3617
msgctxt "vantage"
msgid "Load average"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2280
msgid "Load average over 1, 5 and 15 minutes"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2241
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2316
msgid "Load avg %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3538
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3613
msgid "Local time"
msgstr ""
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1323
+msgid "Log in again to save this for every browser."
+msgstr ""
+
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164
msgid "Low link rate %s despite good signal; interference or an old device"
msgstr ""
@@ -1089,8 +1115,8 @@ msgstr ""
msgid "MAC"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3276
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3308
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3351
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3383
msgid "MAC address"
msgstr ""
@@ -1098,11 +1124,11 @@ msgstr ""
msgid "MCS %d"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1393
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1467
msgid "Make %s narrower"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1396
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1470
msgid "Make %s wider"
msgstr ""
@@ -1119,11 +1145,11 @@ msgid "Measuring…"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:83
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2228
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2303
msgid "Memory"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3543
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3618
msgid "Memory in use"
msgstr ""
@@ -1132,63 +1158,63 @@ msgctxt "vantage"
msgid "MiB"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1303
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1368
msgid "Mirrored"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1304
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1369
msgid "Mirrored, scale per direction"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3445
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3520
msgid "Mode"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3533
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3608
msgid "Model"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1464
msgid "Move %s down"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1381
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1455
msgid "Move %s left"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1384
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1458
msgid "Move %s right"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1387
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1461
msgid "Move %s up"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1373
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1447
msgid "Move %s: drag, or use the arrow keys"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3377
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3452
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:3417
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3492
msgid "Name contains invisible or control characters"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3279
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3311
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3354
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3386
msgid "Name from"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2935
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3010
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:3418
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3493
msgid "Name is longer than %d characters"
msgstr ""
@@ -1196,27 +1222,27 @@ msgstr ""
msgid "Name must be text"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3220
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3289
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3295
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3364
msgid "Name this device"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2838
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2964
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2994
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3264
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3304
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3039
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3069
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3339
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3379
msgid "Network"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1713
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1714
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1175
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1788
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1789
msgid "Network path"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1322
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1387
msgid "Network path background"
msgstr ""
@@ -1224,13 +1250,13 @@ msgstr ""
msgid "Networks: %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2768
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2985
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2843
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3060
msgctxt "vantage"
msgid "New"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1872
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1947
msgid "No SSIDs"
msgstr ""
@@ -1238,24 +1264,24 @@ msgstr ""
msgid "No clients"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2918
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3458
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2993
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3533
msgid "No clients connected"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3046
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3121
msgid "No clients connected."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2909
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2984
msgid "No clients in this view"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2909
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2984
msgid "No clients match “%s”"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1926
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2001
msgctxt "vantage"
msgid "No default route"
msgstr ""
@@ -1264,7 +1290,7 @@ msgstr ""
msgid "No interface with a route"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3483
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3558
msgid "No interface with a route is up."
msgstr ""
@@ -1273,7 +1299,7 @@ msgid "No internet-facing zone found"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3498
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3573
msgid "No link"
msgstr ""
@@ -1281,7 +1307,7 @@ msgstr ""
msgid "No network interface with a route is up"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1853
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1928
msgid "No other interfaces are up"
msgstr ""
@@ -1291,7 +1317,7 @@ msgid "No problems detected"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1876
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1951
msgid "No radios reported"
msgstr ""
@@ -1308,16 +1334,16 @@ msgstr ""
msgid "No stations are associated right now"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2990
msgid "No wired devices heard"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3080
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3155
msgctxt "vantage"
msgid "No wireless networks configured."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2572
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2647
msgid "No wireless radios are reported by this device."
msgstr ""
@@ -1332,39 +1358,39 @@ msgstr ""
msgid "No zones are configured."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3046
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3121
msgid "Nobody is moving data right now."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2605
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2680
msgid "Noise"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3261
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3336
msgid "Noise / SNR"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3449
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3450
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3524
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3525
msgid "Noise floor"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1382
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:3416
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3491
msgid "Not a station MAC address"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3211
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3286
msgid "Not connected"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2966
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3301
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3041
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3376
msgid "Not counted per device on a shared port"
msgstr ""
@@ -1372,7 +1398,7 @@ msgstr ""
msgid "Not in effect"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2278
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2353
msgid "Not reported"
msgstr ""
@@ -1380,7 +1406,7 @@ msgstr ""
msgid "Not reported by the driver"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3325
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3400
msgid "Nothing better known"
msgstr ""
@@ -1401,7 +1427,7 @@ msgstr ""
msgid "Older %s device"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2986
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3061
msgid "Older Wi-Fi generation than the radio; uses more airtime"
msgstr ""
@@ -1409,7 +1435,7 @@ msgstr ""
msgid "On this router"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
msgctxt "vantage"
msgid "Online"
msgstr ""
@@ -1426,7 +1452,7 @@ msgctxt "vantage"
msgid "Open"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2884
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2959
msgid "Open details of %s"
msgstr ""
@@ -1452,11 +1478,11 @@ msgid ""
"new rules: what is open is unknown."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1301
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1366
msgid "Overlaid"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1302
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1367
msgid "Overlaid, log scale"
msgstr ""
@@ -1464,11 +1490,11 @@ msgstr ""
msgid "Overview"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3260
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3335
msgid "PMF"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1565
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1640
msgid "Paused while hidden"
msgstr ""
@@ -1482,7 +1508,7 @@ msgid ""
"on to your network: what every router lets in."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3534
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3609
msgctxt "vantage"
msgid "Platform"
msgstr ""
@@ -1492,7 +1518,7 @@ msgctxt "vantage"
msgid "Poor"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3295
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3370
msgid "Port"
msgstr ""
@@ -1500,11 +1526,11 @@ msgstr ""
msgid "Port %d"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2959
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3034
msgid "Port %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2039
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2114
msgid "Port total: %s"
msgstr ""
@@ -1512,11 +1538,11 @@ msgstr ""
msgid "Private"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3277
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352
msgid "Private Wi-Fi address (randomised by the device)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3309
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384
msgid "Private address (randomised by the device)"
msgstr ""
@@ -1524,26 +1550,26 @@ msgstr ""
msgid "Private device"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3531
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3606
msgid "Processes"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3500
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3575
msgid "Protocol"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2637
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2639
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2712
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2714
msgid "Quick filters"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3265
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3443
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3340
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3518
msgctxt "vantage"
msgid "Radio"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2593
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2668
msgid "Radio details"
msgstr ""
@@ -1555,58 +1581,58 @@ msgstr ""
msgid "Radio is enabled but not up"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2617
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3437
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2692
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3512
msgid "Radio settings"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2545
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2547
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1175
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2620
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2622
msgid "Radios"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1927
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2002
msgid "Reachability not probed"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2951
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3026
msgid "Reached through the uplink port %s, not connected to this device"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3491
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3566
msgid "Realtime graphs"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3515
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3590
msgctxt "vantage"
msgid "Received"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1641
msgctxt "vantage"
msgid "Reconnecting…"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2784
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2859
msgid "Remove filter: %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3383
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3458
msgid "Remove name"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3220
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3289
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3295
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3364
msgctxt "vantage"
msgid "Rename"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1359
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1433
msgid "Reset"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3320
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3395
msgid "Reverse DNS of its address"
msgstr ""
@@ -1614,7 +1640,7 @@ msgstr ""
msgid "Root (overlay)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3511
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3586
msgid "Route metric"
msgstr ""
@@ -1626,20 +1652,20 @@ msgstr ""
msgid "SSH (port 22)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3375
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3450
msgid "Save"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3268
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3343
msgid "Seen since"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3516
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3591
msgctxt "vantage"
msgid "Sent"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1305
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1370
msgid "Separate lanes"
msgstr ""
@@ -1647,57 +1673,57 @@ msgstr ""
msgid "Settings to check"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3296
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3371
msgid "Shared by %d devices"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2955
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3030
msgid "Shared port"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1439
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1514
msgid "Show %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2910
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2985
msgid "Show all clients"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2214
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2289
msgid "Show or hide system details"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1714
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1789
msgid "Show or hide the network path"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2548
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2623
msgid "Show or hide the radio details"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2333
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2408
msgid "Show or hide the throughput chart"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3071
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3146
msgid "Show or hide the wireless networks"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2013
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3089
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2088
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3164
msgid "Show the clients of %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2039
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2114
msgid "Show the devices on %s"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:119
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:120
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:128
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2991
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3244
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3066
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3319
msgid "Signal"
msgstr ""
@@ -1705,7 +1731,7 @@ msgstr ""
msgid "Signal not reported"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3499
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3574
msgctxt "vantage"
msgid "Speed"
msgstr ""
@@ -1716,24 +1742,24 @@ msgid_plural "Standard housekeeping: %d rules"
msgstr[0] ""
msgstr[1] ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1382
msgid "Starfield"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2919
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2994
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:3444
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3519
msgid "Status"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2231
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2306
msgid "Storage"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3459
msgid "Stored on this device in /etc/config/vantage"
msgstr ""
@@ -1749,12 +1775,12 @@ msgstr ""
msgid "Strong signal, %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2288
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2363
msgctxt "vantage"
msgid "Swap"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3299
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3374
msgid "Switch ports"
msgstr ""
@@ -1766,13 +1792,13 @@ msgstr ""
msgid "Switched off"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1150
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2213
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2214
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1176
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2288
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2289
msgid "System"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3531
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3606
msgid "System settings"
msgstr ""
@@ -1785,7 +1811,7 @@ msgid "Telnet (port 23)"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:76
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2245
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2320
msgid "Temperature %s"
msgstr ""
@@ -1793,11 +1819,11 @@ msgstr ""
msgid "Temporary (RAM)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2839
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2914
msgid "The bridge forgets a device after about five minutes without traffic"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2988
msgid ""
"The bridges have learned so many addresses that listing them here would "
"strain this device."
@@ -1810,7 +1836,7 @@ msgid ""
"reject in General Settings."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3421
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3496
msgid "The device could not write /etc/config/vantage."
msgstr ""
@@ -1834,7 +1860,7 @@ msgid ""
"an uplink in no zone would be open. Set Input to reject in General Settings."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3323
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3398
msgid "The name the device announces (WPS)"
msgstr ""
@@ -1846,7 +1872,7 @@ msgstr ""
msgid "The only measured client"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2950
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3025
msgid "The router this device sends its traffic to"
msgstr ""
@@ -1862,7 +1888,7 @@ msgstr ""
msgid "The uplinks could not be checked"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1942
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2017
msgid "This access point"
msgstr ""
@@ -1870,11 +1896,11 @@ msgstr ""
msgid "This address family is in no zone: the default policies apply."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1942
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2017
msgid "This device"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3420
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3495
msgid "This device already stores %d names; remove some first."
msgstr ""
@@ -1882,7 +1908,7 @@ msgstr ""
msgid "This device reports no radios"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3480
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3555
msgid "This line is down or has no default route now."
msgstr ""
@@ -1892,7 +1918,7 @@ msgid ""
"the firewall pages."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3428
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3503
msgid "This radio is not reported any more."
msgstr ""
@@ -1900,23 +1926,23 @@ msgstr ""
msgid "This setup is beyond what this overview checks"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3211
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3286
msgid "This station is not associated right now."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2325
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2327
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3250
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1175
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2400
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2402
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3325
msgctxt "vantage"
msgid "Throughput"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1310
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1375
msgid "Throughput chart"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2393
msgid "Throughput per link; arrow keys read the values over time"
msgstr ""
@@ -1925,38 +1951,38 @@ msgctxt "vantage"
msgid "TiB"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3257
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3332
msgid "To device"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2971
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3006
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3059
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3046
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3081
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3134
msgid "To device %s, from device %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2998
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3073
msgid "To device: %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3494
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3569
msgid "To network"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2912
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2987
msgid "Too many devices to list"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1150
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3023
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3024
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1176
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3098
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3099
msgctxt "vantage"
msgid "Top talkers"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3270
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3300
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3440
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3345
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3375
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3515
msgid "Traffic"
msgstr ""
@@ -1972,16 +1998,16 @@ msgid ""
"networks. Set Forward to reject in General Settings."
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1938
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2013
msgid "Traffic to the internet goes through %s, a tunnel over this line"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3503
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3578
msgid "Tunnel"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2604
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3447
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2679
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3522
msgid "Tx power"
msgstr ""
@@ -1992,16 +2018,16 @@ msgid ""
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:272
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3210
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3285
msgctxt "vantage"
msgid "Unknown device"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3419
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3494
msgid "Unknown device type"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3428
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3503
msgid "Unknown radio"
msgstr ""
@@ -2016,14 +2042,14 @@ msgid "Unnamed rule"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2592
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3444
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3498
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2667
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3519
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3573
msgctxt "vantage"
msgid "Up"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2238
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2313
msgid "Up %s"
msgstr ""
@@ -2032,25 +2058,25 @@ msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:49
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2351
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3483
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2426
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3558
msgctxt "vantage"
msgid "Uplink"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2351
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2352
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2426
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2427
msgid "Uplink %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3476
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3487
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3551
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3562
msgid "Uplink · %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2331
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2427
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2501
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2406
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2502
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2576
msgid "Upload"
msgstr ""
@@ -2058,21 +2084,21 @@ msgstr ""
msgid "Upload (from clients)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3272
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3347
msgctxt "vantage"
msgid "Uploaded"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2951
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3026
msgid "Upstream"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3537
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3612
msgid "Uptime"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2952
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3304
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3027
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3379
msgid "VLAN %d"
msgstr ""
@@ -2207,11 +2233,11 @@ msgstr ""
msgid "WPS"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3280
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3355
msgid "WPS device name"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1599
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1674
msgid "Warning"
msgstr ""
@@ -2225,7 +2251,7 @@ msgid "Weak"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2767
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2842
msgid "Weak signal"
msgstr ""
@@ -2249,27 +2275,27 @@ msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:110
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2821
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2896
msgid "Wi-Fi"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1883
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2821
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1958
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2896
msgid "Wired"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1150
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3070
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3071
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1176
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3145
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3146
msgctxt "vantage"
msgid "Wireless networks"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3230
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3305
msgid "Wireless settings"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3319
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3394
msgid "Your name for this device"
msgstr ""
@@ -2307,15 +2333,15 @@ msgstr ""
msgid "any zone (default policy)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2598
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2673
msgid "auto"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3268
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3343
msgid "before this page opened"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3297
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3372
msgid "behind %s, VLAN %d"
msgstr ""
@@ -2324,16 +2350,16 @@ msgctxt "vantage"
msgid "bit/s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2459
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2534
msgid "collecting · %s of data"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2459
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2534
msgid "collecting · first samples"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:251
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2439
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2514
msgid "collecting…"
msgstr ""
@@ -2345,18 +2371,18 @@ msgstr ""
msgid "dBm"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1802
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1940
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1877
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2015
msgid "default route"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1940
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2015
msgid "default route via %s"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:385
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2955
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3296
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3030
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3371
msgid "down"
msgstr ""
@@ -2365,7 +2391,7 @@ msgctxt "vantage"
msgid "drop"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3349
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3424
msgctxt "vantage"
msgid "e.g. Living room TV"
msgstr ""
@@ -2404,8 +2430,8 @@ msgid "half duplex"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:62
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1960
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3097
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2035
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3172
msgid "idle"
msgstr ""
@@ -2447,14 +2473,14 @@ msgctxt "vantage"
msgid "kbit/s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2223
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2458
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2298
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2533
msgid "last 5 min"
msgstr ""
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:175
#: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:104
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3000
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3075
msgid "legacy"
msgstr ""
@@ -2466,45 +2492,45 @@ msgstr ""
msgid "mDNS"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3321
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3396
msgid "mDNS announcement"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3252
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3303
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3327
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3378
msgid "measuring"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2434
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2509
msgid "measuring…"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2415
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2490
msgctxt "vantage"
msgid "no data"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1933
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2008
msgid "no uplink"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3278
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3353
msgid "not known to this AP"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3310
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3385
msgid "not known to this device"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3450
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3525
msgid "not reported (driver placeholder %s)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3261
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3336
msgid "not reported by the driver"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2455
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2530
msgctxt "vantage"
msgid "now"
msgstr ""
@@ -2513,16 +2539,16 @@ msgstr ""
msgid "now %s down, %s up"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3259
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3334
msgid "older than the radio (%s)"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2432
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2507
msgctxt "vantage"
msgid "peak"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2224
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2299
msgid "per core"
msgstr ""
@@ -2531,11 +2557,11 @@ msgctxt "vantage"
msgid "port forward"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3246
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3321
msgid "range %s … %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3493
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3568
msgid "received on %s"
msgstr ""
@@ -2548,7 +2574,7 @@ msgstr ""
msgid "router port %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3494
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3569
msgid "sent on %s"
msgstr ""
@@ -2556,12 +2582,12 @@ msgstr ""
msgid "short GI"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2974
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3305
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3049
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3380
msgid "static entry"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3298
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3373
msgid "switch port %s"
msgstr ""
@@ -2573,11 +2599,11 @@ msgstr ""
msgid "the covered subnets of zone %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3302
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3377
msgid "the port in total: %s"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3297
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3372
msgid "the port: %s"
msgstr ""
@@ -2593,7 +2619,7 @@ msgstr ""
msgid "traffic rule"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1945
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2020
msgid "up %s"
msgstr ""
@@ -2610,6 +2636,6 @@ msgstr ""
msgid "zones %s and %s if they share a device"
msgstr ""
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2452
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2527
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 8b04f71ba..c30694957 100644
--- a/luci-app-vantage/po/zh_Hans/vantage.po
+++ b/luci-app-vantage/po/zh_Hans/vantage.po
@@ -12,7 +12,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3446
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3521
msgid "%d MHz (%d–%d MHz)"
msgstr "%d MHz(%d–%d MHz)"
@@ -36,19 +36,19 @@ msgid "%d SSID · %d idle"
msgid_plural "%d SSIDs · %d idle"
msgstr[0] "%d 个 SSID · %d 个空闲"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1547
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2015
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2566
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1622
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2090
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2641
msgid "%d clients"
msgstr "%d 个客户端"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2903
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2978
msgid "%d connected"
msgstr "已连接 %d 个"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2042
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2046
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2902
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2117
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2121
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2977
msgid "%d devices"
msgstr "%d 台设备"
@@ -73,11 +73,11 @@ msgctxt "vantage"
msgid "%d min ago"
msgstr "%d 分钟前"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2901
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2976
msgid "%d of %d"
msgstr "%d/%d"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1434
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1509
msgid "%d of %d columns"
msgstr "%d/%d 列"
@@ -104,7 +104,7 @@ msgid "%d radio up"
msgid_plural "%d radios up"
msgstr[0] "%d 个射频已上线"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2633
msgid "%d radios"
msgstr "%d 个射频"
@@ -128,7 +128,7 @@ msgstr "%d 项需要关注"
msgid "%d weak"
msgstr "%d 个信号弱"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2577
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2652
msgid "%d–%d MHz of the %d–%d MHz band"
msgstr "%d–%d MHz 属于 %d–%d MHz 频段"
@@ -146,7 +146,7 @@ msgstr "%s(%s)已启用但未上线"
msgid "%s (IPv%d)"
msgstr "%s(IPv%d)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3268
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3343
msgid "%s (new this session)"
msgstr "%s(本次新增)"
@@ -157,10 +157,10 @@ msgstr "%s Gbit/s"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:166
#: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:103
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2584
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2598
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3000
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3439
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2659
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2673
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3075
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3514
msgid "%s MHz"
msgstr "%s MHz"
@@ -179,13 +179,13 @@ msgid "%s at %s; below %s roaming and throughput suffer"
msgstr "%s(%s);低于 %s 时漫游和吞吐量会受影响"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:83
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2259
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2334
msgctxt "vantage"
msgid "%s available"
msgstr "可用 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2604
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3447
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2679
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3522
msgid "%s dBm"
msgstr "%s dBm"
@@ -197,12 +197,12 @@ msgstr "%s 设备"
msgid "%s device on a newer radio; uses more airtime per byte"
msgstr "%s 设备连接在较新的射频上,每字节占用更多空口时间"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3473
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3548
msgid "%s error"
msgid_plural "%s errors"
msgstr[0] "%s 个错误"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3235
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3310
msgid "%s experience"
msgstr "%s 体验"
@@ -218,11 +218,11 @@ msgstr "overlay 空闲 %s(已用 %s)"
msgid "%s has no carrier: cable unplugged or switch port down"
msgstr "%s 无载波:网线未插或交换机端口关闭"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1401
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1475
msgid "%s hidden"
msgstr "%s 已隐藏"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3517
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3592
msgid "%s in · %s out"
msgstr "%s 入 · %s 出"
@@ -238,7 +238,7 @@ msgstr "%s 被转发到 %s"
msgid "%s is in no zone and accepts every connection"
msgstr "%s 不属于任何区域,接受所有连接"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1394
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1468
msgid "%s is narrower"
msgstr "%s 已变窄"
@@ -246,18 +246,18 @@ msgstr "%s 已变窄"
msgid "%s is not up"
msgstr "%s 未上线"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2959
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3034
msgid ""
"%s is shared by %d devices (a switch or another access point behind it); its "
"%s link is not theirs"
msgstr ""
"%s 由 %d 台设备共用(其后接有交换机或另一个接入点);%s 的链路不属于这些设备"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2958
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3033
msgid "%s is shared by %d devices behind the switch"
msgstr "%s 由交换机后的 %d 台设备共用"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1397
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1471
msgid "%s is wider"
msgstr "%s 已加宽"
@@ -273,23 +273,23 @@ msgstr "%s 链路"
msgid "%s may open the router's admin"
msgstr "%s 可能暴露了路由器管理界面"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1515
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1590
msgid "%s moved"
msgstr "%s 已移动"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1391
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1465
msgid "%s moved down"
msgstr "%s 已下移"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1382
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1456
msgid "%s moved left"
msgstr "%s 已左移"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1385
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1459
msgid "%s moved right"
msgstr "%s 已右移"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1388
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1462
msgid "%s moved up"
msgstr "%s 已上移"
@@ -302,9 +302,9 @@ msgid "%s negotiated only %d Mbit/s; a cable pair or port may be faulty"
msgstr "%s 仅协商到 %d Mbit/s;网线线对或端口可能有故障"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:84
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2260
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2289
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3543
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2335
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2364
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3618
msgid "%s of %s"
msgstr "%s / %s"
@@ -325,20 +325,20 @@ msgstr "发往设备的帧失败率:%s"
msgid "%s of frames to the device fail; interference likely"
msgstr "发往设备的帧失败率:%s,可能存在干扰"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3541
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3616
msgid "%s over %d core"
msgid_plural "%s over %d cores"
msgstr[0] "%s / %d 核"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2353
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2428
msgid "%s radio"
msgstr "%s 射频"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3273
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3348
msgid "%s sent · %s retried · %s failed"
msgstr "发送 %s · 重传 %s · 失败 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1440
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1515
msgid "%s shown"
msgstr "%s 已显示"
@@ -354,11 +354,11 @@ msgstr "%s 已连接,速率 %s"
msgid "%s used"
msgstr "已用 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2297
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2372
msgid "%s used of %s"
msgstr "已用 %s / 共 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2956
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3031
msgid "%s · %d devices"
msgstr "%s · %d 台设备"
@@ -366,7 +366,7 @@ msgstr "%s · %d 台设备"
msgid "%s · %s"
msgstr "%s · %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3265
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3340
msgid "%s · channel %d · %d MHz"
msgstr "%s · 信道 %d · %d MHz"
@@ -382,27 +382,27 @@ msgstr "%s · 链路较慢"
msgid "%s: no carrier"
msgstr "%s:无载波"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3447
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3522
msgid "(configured %d dBm, limited by regulatory rules)"
msgstr "(配置 %d dBm,受管制规则限制)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2014
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3092
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2089
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3167
msgid "(hidden)"
msgstr "(隐藏)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1547
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2015
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2566
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1622
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2090
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2641
msgid "1 client"
msgstr "1 个客户端"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2903
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2978
msgid "1 connected"
msgstr "已连接 1 个"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2046
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2902
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2121
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2977
msgid "1 device"
msgstr "1 台设备"
@@ -410,7 +410,7 @@ msgstr "1 台设备"
msgid "1 older device (Wi-Fi 4 or earlier) slows airtime"
msgstr "1 台旧设备(Wi-Fi 4 或更早)占用更多空口时间"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2558
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2633
msgid "1 radio"
msgstr "1 个射频"
@@ -438,20 +438,20 @@ msgstr "6 GHz"
msgid "60 GHz"
msgstr "60 GHz"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2766
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2841
msgid "Active"
msgstr "活跃"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3277
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3309
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384
msgid "Address type"
msgstr "地址类型"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3506
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3581
msgid "Addresses"
msgstr "地址"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2606
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2681
msgid "Airtime"
msgstr "空口时间"
@@ -460,8 +460,8 @@ msgctxt "vantage"
msgid "Alias"
msgstr "别名"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2757
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2763
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2832
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2838
msgid "All"
msgstr "全部"
@@ -490,7 +490,7 @@ msgstr "B"
msgid "Busiest radio: %s of Wi-Fi traffic"
msgstr "最繁忙射频:占 Wi-Fi 流量的 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2224
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2299
msgid "Busy share of each CPU core"
msgstr "每个 CPU 核心的繁忙占比"
@@ -505,8 +505,8 @@ msgstr[0] "繁忙;负载 %s(%d 核);查看最繁忙进程"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:71
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:72
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2217
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3541
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2292
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3616
msgctxt "vantage"
msgid "CPU"
msgstr "CPU"
@@ -515,78 +515,78 @@ msgstr "CPU"
msgid "Cache (reclaimable)"
msgstr "缓存(可回收)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3382
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3457
msgid "Cancel"
msgstr "取消"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3260
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3335
msgctxt "vantage"
msgid "Capabilities"
msgstr "能力"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3498
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3573
msgid "Carrier"
msgstr "链路状态"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3446
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3521
msgid "Centre frequency"
msgstr "中心频率"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2597
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2672
msgid "Ch %d"
msgstr "信道 %d"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1995
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2565
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2070
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2640
msgid "Ch %d · %d MHz"
msgstr "信道 %d · %d MHz"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3439
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3514
msgid "Channel"
msgstr "信道"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1995
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2070
msgid "Channel —"
msgstr "信道 —"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2630
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2705
msgctxt "vantage"
msgid "Clear filter"
msgstr "清除筛选"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2603
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2648
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2649
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1175
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2678
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2723
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2724
msgid "Clients"
msgstr "客户端"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3453
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3528
msgid "Clients on this radio"
msgstr "此射频上的客户端"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3109
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3184
msgid "Close"
msgstr "关闭"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3015
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3090
msgid "Connected"
msgstr "已连接"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2985
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3060
msgid "Connected after you opened this page"
msgstr "打开本页面后连接"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3266
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3341
msgid "Connected for"
msgstr "已连接时长"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3263
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3294
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3338
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3369
msgid "Connection"
msgstr "连接"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2251
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2326
msgid "Core %d: %s"
msgstr "核心 %d:%s"
@@ -594,15 +594,19 @@ msgstr "核心 %d:%s"
msgid "Could not read the firewall configuration"
msgstr "无法读取防火墙配置"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3365
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3440
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:3514
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1356
+msgid "Could not save this for every browser. Try again."
+msgstr "无法为所有浏览器保存此设置,请重试。"
+
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3589
msgid "Counters since boot"
msgstr "自启动以来的计数器"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3451
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3526
msgid "Country"
msgstr "国家"
@@ -611,13 +615,13 @@ msgid ""
"Custom rule files are configured (%s); rules in them are not listed here."
msgstr "已配置自定义规则文件(%s);其中的规则不会在此列出。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1536
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1611
msgid "Customize"
msgstr "自定义"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1346
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1347
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1535
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1420
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1421
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1610
msgid "Customize the dashboard"
msgstr "自定义仪表盘"
@@ -625,16 +629,16 @@ msgstr "自定义仪表盘"
msgid "DHCP"
msgstr "DHCP"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3322
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3397
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:3512
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3587
msgid "DNS"
msgstr "DNS"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1927
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2002
msgid "DNS %s"
msgstr "DNS %s"
@@ -643,56 +647,56 @@ msgstr "DNS %s"
msgid "Dashboard"
msgstr "仪表盘"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2838
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2930
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3532
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3005
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3607
msgid "Device"
msgstr "设备"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3349
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3424
msgid "Device name"
msgstr "设备名"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3378
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3453
msgid "Device type"
msgstr "设备类型"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2916
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2991
msgid ""
"Devices on the Ethernet ports appear here once they send traffic; the bridge "
"forgets quiet ones after about five minutes."
msgstr ""
"以太网端口上的设备发送流量后会显示在这里;网桥会在约五分钟无流量后忘记它们。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1996
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2567
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2592
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3444
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2071
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2642
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2667
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3519
msgid "Disabled"
msgstr "已禁用"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3229
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3304
msgid "Disconnected %s; shown from the last sample."
msgstr "断开于 %s;显示最后一次采样的数据。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1360
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1434
msgctxt "vantage"
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:1996
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2567
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2592
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3444
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2071
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2642
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2667
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3519
msgctxt "vantage"
msgid "Down"
msgstr "已下线"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2330
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2425
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2405
#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2500
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2575
msgid "Download"
msgstr "下载"
@@ -700,39 +704,60 @@ msgstr "下载"
msgid "Download (to clients)"
msgstr "下载(到客户端)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3271
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3346
msgctxt "vantage"
msgid "Downloaded"
msgstr "已下载"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1421
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1496
+msgid ""
+"Drag a tile by its handle or use its buttons. Done saves it for medium "
+"screens in every browser."
+msgstr ""
+"拖动卡片手柄或使用其按钮移动。点击“完成”后,中屏布局将保存到所有浏览器。"
+
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1497
+msgid ""
+"Drag a tile by its handle or use its buttons. Done saves it for narrow "
+"screens in every browser."
+msgstr ""
+"拖动卡片手柄或使用其按钮移动。点击“完成”后,窄屏布局将保存到所有浏览器。"
+
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1495
+msgid ""
+"Drag a tile by its handle or use its buttons. Done saves it for wide screens "
+"in every browser."
+msgstr ""
+"拖动卡片手柄或使用其按钮移动。点击“完成”后,宽屏布局将保存到所有浏览器。"
+
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1496
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:1422
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1497
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:1420
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1495
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:1373
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1447
msgid "Drag to move"
msgstr "拖动以移动"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3517
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3592
msgctxt "vantage"
msgid "Dropped"
msgstr "已丢弃"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3071
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3146
msgid "Edit"
msgstr "编辑"
@@ -740,7 +765,7 @@ msgstr "编辑"
msgid "Enhanced Open (OWE)"
msgstr "增强开放 (OWE)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1599
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1674
msgid "Error"
msgstr "错误"
@@ -754,8 +779,8 @@ msgctxt "vantage"
msgid "Excellent"
msgstr "极好"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3009
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3084
msgid "Experience"
msgstr "体验"
@@ -773,20 +798,20 @@ msgstr "信号一般"
msgid "Fair signal %s; lower rates at range"
msgstr "信号一般 %s;远距离速率较低"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2627
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2828
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2702
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2903
msgid "Filter by name, address, SSID…"
msgstr "按名称、地址、SSID…筛选"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2828
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2903
msgid "Filter by name, address, port…"
msgstr "按名称、地址、端口…筛选"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2628
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2703
msgid "Filter clients"
msgstr "筛选客户端"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3535
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3610
msgctxt "vantage"
msgid "Firmware"
msgstr "固件"
@@ -799,7 +824,7 @@ msgstr "从 %s 转发到 %s"
msgid "Forwarding is accepted by default"
msgstr "默认接受转发"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3273
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3348
msgid "Frames to device"
msgstr "发往设备的帧"
@@ -808,15 +833,15 @@ msgctxt "vantage"
msgid "Free"
msgstr "空闲"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3258
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3333
msgid "From device"
msgstr "来自设备"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2998
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3073
msgid "From device: %s"
msgstr "来自设备:%s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3493
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3568
msgid "From network"
msgstr "来自网络"
@@ -826,9 +851,9 @@ msgid ""
"files are not shown."
msgstr "内容来自防火墙配置。由 UPnP 或自定义规则文件开放的端口不会显示。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1925
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2950
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3509
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2000
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3025
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3584
msgid "Gateway"
msgstr "网关"
@@ -841,7 +866,7 @@ msgstr "Gbit/s"
msgid "General Settings"
msgstr "基本设置"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3259
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3334
msgctxt "vantage"
msgid "Generation"
msgstr "代际"
@@ -851,13 +876,13 @@ msgctxt "vantage"
msgid "GiB"
msgstr "GiB"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3277
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3309
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384
msgid "Globally unique"
msgstr "全局唯一"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3277
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3309
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384
msgid "Globally unique · %s"
msgstr "全局唯一 · %s"
@@ -875,7 +900,7 @@ msgstr "信号良好"
msgid "Good signal %s"
msgstr "信号良好 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1382
msgid "Grid packets"
msgstr "网格数据包"
@@ -891,36 +916,36 @@ msgstr "HTTPS(端口 443)"
msgid "Half duplex"
msgstr "半双工"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1045
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1071
msgctxt "vantage"
msgid "Health checks"
msgstr "健康检查"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1437
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3092
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1512
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3167
msgctxt "vantage"
msgid "Hidden"
msgstr "隐藏"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1400
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1474
msgid "Hide %s"
msgstr "隐藏 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3278
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3310
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3353
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3385
msgid "IP addresses"
msgstr "IP 地址"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3507
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3582
msgid "IPv4"
msgstr "IPv4"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3508
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3583
msgid "IPv6"
msgstr "IPv6"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3275
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3307
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3350
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3382
msgid "Identity"
msgstr "身份"
@@ -928,7 +953,7 @@ msgstr "身份"
msgid "In no zone: the default policies apply."
msgstr "不属于任何区域:适用默认策略。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3504
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3579
msgid "In the tunnel"
msgstr "隧道内"
@@ -942,21 +967,21 @@ msgctxt "vantage"
msgid "Input"
msgstr "入站数据"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1974
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2049
msgid "Interface"
msgstr "接口"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3501
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3576
msgid "Interface up for"
msgstr "接口已启用时长"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3292
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3479
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3491
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3367
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3554
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3566
msgid "Interfaces"
msgstr "接口"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1925
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2000
msgid "Internet"
msgstr "互联网"
@@ -986,11 +1011,11 @@ msgstr ""
"它将来自互联网上任何地址的 %s 转发到 %s。无法读取接口列表,因此本页无法判断该"
"地址是否为路由器本身。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3536
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3611
msgid "Kernel"
msgstr "内核"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2303
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2378
msgid "Kernel %s"
msgstr "内核 %s"
@@ -999,58 +1024,58 @@ msgctxt "vantage"
msgid "KiB"
msgstr "KiB"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2642
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2717
msgid "Kind of client"
msgstr "客户端类型"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3267
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3342
msgctxt "vantage"
msgid "Last activity"
msgstr "最后活动"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2839
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2974
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3305
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2914
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3049
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3380
msgid "Last heard"
msgstr "最后活动"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1358
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1432
msgid "Layout reset"
msgstr "布局已重置"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2984
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3059
msgid "Left %s"
msgstr "离开于 %s"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:174
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2986
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3061
msgctxt "vantage"
msgid "Legacy"
msgstr "旧版"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2838
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2954
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3256
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3296
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3497
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3029
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3331
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3371
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3572
msgctxt "vantage"
msgid "Link"
msgstr "链路"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2997
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3072
msgid "Link rate"
msgstr "链路速率"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1567
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2838
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2965
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3002
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1642
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3040
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3077
msgid "Live"
msgstr "实时"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3540
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3615
msgid "Load"
msgstr "负载"
@@ -1064,23 +1089,27 @@ msgid "Load %s · %d core"
msgid_plural "Load %s · %d cores"
msgstr[0] "负载 %s · %d 核"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3542
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3617
msgctxt "vantage"
msgid "Load average"
msgstr "平均负载"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2205
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2280
msgid "Load average over 1, 5 and 15 minutes"
msgstr "1、5、15 分钟平均负载"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2241
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2316
msgid "Load avg %s"
msgstr "平均负载 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3538
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3613
msgid "Local time"
msgstr "本地时间"
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1323
+msgid "Log in again to save this for every browser."
+msgstr "重新登录后即可为所有浏览器保存此设置。"
+
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:164
msgid "Low link rate %s despite good signal; interference or an old device"
msgstr "信号良好但链路速率仅 %s;可能存在干扰或设备较旧"
@@ -1093,8 +1122,8 @@ msgstr "链路速率低于信号预期"
msgid "MAC"
msgstr "MAC"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3276
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3308
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3351
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3383
msgid "MAC address"
msgstr "MAC 地址"
@@ -1102,11 +1131,11 @@ msgstr "MAC 地址"
msgid "MCS %d"
msgstr "MCS %d"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1393
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1467
msgid "Make %s narrower"
msgstr "使 %s 变窄"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1396
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1470
msgid "Make %s wider"
msgstr "使 %s 加宽"
@@ -1123,11 +1152,11 @@ msgid "Measuring…"
msgstr "测量中…"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:83
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2228
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2303
msgid "Memory"
msgstr "内存"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3543
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3618
msgid "Memory in use"
msgstr "已用内存"
@@ -1136,63 +1165,63 @@ msgctxt "vantage"
msgid "MiB"
msgstr "MiB"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1303
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1368
msgid "Mirrored"
msgstr "镜像"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1304
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1369
msgid "Mirrored, scale per direction"
msgstr "镜像,每个方向单独刻度"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3445
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3520
msgid "Mode"
msgstr "模式"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3533
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3608
msgid "Model"
msgstr "型号"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1390
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1464
msgid "Move %s down"
msgstr "下移 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1381
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1455
msgid "Move %s left"
msgstr "左移 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1384
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1458
msgid "Move %s right"
msgstr "右移 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1387
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1461
msgid "Move %s up"
msgstr "上移 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1373
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1447
msgid "Move %s: drag, or use the arrow keys"
msgstr "移动 %s:拖动或使用方向键"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3377
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3452
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:3417
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3492
msgid "Name contains invisible or control characters"
msgstr "名称包含不可见或控制字符"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3279
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3311
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3354
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3386
msgid "Name from"
msgstr "名称来源"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2935
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3010
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:3418
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3493
msgid "Name is longer than %d characters"
msgstr "名称超过 %d 个字符"
@@ -1200,27 +1229,27 @@ msgstr "名称超过 %d 个字符"
msgid "Name must be text"
msgstr "名称必须是文本"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3220
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3289
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3295
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3364
msgid "Name this device"
msgstr "命名此设备"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2838
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2964
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2994
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3264
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3304
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3039
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3069
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3339
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3379
msgid "Network"
msgstr "网络"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1713
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1714
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1175
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1788
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1789
msgid "Network path"
msgstr "网络路径"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1322
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1387
msgid "Network path background"
msgstr "网络路径背景"
@@ -1228,13 +1257,13 @@ msgstr "网络路径背景"
msgid "Networks: %s"
msgstr "网络:%s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2768
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2985
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2843
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3060
msgctxt "vantage"
msgid "New"
msgstr "新增"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1872
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1947
msgid "No SSIDs"
msgstr "无 SSID"
@@ -1242,24 +1271,24 @@ msgstr "无 SSID"
msgid "No clients"
msgstr "无客户端"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2918
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3458
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2993
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3533
msgid "No clients connected"
msgstr "无客户端连接"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3046
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3121
msgid "No clients connected."
msgstr "没有客户端连接。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2909
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2984
msgid "No clients in this view"
msgstr "此视图中没有客户端"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2909
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2984
msgid "No clients match “%s”"
msgstr "没有匹配“%s”的客户端"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1926
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2001
msgctxt "vantage"
msgid "No default route"
msgstr "无默认路由"
@@ -1268,7 +1297,7 @@ msgstr "无默认路由"
msgid "No interface with a route"
msgstr "没有带路由的接口"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3483
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3558
msgid "No interface with a route is up."
msgstr "没有带路由的接口处于启用状态。"
@@ -1277,7 +1306,7 @@ msgid "No internet-facing zone found"
msgstr "未找到面向互联网的区域"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:47
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3498
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3573
msgid "No link"
msgstr "无链路"
@@ -1285,7 +1314,7 @@ msgstr "无链路"
msgid "No network interface with a route is up"
msgstr "没有带路由的网络接口处于启用状态"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1853
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1928
msgid "No other interfaces are up"
msgstr "没有其他接口处于启用状态"
@@ -1295,7 +1324,7 @@ msgid "No problems detected"
msgstr "未检测到问题"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1876
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1951
msgid "No radios reported"
msgstr "未报告射频"
@@ -1312,16 +1341,16 @@ msgstr "无信号"
msgid "No stations are associated right now"
msgstr "当前没有站点关联"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2990
msgid "No wired devices heard"
msgstr "未发现有线设备"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3080
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3155
msgctxt "vantage"
msgid "No wireless networks configured."
msgstr "未配置无线网络。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2572
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2647
msgid "No wireless radios are reported by this device."
msgstr "此设备未报告任何无线射频。"
@@ -1338,39 +1367,39 @@ msgstr ""
msgid "No zones are configured."
msgstr "尚未配置区域。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3046
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3121
msgid "Nobody is moving data right now."
msgstr "当前没有设备在传输数据。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2605
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2680
msgid "Noise"
msgstr "噪声"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3261
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3336
msgid "Noise / SNR"
msgstr "噪声 / 信噪比"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3449
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3450
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3524
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3525
msgid "Noise floor"
msgstr "底噪"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:105
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1382
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:3416
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3491
msgid "Not a station MAC address"
msgstr "不是站点 MAC 地址"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3211
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3286
msgid "Not connected"
msgstr "未连接"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2966
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3301
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3041
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3376
msgid "Not counted per device on a shared port"
msgstr "共用端口不按设备统计"
@@ -1378,7 +1407,7 @@ msgstr "共用端口不按设备统计"
msgid "Not in effect"
msgstr "未生效"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2278
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2353
msgid "Not reported"
msgstr "未报告"
@@ -1386,7 +1415,7 @@ msgstr "未报告"
msgid "Not reported by the driver"
msgstr "驱动未报告"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3325
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3400
msgid "Nothing better known"
msgstr "无更多信息"
@@ -1407,7 +1436,7 @@ msgstr "OWE"
msgid "Older %s device"
msgstr "较旧的 %s 设备"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2986
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3061
msgid "Older Wi-Fi generation than the radio; uses more airtime"
msgstr "比射频支持的 Wi-Fi 代际更旧;占用更多空口时间"
@@ -1415,7 +1444,7 @@ msgstr "比射频支持的 Wi-Fi 代际更旧;占用更多空口时间"
msgid "On this router"
msgstr "在此路由器上"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
msgctxt "vantage"
msgid "Online"
msgstr "在线"
@@ -1431,7 +1460,7 @@ msgctxt "vantage"
msgid "Open"
msgstr "开放"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2884
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2959
msgid "Open details of %s"
msgstr "打开 %s 的详情"
@@ -1459,11 +1488,11 @@ msgstr ""
"基本设置中的选项 %s 的值被 firewall4 拒绝,因此不会加载新规则:无法确定开放了"
"哪些内容。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1301
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1366
msgid "Overlaid"
msgstr "叠加"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1302
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1367
msgid "Overlaid, log scale"
msgstr "叠加,对数刻度"
@@ -1471,11 +1500,11 @@ msgstr "叠加,对数刻度"
msgid "Overview"
msgstr "概览"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3260
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3335
msgid "PMF"
msgstr "PMF"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1565
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1640
msgid "Paused while hidden"
msgstr "页面隐藏时暂停"
@@ -1491,7 +1520,7 @@ msgstr ""
"Ping 和其他控制消息、组播、DHCP 续租以及转发到你网络的 IPsec:每台路由器都会"
"放行的流量。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3534
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3609
msgctxt "vantage"
msgid "Platform"
msgstr "平台"
@@ -1501,7 +1530,7 @@ msgctxt "vantage"
msgid "Poor"
msgstr "较差"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3295
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3370
msgid "Port"
msgstr "端口"
@@ -1509,11 +1538,11 @@ msgstr "端口"
msgid "Port %d"
msgstr "端口 %d"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2959
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3034
msgid "Port %s"
msgstr "端口 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2039
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2114
msgid "Port total: %s"
msgstr "端口合计:%s"
@@ -1521,11 +1550,11 @@ msgstr "端口合计:%s"
msgid "Private"
msgstr "私有"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3277
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3352
msgid "Private Wi-Fi address (randomised by the device)"
msgstr "私有 Wi-Fi 地址(设备随机化)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3309
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384
msgid "Private address (randomised by the device)"
msgstr "私有地址(设备随机化)"
@@ -1533,26 +1562,26 @@ msgstr "私有地址(设备随机化)"
msgid "Private device"
msgstr "私有设备"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3531
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3606
msgid "Processes"
msgstr "进程"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3500
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3575
msgid "Protocol"
msgstr "协议"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2637
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2639
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2712
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2714
msgid "Quick filters"
msgstr "快速筛选"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3265
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3443
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3340
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3518
msgctxt "vantage"
msgid "Radio"
msgstr "射频"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2593
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2668
msgid "Radio details"
msgstr "射频详情"
@@ -1564,58 +1593,58 @@ msgstr "射频已禁用"
msgid "Radio is enabled but not up"
msgstr "射频已启用但未上线"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2617
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3437
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2692
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3512
msgid "Radio settings"
msgstr "射频设置"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2545
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2547
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1175
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2620
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2622
msgid "Radios"
msgstr "射频"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1927
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2002
msgid "Reachability not probed"
msgstr "未探测可达性"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2951
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3026
msgid "Reached through the uplink port %s, not connected to this device"
msgstr "经由上行端口 %s 到达,并未连接到本设备"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3491
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3566
msgid "Realtime graphs"
msgstr "实时图表"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3515
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3590
msgctxt "vantage"
msgid "Received"
msgstr "已接收"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1566
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1641
msgctxt "vantage"
msgid "Reconnecting…"
msgstr "重新连接中…"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2784
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2859
msgid "Remove filter: %s"
msgstr "移除筛选:%s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3383
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3458
msgid "Remove name"
msgstr "移除名称"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3220
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3289
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3295
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3364
msgctxt "vantage"
msgid "Rename"
msgstr "重命名"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1359
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1433
msgid "Reset"
msgstr "重置"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3320
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3395
msgid "Reverse DNS of its address"
msgstr "其地址的反向 DNS"
@@ -1623,7 +1652,7 @@ msgstr "其地址的反向 DNS"
msgid "Root (overlay)"
msgstr "Root(overlay)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3511
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3586
msgid "Route metric"
msgstr "路由跃点数"
@@ -1635,20 +1664,20 @@ msgstr "路由器管理界面已开放:%s"
msgid "SSH (port 22)"
msgstr "SSH(端口 22)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3375
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3450
msgid "Save"
msgstr "保存"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3268
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3343
msgid "Seen since"
msgstr "首次出现"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3516
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3591
msgctxt "vantage"
msgid "Sent"
msgstr "已发送"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1305
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1370
msgid "Separate lanes"
msgstr "分开显示"
@@ -1656,57 +1685,57 @@ msgstr "分开显示"
msgid "Settings to check"
msgstr "待检查的设置"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3296
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3371
msgid "Shared by %d devices"
msgstr "%d 台设备共用"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2955
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3030
msgid "Shared port"
msgstr "共用端口"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1439
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1514
msgid "Show %s"
msgstr "显示 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2910
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2985
msgid "Show all clients"
msgstr "显示全部客户端"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2214
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2289
msgid "Show or hide system details"
msgstr "显示/隐藏系统详情"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1714
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1789
msgid "Show or hide the network path"
msgstr "显示/隐藏网络路径"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2548
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2623
msgid "Show or hide the radio details"
msgstr "显示/隐藏射频详情"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2333
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2408
msgid "Show or hide the throughput chart"
msgstr "显示/隐藏吞吐量图表"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3071
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3146
msgid "Show or hide the wireless networks"
msgstr "显示/隐藏无线网络"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2013
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3089
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2088
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3164
msgid "Show the clients of %s"
msgstr "显示 %s 的客户端"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2039
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2114
msgid "Show the devices on %s"
msgstr "显示 %s 上的设备"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:119
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:120
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:128
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2840
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2991
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3244
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2915
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3066
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3319
msgid "Signal"
msgstr "信号强度"
@@ -1714,7 +1743,7 @@ msgstr "信号强度"
msgid "Signal not reported"
msgstr "未报告信号"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3499
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3574
msgctxt "vantage"
msgid "Speed"
msgstr "速率"
@@ -1724,24 +1753,24 @@ msgid "Standard housekeeping: %d rule"
msgid_plural "Standard housekeeping: %d rules"
msgstr[0] "标准常规规则:%d 条"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1317
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1382
msgid "Starfield"
msgstr "星空"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2919
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2994
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:3444
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3519
msgid "Status"
msgstr "状态"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:93
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2231
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2306
msgid "Storage"
msgstr "存储"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3384
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3459
msgid "Stored on this device in /etc/config/vantage"
msgstr "保存在本设备 /etc/config/vantage 中"
@@ -1757,12 +1786,12 @@ msgstr "信号强 %s,链路 %s"
msgid "Strong signal, %s"
msgstr "信号强,%s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2288
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2363
msgctxt "vantage"
msgid "Swap"
msgstr "交换分区"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3299
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3374
msgid "Switch ports"
msgstr "交换机端口"
@@ -1774,13 +1803,13 @@ msgstr "VLAN %d(%s)的交换机端口:%s"
msgid "Switched off"
msgstr "已关闭"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1150
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2213
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2214
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1176
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2288
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2289
msgid "System"
msgstr "系统"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3531
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3606
msgid "System settings"
msgstr "系统设置"
@@ -1793,7 +1822,7 @@ msgid "Telnet (port 23)"
msgstr "Telnet(端口 23)"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:76
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2245
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2320
msgid "Temperature %s"
msgstr "温度 %s"
@@ -1801,11 +1830,11 @@ msgstr "温度 %s"
msgid "Temporary (RAM)"
msgstr "临时(RAM)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2839
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2914
msgid "The bridge forgets a device after about five minutes without traffic"
msgstr "设备约五分钟无流量后,网桥会将其遗忘"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2913
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2988
msgid ""
"The bridges have learned so many addresses that listing them here would "
"strain this device."
@@ -1820,7 +1849,7 @@ msgstr ""
"该处适用默认入站数据策略且为接受,因此互联网上的任何主机都能访问路由器本身。"
"请将其加入 wan 区域,或在基本设置中将入站数据设为拒绝。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3421
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3496
msgid "The device could not write /etc/config/vantage."
msgstr "设备无法写入 /etc/config/vantage。"
@@ -1846,7 +1875,7 @@ msgstr ""
"无法读取接口列表,且默认入站数据策略为接受:不属于任何区域的上行接口将会开"
"放。请在基本设置中将入站数据设为拒绝。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3323
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3398
msgid "The name the device announces (WPS)"
msgstr "设备广播的名称(WPS)"
@@ -1858,7 +1887,7 @@ msgstr "唯一已测客户端高于 %s"
msgid "The only measured client"
msgstr "唯一已测客户端"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2950
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3025
msgid "The router this device sends its traffic to"
msgstr "此设备发送流量所经的路由器"
@@ -1874,7 +1903,7 @@ msgstr "保存的名称包含无效的配置节 ID"
msgid "The uplinks could not be checked"
msgstr "无法检查上行接口"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1942
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2017
msgid "This access point"
msgstr "此接入点"
@@ -1882,11 +1911,11 @@ msgstr "此接入点"
msgid "This address family is in no zone: the default policies apply."
msgstr "此地址族不属于任何区域:适用默认策略。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1942
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2017
msgid "This device"
msgstr "此设备"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3420
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3495
msgid "This device already stores %d names; remove some first."
msgstr "此设备已存储 %d 个名称;请先移除部分。"
@@ -1894,7 +1923,7 @@ msgstr "此设备已存储 %d 个名称;请先移除部分。"
msgid "This device reports no radios"
msgstr "此设备未报告任何射频"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3480
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3555
msgid "This line is down or has no default route now."
msgstr "此线路已断开,或当前没有默认路由。"
@@ -1904,7 +1933,7 @@ msgid ""
"the firewall pages."
msgstr "本页无法判断开放了哪些内容。请重新加载;如果仍无效,请检查防火墙页面。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3428
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3503
msgid "This radio is not reported any more."
msgstr "驱动不再报告此射频。"
@@ -1912,23 +1941,23 @@ msgstr "驱动不再报告此射频。"
msgid "This setup is beyond what this overview checks"
msgstr "此配置超出本概览的检查范围"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3211
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3286
msgid "This station is not associated right now."
msgstr "此站点当前未关联。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1149
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2325
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2327
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3250
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1175
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2400
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2402
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3325
msgctxt "vantage"
msgid "Throughput"
msgstr "吞吐量"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1310
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1375
msgid "Throughput chart"
msgstr "吞吐量图表"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2318
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2393
msgid "Throughput per link; arrow keys read the values over time"
msgstr "每条链路的吞吐量;方向键可查看历史值"
@@ -1937,38 +1966,38 @@ msgctxt "vantage"
msgid "TiB"
msgstr "TiB"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3257
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3332
msgid "To device"
msgstr "到设备"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2971
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3006
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3059
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3046
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3081
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3134
msgid "To device %s, from device %s"
msgstr "到设备 %s,来自设备 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2998
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3073
msgid "To device: %s"
msgstr "到设备:%s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3494
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3569
msgid "To network"
msgstr "发往网络"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2912
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2987
msgid "Too many devices to list"
msgstr "设备过多,无法列出"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1150
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3023
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3024
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1176
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3098
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3099
msgctxt "vantage"
msgid "Top talkers"
msgstr "流量大户"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3270
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3300
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3440
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3345
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3375
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3515
msgid "Traffic"
msgstr "流量"
@@ -1986,16 +2015,16 @@ msgstr ""
"未被任何转发覆盖的互联网流量仍会到达你的其他网络。请在基本设置中将转发设为拒"
"绝。"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1938
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2013
msgid "Traffic to the internet goes through %s, a tunnel over this line"
msgstr "去往互联网的流量经过 %s,一条在此线路上运行的隧道"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3503
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3578
msgid "Tunnel"
msgstr "隧道"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2604
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3447
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2679
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3522
msgid "Tx power"
msgstr "发射功率"
@@ -2007,16 +2036,16 @@ msgstr ""
"已安装 UPnP:它运行时,你网络中的设备可以自行开放端口,这些端口不会在此列出。"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/names.js:272
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3210
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3285
msgctxt "vantage"
msgid "Unknown device"
msgstr "未知设备"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3419
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3494
msgid "Unknown device type"
msgstr "未知设备类型"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3428
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3503
msgid "Unknown radio"
msgstr "未知射频"
@@ -2031,14 +2060,14 @@ msgid "Unnamed rule"
msgstr "未命名的规则"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2592
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3444
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3498
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2667
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3519
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3573
msgctxt "vantage"
msgid "Up"
msgstr "已上线"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2238
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2313
msgid "Up %s"
msgstr "已运行 %s"
@@ -2047,25 +2076,25 @@ msgstr "已运行 %s"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:49
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:51
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:57
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2351
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3483
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2426
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3558
msgctxt "vantage"
msgid "Uplink"
msgstr "上行链路"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2351
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2352
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2426
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2427
msgid "Uplink %s"
msgstr "上行链路 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3476
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3487
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3551
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3562
msgid "Uplink · %s"
msgstr "上行链路 · %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2331
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2427
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2501
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2406
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2502
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2576
msgid "Upload"
msgstr "上传"
@@ -2073,21 +2102,21 @@ msgstr "上传"
msgid "Upload (from clients)"
msgstr "上传(来自客户端)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3272
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3347
msgctxt "vantage"
msgid "Uploaded"
msgstr "已上传"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2951
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3026
msgid "Upstream"
msgstr "上游"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3537
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3612
msgid "Uptime"
msgstr "运行时间"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2952
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3304
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3027
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3379
msgid "VLAN %d"
msgstr "VLAN %d"
@@ -2232,11 +2261,11 @@ msgstr "WPA3 个人版"
msgid "WPS"
msgstr "WPS"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3280
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3355
msgid "WPS device name"
msgstr "WPS 设备名称"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1599
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1674
msgid "Warning"
msgstr "警告"
@@ -2250,7 +2279,7 @@ msgid "Weak"
msgstr "弱"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:157
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2767
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2842
msgid "Weak signal"
msgstr "信号弱"
@@ -2273,27 +2302,27 @@ msgstr "开放内容取决于 firewall4 如何处理 %s,本页无法跟踪。
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:106
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:108
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:110
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2821
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2896
msgid "Wi-Fi"
msgstr "Wi-Fi"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1883
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2821
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1958
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2896
msgid "Wired"
msgstr "有线"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1150
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3070
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3071
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1176
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3145
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3146
msgctxt "vantage"
msgid "Wireless networks"
msgstr "无线网络"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3230
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3305
msgid "Wireless settings"
msgstr "无线设置"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3319
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3394
msgid "Your name for this device"
msgstr "你为此设备设置的名称"
@@ -2331,15 +2360,15 @@ msgstr "任意区域"
msgid "any zone (default policy)"
msgstr "任意区域(默认策略)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2598
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2673
msgid "auto"
msgstr "自动"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3268
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3343
msgid "before this page opened"
msgstr "打开本页之前"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3297
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3372
msgid "behind %s, VLAN %d"
msgstr "位于 %s 之后,VLAN %d"
@@ -2348,16 +2377,16 @@ msgctxt "vantage"
msgid "bit/s"
msgstr "bit/s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2459
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2534
msgid "collecting · %s of data"
msgstr "采集中 · 已采集 %s 数据"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2459
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2534
msgid "collecting · first samples"
msgstr "采集中 · 首个样本"
#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:251
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2439
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2514
msgid "collecting…"
msgstr "采集中…"
@@ -2369,18 +2398,18 @@ msgstr "自定义规则文件"
msgid "dBm"
msgstr "dBm"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1802
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1940
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1877
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2015
msgid "default route"
msgstr "默认路由"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1940
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2015
msgid "default route via %s"
msgstr "默认路由经由 %s"
#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:385
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2955
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3296
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3030
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3371
msgid "down"
msgstr "已断开"
@@ -2389,7 +2418,7 @@ msgctxt "vantage"
msgid "drop"
msgstr "丢弃"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3349
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3424
msgctxt "vantage"
msgid "e.g. Living room TV"
msgstr "例如:客厅电视"
@@ -2428,8 +2457,8 @@ msgid "half duplex"
msgstr "半双工"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/fmt.js:62
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1960
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3097
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2035
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3172
msgid "idle"
msgstr "空闲"
@@ -2471,14 +2500,14 @@ msgctxt "vantage"
msgid "kbit/s"
msgstr "kbit/s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2223
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2458
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2298
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2533
msgid "last 5 min"
msgstr "最近 5 分钟"
#: luci-app-vantage/htdocs/luci-static/resources/vantage/insight.js:175
#: luci-app-vantage/htdocs/luci-static/resources/vantage/wifi.js:104
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3000
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3075
msgid "legacy"
msgstr "旧版"
@@ -2490,45 +2519,45 @@ msgstr "已连接"
msgid "mDNS"
msgstr "mDNS"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3321
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3396
msgid "mDNS announcement"
msgstr "mDNS 广播"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3252
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3303
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3327
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3378
msgid "measuring"
msgstr "测量中"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2434
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2509
msgid "measuring…"
msgstr "测量中…"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2415
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2490
msgctxt "vantage"
msgid "no data"
msgstr "无数据"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1933
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2008
msgid "no uplink"
msgstr "无上行链路"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3278
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3353
msgid "not known to this AP"
msgstr "此 AP 未识别"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3310
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3385
msgid "not known to this device"
msgstr "此设备未识别"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3450
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3525
msgid "not reported (driver placeholder %s)"
msgstr "未报告(驱动占位值 %s)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3261
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3336
msgid "not reported by the driver"
msgstr "驱动未报告"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2455
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2530
msgctxt "vantage"
msgid "now"
msgstr "现在"
@@ -2537,16 +2566,16 @@ msgstr "现在"
msgid "now %s down, %s up"
msgstr "当前下行 %s,上行 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3259
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3334
msgid "older than the radio (%s)"
msgstr "比射频支持的标准更旧(%s)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2432
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2507
msgctxt "vantage"
msgid "peak"
msgstr "峰值"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2224
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2299
msgid "per core"
msgstr "每核"
@@ -2555,11 +2584,11 @@ msgctxt "vantage"
msgid "port forward"
msgstr "端口转发"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3246
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3321
msgid "range %s … %s"
msgstr "范围 %s … %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3493
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3568
msgid "received on %s"
msgstr "在 %s 上接收"
@@ -2572,7 +2601,7 @@ msgstr "拒绝"
msgid "router port %s"
msgstr "路由器端口 %s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3494
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3569
msgid "sent on %s"
msgstr "在 %s 上发送"
@@ -2580,12 +2609,12 @@ msgstr "在 %s 上发送"
msgid "short GI"
msgstr "短 GI"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2974
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3305
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3049
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3380
msgid "static entry"
msgstr "静态条目"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3298
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3373
msgid "switch port %s"
msgstr "交换机端口 %s"
@@ -2597,11 +2626,11 @@ msgstr "已关闭"
msgid "the covered subnets of zone %s"
msgstr "区域 %s 覆盖的子网"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3302
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3377
msgid "the port in total: %s"
msgstr "该端口合计:%s"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3297
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:3372
msgid "the port: %s"
msgstr "端口:%s"
@@ -2617,7 +2646,7 @@ msgstr "此路由器"
msgid "traffic rule"
msgstr "通信规则"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:1945
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2020
msgid "up %s"
msgstr "已运行 %s"
@@ -2634,7 +2663,7 @@ msgstr "区域转发"
msgid "zones %s and %s if they share a device"
msgstr "区域 %s 和 %s(若两者共用设备)"
-#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2452
+#: luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js:2527
msgid "−%d min"
msgstr "−%d 分钟"
diff --git a/luci-theme-argon/Makefile b/luci-theme-argon/Makefile
index a66e3e271..839441c1e 100644
--- a/luci-theme-argon/Makefile
+++ b/luci-theme-argon/Makefile
@@ -8,11 +8,12 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=Argon Theme
# Older SDKs require the coreutils parent menu to enable coreutils-timeout.
-LUCI_DEPENDS:=+luci-base +USE_APK:wget-any +!USE_APK:wget +jsonfilter +ucode-mod-math +flock +coreutils +coreutils-timeout
+# Virtual wget providers include wget-nossl, but every wallpaper API uses HTTPS.
+LUCI_DEPENDS:=+luci-base +wget-ssl +ca-bundle +jsonfilter +ucode-mod-math +flock +coreutils +coreutils-timeout
# Keep existing translation package names and the argon-config message domain.
LUCI_BASENAME:=argon-config
-PKG_VERSION:=3.1.2
-PKG_RELEASE:=41
+PKG_VERSION:=3.1.3
+PKG_RELEASE:=42
PKG_LICENSE:=Apache-2.0 MIT
# LuCI derives translations independently of the theme version. Keep release
@@ -36,6 +37,20 @@ define Package/luci-theme-argon/conffiles
/etc/config/argon
endef
+# Some firmware builds bundle translations into the theme instead of separate
+# language packages. Preserve them even when an older updater installs us alone.
+define Package/luci-theme-argon/preinst
+#!/bin/sh
+root="$${IPKG_INSTROOT}"
+for catalog in "$$root"/usr/lib/lua/luci/i18n/argon-config.*.lmo "$$root"/usr/lib/lua/luci/i18n/argon.*.lmo; do
+ [ -f "$$catalog" ] && [ ! -L "$$catalog" ] || continue
+ umask 077
+ mkdir -p "$$root/etc/argon-config-migration/i18n" || exit 1
+ cp -p "$$catalog" "$$root/etc/argon-config-migration/i18n/$${catalog##*/}" || exit 1
+done
+exit 0
+endef
+
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature
diff --git a/luci-theme-argon/README.md b/luci-theme-argon/README.md
index b3ef06f03..18ebefa15 100644
--- a/luci-theme-argon/README.md
+++ b/luci-theme-argon/README.md
@@ -41,7 +41,7 @@ It also supports automatic and manual switching between light and dark modes.
- **Layout fixes.** Improve dashboard actions, overview layouts, dynamic lists and custom IP/MAC inputs across narrow screens, light/dark modes and RTL layouts.
- **Compatibility improvements.** Improve compatibility with stable OpenWrt firmware.
-Users on v3.0.0 or earlier must install v3.1.2 manually once to get online updates. Users on v3.1.0 or later can upgrade through Theme updates. See the [release notes](RELEASE.md).
+Users on v3.0.0 or earlier must install v3.1.3 manually once to get online updates. Users on v3.1.0 or later can upgrade through Theme updates. See the [release notes](RELEASE.md).
## 3.0 highlights
@@ -99,7 +99,9 @@ Local image and video backgrounds are supported, along with Bing, Unsplash and W
Under **Theme updates**, check the latest stable release, read its release notes and download the package matching your firmware's package manager.
-When a newer version is available, choose **Update now** and confirm to install the theme using the firmware’s native APK or OPKG package manager, preserving your Argon configuration. The page shows download, verification and installation status plus installation logs, and resumes monitoring after a page refresh. Reload the page after installation. Automatic installation requires a matching release package and SHA256 digest and does not perform downgrades. It updates the main theme package; separate translation packages remain managed by the system package manager.
+When a newer version is available, choose **Update now** and confirm to install the theme using the firmware’s native APK or OPKG package manager, preserving your Argon configuration. The page shows download, verification and installation status plus installation logs, and resumes monitoring after a page refresh. Reload the page after installation. The updater downloads and verifies the theme and matching packages for your existing Argon translations before installing them. It also installs the configured LuCI language when that translation is available. Automatic installation requires matching release packages and SHA256 digests and does not downgrade the theme. If verified metadata is missing for an existing translation, update the theme and language packages manually from the same release.
+
+Translations bundled into a firmware's theme package, such as KWRT's Chinese catalog, are preserved during the first upgrade to official packages, including upgrades started by an older updater. A separately installed language package can then take ownership of the catalog.
When building firmware, stop including the old standalone `luci-app-argon-config` plugin alongside the theme: its files conflict with the integrated settings. See [Build with OpenWrt](docs/DEVELOPMENT.md#build-with-openwrt) for existing build scripts.
diff --git a/luci-theme-argon/README_ZH.md b/luci-theme-argon/README_ZH.md
index f184402fe..ed72b18aa 100644
--- a/luci-theme-argon/README_ZH.md
+++ b/luci-theme-argon/README_ZH.md
@@ -41,7 +41,7 @@ Argon 是**一款干净整洁的 OpenWrt LuCI 主题**,
- **布局修复**:优化 Dashboard 操作区、概览布局、动态列表和自定义 IP/MAC 输入框,兼顾窄屏、亮暗色和 RTL 布局。
- **兼容性改进**:改善稳定版 OpenWrt 固件上的兼容性。
-v3.0.0 及更早版本用户需先手动安装一次 v3.1.2,之后即可使用在线更新。v3.1.0 及以上用户可直接通过主题更新升级。详见[更新日志](RELEASE_ZH.md)。
+v3.0.0 及更早版本用户需先手动安装一次 v3.1.3,之后即可使用在线更新。v3.1.0 及以上用户可直接通过主题更新升级。详见[更新日志](RELEASE_ZH.md)。
## 3.0 主要特性
@@ -99,7 +99,9 @@ apk add --allow-untrusted ./luci-theme-argon-*.apk
在**主题更新**中手动检查最新稳定版、查看更新日志,并下载与固件包管理器匹配的安装包。
-检测到更高版本后,可点击**立即更新**并确认,通过固件自带的 APK 或 OPKG 安装主题,保留当前 Argon 配置。页面显示下载、校验、安装状态及安装日志,刷新页面后可继续查看进度;安装完成后重新加载页面。自动安装要求正式发布提供对应安装包及 SHA256 校验值,不执行降级。此功能更新主题主包,独立语言包仍由系统包管理器管理。
+检测到更高版本后,可点击**立即更新**并确认,通过固件自带的 APK 或 OPKG 安装主题,保留当前 Argon 配置。页面显示下载、校验、安装状态及安装日志,刷新页面后可继续查看进度;安装完成后重新加载页面。更新器会先下载并校验主题与现有 Argon 翻译对应的语言包,再执行安装;如果发布中提供了 LuCI 当前配置语言的翻译,也会一并安装。自动安装要求对应安装包及 SHA256 校验值,不降级主题。现有翻译缺少可校验的语言包信息时,请从同一次发布中手动安装主题和语言包。
+
+从 KWRT 等将中文翻译内嵌在主题主包的固件升级时,首次安装官方主题会保留原有翻译,使用旧版更新器发起升级也适用。之后安装独立语言包即可完成翻译文件的归属交接。
自行编译固件时,不要再同时引入旧版独立 `luci-app-argon-config` 插件;它会与主题内置文件冲突。已有自动编译脚本的调整方式见[源码构建说明](docs/DEVELOPMENT_ZH.md#源码构建)。
diff --git a/luci-theme-argon/RELEASE.md b/luci-theme-argon/RELEASE.md
index 7e8be352c..fcd081f1f 100644
--- a/luci-theme-argon/RELEASE.md
+++ b/luci-theme-argon/RELEASE.md
@@ -1,5 +1,11 @@
# Update log for master branch
+## v3.1.3 [ 2026.11.06 ]
+
+- Preserve bundled Argon translations during upgrades and synchronize language packages in subsequent online updates (#737).
+- Fix online wallpapers failing on firmware that selects a downloader without HTTPS support (#738).
+- Keep bridge VLAN dropdown labels readable instead of wrapping one character per line (#738).
+
## v3.1.2 [ 2026.11.02 ]
- Fix port card wrapping and alignment, including ImmortalWrt.
diff --git a/luci-theme-argon/RELEASE_ZH.md b/luci-theme-argon/RELEASE_ZH.md
index 8372c414b..9220c76ce 100644
--- a/luci-theme-argon/RELEASE_ZH.md
+++ b/luci-theme-argon/RELEASE_ZH.md
@@ -1,5 +1,11 @@
# Master 分支的更新日志
+## v3.1.3 [ 2026.11.06 ]
+
+- 修复部分固件升级后 Argon 翻译丢失,保留已有翻译,并在后续在线升级时同步语言包(#737)。
+- 修复部分固件因下载器缺少 HTTPS 支持而无法获取在线壁纸的问题(#738)。
+- 修复网桥 VLAN 下拉菜单文字逐字竖排的问题(#738)。
+
## v3.1.2 [ 2026.11.02 ]
- 修复端口卡片换行和高度不一致,兼容 ImmortalWrt。
diff --git a/luci-theme-argon/docs/DEVELOPMENT.md b/luci-theme-argon/docs/DEVELOPMENT.md
index 72f837aa2..29c6daec2 100644
--- a/luci-theme-argon/docs/DEVELOPMENT.md
+++ b/luci-theme-argon/docs/DEVELOPMENT.md
@@ -93,7 +93,7 @@ Use monochrome SVGs with a `viewBox` and transparent background. CSS masks suppl
## Static update feed deployment
-The router reads a static `/updates/stable.json` manifest without calling the GitHub API. After publication, CI uses its own `GITHUB_TOKEN` to retrieve the official release, verifies the theme package SHA256 digests and sizes, and generates one artifact. GitHub Pages publishes that artifact directly; Cloudflare Pages deploys the same files from a dedicated `updates` Git branch. Packages continue to download from the pinned GitHub Release, and translation packages remain separate.
+The router reads a static `/updates/stable.json` manifest without calling the GitHub API. After publication, CI uses its own `GITHUB_TOKEN` to retrieve the official release, verifies theme and translation package SHA256 digests and sizes, and generates one artifact. GitHub Pages publishes that artifact directly; Cloudflare Pages deploys the same files from a dedicated `updates` Git branch. Packages continue to download from the pinned GitHub Release. The installer includes matching packages for existing Argon translations and the configured LuCI language when available.
Initial maintainer setup:
@@ -119,6 +119,8 @@ Run **Publish update feeds** again to republish GitHub Pages. Identical artifact
The manifest contains `schema`, `repository`, `tag`, `published_at`, `notes`, and the `apk`/`ipk` filenames with `_sha256`/`_size` fields. Metadata comes from the published package bytes rather than master's Makefile. Both formats must be complete and match the tag. Malformed feeds trigger fallback and never overwrite the previous successful cache. Checks are manual, with a five-minute success cache, a one-minute failure cooldown and a lock that coalesces concurrent requests.
+Schema 1 also supports an optional `translations` object keyed by language package suffix, such as `zh-cn`. Each entry has the same six package fields for both formats. Names must match the theme's release, each translation is limited to 1 MiB, and at most 32 languages are accepted. Existing translations without verified metadata disable automatic installation. All required packages are downloaded and verified before the package manager runs; storage checks use their combined size, and completion requires the expected installed versions. The theme's pre-install hook and UCI initialization preserve bundled catalogs across a first upgrade made by an older updater, without replacing catalogs already supplied by independent language packages.
+
Source builds default to an empty CF primary. Configure one before packaging:
```sh
diff --git a/luci-theme-argon/docs/DEVELOPMENT_ZH.md b/luci-theme-argon/docs/DEVELOPMENT_ZH.md
index 7a0b28130..ec402ae76 100644
--- a/luci-theme-argon/docs/DEVELOPMENT_ZH.md
+++ b/luci-theme-argon/docs/DEVELOPMENT_ZH.md
@@ -93,7 +93,7 @@ lessc less/cascade.less htdocs/luci-static/argon/css/cascade.css
## 静态更新源部署
-更新检查读取 `/updates/stable.json` 静态清单。路由器不调用 GitHub API;发布工作流使用自身的 `GITHUB_TOKEN` 读取正式 Release,核验主题包的 SHA256/大小后生成一份产物。GitHub Pages 直接发布该产物,Cloudflare Pages 从专用 `updates` 分支部署同一份文件。安装包继续从固定的 GitHub Release 版本下载,独立语言包仍单独安装。
+更新检查读取 `/updates/stable.json` 静态清单。路由器不调用 GitHub API;发布工作流使用自身的 `GITHUB_TOKEN` 读取正式 Release,核验主题和语言包的 SHA256/大小后生成一份产物。GitHub Pages 直接发布该产物,Cloudflare Pages 从专用 `updates` 分支部署同一份文件。安装包继续从固定的 GitHub Release 版本下载;安装器会包含现有 Argon 翻译及可用的 LuCI 当前配置语言对应的包。
首次启用需要仓库维护者完成以下配置:
@@ -119,6 +119,8 @@ lessc less/cascade.less htdocs/luci-static/argon/css/cascade.css
清单字段包括 `schema`、`repository`、`tag`、`published_at`、`notes`,以及 `apk`/`ipk` 文件名和对应的 `_sha256`/`_size`。由最终发布包计算元数据,不从 master 的 Makefile 推断最新版。两种格式均须完整且属于同一版本;客户端拒绝损坏清单,并保留上一次成功记录。请求只在手动检查时发起,成功缓存五分钟,双源均失败后冷却一分钟。
+Schema 1 还支持可选的 `translations` 对象,以 `zh-cn` 等语言包后缀为键,每项包含双格式对应的六个包字段。文件名须与主题发行版本匹配,单个语言包不超过 1 MiB,最多接受 32 种语言。现有翻译缺少可校验信息时不开放自动安装。所有所需包先完成下载和校验,再调用包管理器;空间检查按总大小计算,安装完成后核对各包版本。主题的 preinst 与 UCI 初始化会保留旧更新器首次升级时的内嵌翻译,并保留独立语言包已提供的文件。
+
源码构建默认不包含 CF 地址。需要自行指定时,在打包前执行:
```sh
diff --git a/luci-theme-argon/htdocs/luci-static/argon/css/cascade.css b/luci-theme-argon/htdocs/luci-static/argon/css/cascade.css
index 3dda33796..02e9baa1b 100644
--- a/luci-theme-argon/htdocs/luci-static/argon/css/cascade.css
+++ b/luci-theme-argon/htdocs/luci-static/argon/css/cascade.css
@@ -3788,7 +3788,7 @@ body:not(.Interfaces) .cbi-rowstyle-2:first-child {
background: transparent;
color: inherit;
white-space: normal;
- overflow-wrap: anywhere;
+ overflow-wrap: break-word;
cursor: pointer;
}
.cbi-dropdown[open] > ul.dropdown > li > label {
diff --git a/luci-theme-argon/less/components/dropdowns.less b/luci-theme-argon/less/components/dropdowns.less
index 1d6b1f4d6..43e1b0636 100644
--- a/luci-theme-argon/less/components/dropdowns.less
+++ b/luci-theme-argon/less/components/dropdowns.less
@@ -99,7 +99,9 @@
background: transparent;
color: inherit;
white-space: normal;
- overflow-wrap: anywhere;
+ // Let full words contribute to the menu's intrinsic width. `anywhere`
+ // shrinks compact controls' expanded labels down to a single character.
+ overflow-wrap: break-word;
cursor: pointer;
> label {
diff --git a/luci-theme-argon/root/etc/uci-defaults/30_luci-theme-argon b/luci-theme-argon/root/etc/uci-defaults/30_luci-theme-argon
index 0ac96bbac..5550c5faf 100644
--- a/luci-theme-argon/root/etc/uci-defaults/30_luci-theme-argon
+++ b/luci-theme-argon/root/etc/uci-defaults/30_luci-theme-argon
@@ -1,5 +1,22 @@
#!/bin/sh
+# OPKG/APK may remove catalogs owned by the previous theme. Keep existing
+# translations until a separate language package takes ownership of them.
+i18n_backup=/etc/argon-config-migration/i18n
+if [ -d "$i18n_backup" ]; then
+ mkdir -p /usr/lib/lua/luci/i18n || exit 1
+ for catalog in "$i18n_backup"/argon-config.*.lmo "$i18n_backup"/argon.*.lmo; do
+ [ -f "$catalog" ] && [ ! -L "$catalog" ] || continue
+ target="/usr/lib/lua/luci/i18n/${catalog##*/}"
+ if [ ! -e "$target" ] && [ ! -L "$target" ]; then
+ cp -p "$catalog" "$target" || exit 1
+ fi
+ rm -f "$catalog"
+ done
+ rmdir "$i18n_backup" 2>/dev/null || true
+ rmdir /etc/argon-config-migration 2>/dev/null || true
+fi
+
# The empty legacy package saves its conffile before releasing file ownership.
if [ -f /etc/argon-config-migration/argon ]; then
cp -p /etc/argon-config-migration/argon /etc/config/argon || exit 1
diff --git a/luci-theme-argon/root/usr/libexec/rpcd/luci.argon_update b/luci-theme-argon/root/usr/libexec/rpcd/luci.argon_update
index fb6f61070..c3718dec7 100755
--- a/luci-theme-argon/root/usr/libexec/rpcd/luci.argon_update
+++ b/luci-theme-argon/root/usr/libexec/rpcd/luci.argon_update
@@ -6,6 +6,10 @@ readonly state_dir='/var/run/argon-update'
readonly cache_file='/var/run/argon-update/release.json'
readonly sources_file='/usr/share/argon/update-sources.json'
readonly repository='jerrykuku/luci-theme-argon'
+readonly i18n_dir='/usr/lib/lua/luci/i18n'
+
+wget_bin=/usr/libexec/wget-ssl
+[ -x "$wget_bin" ] || wget_bin="$(command -v uclient-fetch || command -v wget)"
opkg_query() (
# OPKG locks its database even for status and comparison commands. Keep our
@@ -66,7 +70,45 @@ load_sources() {
fi
}
-normalize_manifest() {
+valid_language() {
+ printf '%s\n' "$1" | grep -Eq '^[a-z]{2,3}(-[a-z0-9]{2,8})?$'
+}
+
+valid_translation_asset() {
+ [ "$1" = "$4" ] && printf '%s\n' "$2" | grep -Eq '^[a-f0-9]{64}$' &&
+ printf '%s\n' "$3" | grep -Eq '^[1-9][0-9]{0,6}$' && [ "$3" -le 1048576 ]
+}
+
+translation_languages() (
+ json_get_type kind translations
+ [ -n "$kind" ] || exit 0
+ [ "$kind" = object ] && json_select translations || exit 1
+ json_get_keys language_keys
+ count=0
+ for language_key in $language_keys; do
+ # jshn's reader converts hyphens to underscores. Recover the package
+ # suffix, then require filenames that exactly match that language.
+ language="$(printf '%s' "$language_key" | tr '_' '-')"
+ count=$((count + 1))
+ [ "$count" -le 32 ] && valid_language "$language" || exit 1
+ json_get_type kind "$language_key"
+ [ "$kind" = object ] && json_select "$language_key" || exit 1
+ for kind in ipk apk; do
+ json_get_var file "$kind"
+ json_get_var checksum "${kind}_sha256"
+ json_get_var bytes "${kind}_size"
+ case "$kind" in
+ ipk) expected="luci-i18n-argon-config-${language}_v${ipk#luci-theme-argon_}" ;;
+ apk) expected="luci-i18n-argon-config-${language}-${apk#luci-theme-argon-}" ;;
+ esac
+ valid_translation_asset "$file" "$checksum" "$bytes" "$expected" || exit 1
+ done
+ json_select ..
+ printf '%s\n' "$language"
+ done
+)
+
+read_manifest_fields() {
json_load_file "$1" || return 1
json_get_var schema schema
json_get_var manifest_repository repository
@@ -82,6 +124,17 @@ normalize_manifest() {
done
printf '%s\n' "$published_at" | grep -Eq '^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$' || return 1
[ "${#notes}" -le 131072 ] || return 1
+ languages="$(translation_languages)" || return 1
+}
+
+normalize_manifest() {
+ local manifest_namespace language field
+ json_set_namespace manifest_input manifest_namespace
+ if ! read_manifest_fields "$1"; then
+ json_set_namespace "$manifest_namespace"
+ return 1
+ fi
+ json_set_namespace "$manifest_namespace"
# Copy only the contract fields, not remote status, URLs or local timestamps.
json_init
json_add_int schema 1
@@ -95,6 +148,29 @@ normalize_manifest() {
json_add_string apk_sha256 "$apk_sha256"
json_add_int ipk_size "$ipk_size"
json_add_int apk_size "$apk_size"
+ if [ -n "$languages" ]; then
+ json_add_object translations
+ for language in $languages; do
+ json_set_namespace manifest_input
+ json_select translations
+ json_select "$language"
+ for field in ipk apk ipk_sha256 apk_sha256 ipk_size apk_size; do
+ json_get_var "translation_$field" "$field"
+ done
+ json_select ..
+ json_select ..
+ json_set_namespace "$manifest_namespace"
+ json_add_object "$language"
+ json_add_string ipk "$translation_ipk"
+ json_add_string apk "$translation_apk"
+ json_add_string ipk_sha256 "$translation_ipk_sha256"
+ json_add_string apk_sha256 "$translation_apk_sha256"
+ json_add_int ipk_size "$translation_ipk_size"
+ json_add_int apk_size "$translation_apk_size"
+ json_close_object
+ done
+ json_close_object
+ fi
json_add_int checked_at "$(date +%s)"
}
@@ -131,7 +207,7 @@ check_updates() {
for source_url in "$primary_url" "$fallback_url"; do
[ -n "$source_url" ] || continue
# The two attempts together stay below rpcd's request timeout.
- if (ulimit -f 2048; timeout -k 1 5 wget -T 4 -q -U 'luci-theme-argon' \
+ if (ulimit -f 2048; timeout -k 1 5 "$wget_bin" -T 4 -q -U 'luci-theme-argon' \
-O "$work/manifest.json" "$source_url") 2>/dev/null &&
[ "$(wc -c < "$work/manifest.json")" -le 1048576 ] && normalize_manifest "$work/manifest.json"; then
json_dump > "$work/cache.json"
@@ -172,6 +248,79 @@ select_package() {
[ "$size" -gt 0 ] && [ "$size" -le 8388608 ]
}
+installed_translations() {
+ {
+ for catalog in "$i18n_dir"/argon-config.*.lmo "$i18n_dir"/argon.*.lmo; do
+ [ -f "$catalog" ] && [ ! -L "$catalog" ] || continue
+ language="${catalog##*/}"
+ language="${language#*.}"
+ printf '%s\n' "${language%.lmo}"
+ done
+ case "$package_manager" in
+ apk) apk list --installed 'luci-i18n-argon-config-*' 2>/dev/null |
+ sed -n 's/^luci-i18n-argon-config-\([a-z][a-z0-9-]*\)-[0-9].*/\1/p' ;;
+ opkg) opkg_query list-installed 'luci-i18n-argon-config-*' 2>/dev/null |
+ awk '$1 ~ /^luci-i18n-argon-config-/ { sub(/^luci-i18n-argon-config-/, "", $1); print $1 }' ;;
+ esac
+ } | sort -u | while IFS= read -r language; do
+ valid_language "$language" && printf '%s\n' "$language"
+ done
+}
+
+# Emit a private, validated download plan. Never install the theme first and
+# discover afterwards that the language package is missing or corrupt.
+package_plan() (
+ printf '%s %s %s\n' "$package" "$digest" "$size"
+ wanted="$(installed_translations)"
+ configured="$(uci -q get luci.main.lang 2>/dev/null | tr 'A-Z_' 'a-z-')"
+ case "$configured" in zh-cn|zh-hans) configured=zh-cn ;; zh-tw|zh-hant) configured=zh-tw ;; nb-no) configured=no ;; esac
+ if ! json_select translations; then
+ [ -z "$wanted" ]
+ exit $?
+ fi
+ if valid_language "$configured"; then
+ json_get_type kind "$configured"
+ [ "$kind" != object ] || wanted="$(printf '%s\n%s\n' "$wanted" "$configured" | sort -u)"
+ fi
+ for language in $wanted; do
+ json_select "$language" || exit 1
+ json_get_var file "$format"
+ json_get_var checksum "${format}_sha256"
+ json_get_var bytes "${format}_size"
+ case "$format" in
+ ipk) expected="luci-i18n-argon-config-${language}_v${target_version}_all.ipk" ;;
+ apk) expected="luci-i18n-argon-config-${language}-${target_version}.apk" ;;
+ esac
+ valid_translation_asset "$file" "$checksum" "$bytes" "$expected" || exit 1
+ printf '%s %s %s\n' "$file" "$checksum" "$bytes"
+ json_select ..
+ done
+)
+
+verify_translation_versions() {
+ local file checksum bytes name expected actual
+ while read -r file checksum bytes; do
+ case "$file" in luci-i18n-argon-config-*) ;; *) continue ;; esac
+ case "$package_manager" in
+ apk)
+ name="${file%-${target_version}.apk}"
+ expected="$target_version"
+ actual="$(apk list --installed "$name" 2>/dev/null | awk -v prefix="$name-" '
+ index($1, prefix) == 1 { print substr($1, length(prefix) + 1); exit }')" ;;
+ opkg)
+ name="${file%_v${target_version}_all.ipk}"
+ expected="v$target_version"
+ actual="$(opkg_query status "$name" 2>/dev/null | awk '
+ /^Version: / { version=$2 }
+ /^Status: .* installed$/ { installed=1 }
+ END { if (installed) print version }')" ;;
+ esac
+ [ "$actual" = "$expected" ] || return 1
+ done </dev/null 2>&1 && command -v sha256sum >/dev/null 2>&1 && command -v timeout >/dev/null 2>&1; then
+ select_package && is_upgrade && package_plan >/dev/null && command -v flock >/dev/null 2>&1 && command -v sha256sum >/dev/null 2>&1 && command -v timeout >/dev/null 2>&1; then
can_upgrade=1
fi
json_add_int result "$1"
@@ -268,6 +417,7 @@ write_status() {
}
run_upgrade() {
+ local plan file checksum bytes total_size
# Run a private copy, since installing the theme replaces this RPC script.
work="${0%/*}"
case "$work" in "$state_dir"/job.??????) ;; *) return 1 ;; esac
@@ -277,27 +427,39 @@ run_upgrade() {
json_load_file "$work/release.json" && select_package || { write_status failed metadata; return; }
installed_version
is_upgrade || { write_status failed version; return; }
+ plan="$(package_plan)" || { write_status failed metadata; return; }
+ total_size="$(printf '%s\n' "$plan" | awk '{ size += $3 } END { print size }')"
# Leave room for download metadata and unpacking. The package manager also
# performs its own dependency and storage checks; never force those checks.
tmp_free="$(df -Pk "$state_dir" | awk 'END { print $4 }')"
root_path=/
[ ! -d /overlay ] || root_path=/overlay
root_free="$(df -Pk "$root_path" | awk 'END { print $4 }')"
- if [ "${tmp_free:-0}" -lt "$((size / 1024 + 2048))" ] ||
- [ "${root_free:-0}" -lt "$((size * 3 / 1024 + 1024))" ]; then
+ if [ "${tmp_free:-0}" -lt "$((total_size / 1024 + 2048))" ] ||
+ [ "${root_free:-0}" -lt "$((total_size * 3 / 1024 + 1024))" ]; then
write_status failed space
return
fi
write_status downloading
- url="https://github.com/jerrykuku/luci-theme-argon/releases/download/$tag/$package"
- (ulimit -f 16384; timeout -k 2 90 wget -T 20 -q -U 'luci-theme-argon' \
- -O "$work/$package" "$url") 2>/dev/null || { write_status failed network; return; }
+ set --
+ while read -r file checksum bytes; do
+ url="https://github.com/jerrykuku/luci-theme-argon/releases/download/$tag/$file"
+ (ulimit -f 16384; timeout -k 2 90 "$wget_bin" -T 20 -q -U 'luci-theme-argon' \
+ -O "$work/$file" "$url") 2>/dev/null || { write_status failed network; return; }
+ set -- "$@" "$work/$file"
+ done < "$work/exit"
) 2>&1 | tail -c 8192 > "$state_dir/log"
@@ -315,7 +477,7 @@ run_upgrade() {
return
fi
installed_version
- if [ "$current_version" != "$target_version" ]; then
+ if [ "$current_version" != "$target_version" ] || ! verify_translation_versions "$plan"; then
write_status failed install
return
fi
@@ -331,6 +493,7 @@ start_upgrade() {
read_cache && [ "$now" -ge "$checked_at" ] && [ "$((now - checked_at))" -lt 300 ] &&
select_package && [ "$tag" = "$requested_tag" ] && [ "$package" = "$requested_package" ] || { fail 3; return; }
is_upgrade || { fail 5; return; }
+ package_plan >/dev/null || { fail 3; return; }
prepare_state || { fail 1; return; }
exec 9>"$state_dir/lock"
flock -n 9 || { fail 4; return; }
diff --git a/luci-theme-argon/root/usr/libexec/rpcd/luci.argon_wallpaper b/luci-theme-argon/root/usr/libexec/rpcd/luci.argon_wallpaper
index 2decfaea2..232418e2b 100755
--- a/luci-theme-argon/root/usr/libexec/rpcd/luci.argon_wallpaper
+++ b/luci-theme-argon/root/usr/libexec/rpcd/luci.argon_wallpaper
@@ -4,8 +4,7 @@
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
-# the script will be excuted when `argon.@global[0].bing_background == '1'`
-# defaults to 'bing' to be compatible with old config
+# Default to Bing for the legacy bing_background configuration.
WEB_PIC_SRC="$(uci -q get argon.@global[0].online_wallpaper || echo 'bing')"
# API_KEY is used by Unsplash and Wallhaven when configured.
@@ -16,10 +15,23 @@ EXACT_RESO="$(uci -q get argon.@global[0].use_exact_resolution || echo '1')"
CACHE="/var/run/argon_${WEB_PIC_SRC}.url"
WRLOCK="/var/lock/argon_${WEB_PIC_SRC}.lock"
+# Older releases give wget-ssl and wget-nossl the same alternative priority.
+# Use the TLS binary directly even when /usr/bin/wget still selects wget-nossl.
+WGET=/usr/libexec/wget-ssl
+if [ ! -x "$WGET" ]; then
+ # Keep source-only deployments compatible with the firmware's downloader.
+ WGET="$(command -v uclient-fetch || command -v wget)"
+fi
+
+fetch_url() {
+ # GNU wget may retry beyond -T. Bound the whole request below rpcd's timeout.
+ timeout -k 1 6 "$WGET" -T 5 -qO- "$1"
+}
+
fetch_pic_url() {
case "$WEB_PIC_SRC" in
bing)
- local picpath="$(wget -T3 -qO- \
+ local picpath="$(fetch_url \
"https://www.bing.com/HPImageArchive.aspx?format=js&n=1" |
jsonfilter -qe '@.images[0].url' |
sed 's/1920x1080/UHD/g')"
@@ -27,20 +39,20 @@ fetch_pic_url() {
;;
unsplash)
if [ -n "$API_KEY" ]; then
- wget -T3 -qO- "https://api.unsplash.com/photos/random?client_id=${API_KEY}" |
+ fetch_url "https://api.unsplash.com/photos/random?client_id=${API_KEY}" |
jsonfilter -qe '@["urls"]["regular"]'
fi
;;
unsplash_*)
local collection_id="${WEB_PIC_SRC#unsplash_}"
if [ -n "$API_KEY" ]; then
- wget -T3 -qO- \
+ fetch_url \
"https://api.unsplash.com/photos/random?client_id=${API_KEY}&collections=${collection_id}" |
jsonfilter -qe '@["urls"]["regular"]'
fi
;;
wallhaven)
- wget -T3 -qO- \
+ fetch_url \
"https://wallhaven.cc/api/v1/search?resolutions=1920x1080&sorting=random" |
jsonfilter -qe "@.data[0].path"
;;
@@ -49,7 +61,7 @@ fetch_pic_url() {
local use_reso="resolutions"
[ "$EXACT_RESO" -eq "1" ] || use_reso="atleast"
[ -z "$API_KEY" ] || API_KEY="apikey=$API_KEY&"
- wget -T3 -qO- \
+ fetch_url \
"https://wallhaven.cc/api/v1/search?${API_KEY}q=id%3A${tag_id}&${use_reso}=1920x1080&sorting=random" |
jsonfilter -qe '@.data[0].path'
;;
@@ -58,9 +70,9 @@ fetch_pic_url() {
try_update() {
local lock="$WRLOCK"
- exec 200>"$lock"
+ exec 9>"$lock"
- if flock -n 200 >"/dev/null" 2>&1; then
+ if flock -n 9 >"/dev/null" 2>&1; then
local picurl="$(fetch_pic_url)"
if [ -n "$picurl" ]; then
@@ -70,7 +82,7 @@ try_update() {
# if not, browser only displays a blank image
# NOTE: only happens to Wallhaven.cc source images
case "$WEB_PIC_SRC" in
- wallhaven*) wget -T3 -qO- "${picurl}" > /dev/null ;;
+ wallhaven*) fetch_url "${picurl}" > /dev/null ;;
esac
echo "$picurl" | tee "$CACHE"
@@ -79,7 +91,7 @@ try_update() {
# and let the login page select a local background instead.
: > "$CACHE"
fi
- flock -u 200 >"/dev/null" 2>&1
+ flock -u 9 >"/dev/null" 2>&1
elif [ -s "$CACHE" ]; then
cat "$CACHE"
fi
diff --git a/luci-theme-argon/tests/test_config_migration.py b/luci-theme-argon/tests/test_config_migration.py
index da32f28e9..bff6b6e2d 100644
--- a/luci-theme-argon/tests/test_config_migration.py
+++ b/luci-theme-argon/tests/test_config_migration.py
@@ -51,7 +51,8 @@ if op != 'get': p.write_text(json.dumps(state))
PKG_UPGRADE='1', PATH=str(binary) + os.pathsep + os.environ['PATH'])
script = (ROOT / 'root/etc/uci-defaults/30_luci-theme-argon').read_text()
self.script = self.root / 'initialize'
- self.script.write_text(script.replace('/etc/', str(self.root / 'etc') + '/'))
+ self.script.write_text(script.replace('/etc/', str(self.root / 'etc') + '/')
+ .replace('/usr/lib/lua/luci/i18n', str(self.root / 'i18n')))
def initialize(self, state=None):
if state is not None:
@@ -128,6 +129,40 @@ if op != 'get': p.write_text(json.dumps(state))
check=True, capture_output=True)
self.assertFalse((self.root / 'etc/argon-config-migration').exists())
+ def theme_preinst(self):
+ recipe = (ROOT / 'Makefile').read_text()
+ source = re.search(r'define Package/luci-theme-argon/preinst\n(.*?)\nendef', recipe, re.S).group(1)
+ script = self.root / 'theme-preinst'
+ script.write_text(source.replace('$$', '$'))
+ subprocess.run(['sh', str(script)], env=dict(self.env, IPKG_INSTROOT=str(self.root)),
+ check=True, capture_output=True)
+
+ def test_bundled_translations_survive_an_older_theme_only_updater(self):
+ original = self.root / 'usr/lib/lua/luci/i18n/argon-config.zh-cn.lmo'
+ original.parent.mkdir(parents=True)
+ original.write_bytes(b'previous Chinese catalog')
+ self.theme_preinst()
+ # The previous package removes its formerly owned catalog on upgrade.
+ original.unlink()
+ self.initialize()
+ restored = self.root / 'i18n/argon-config.zh-cn.lmo'
+ self.assertEqual(restored.read_bytes(), b'previous Chinese catalog')
+ self.assertFalse((self.root / 'etc/argon-config-migration').exists())
+ self.initialize()
+ self.assertEqual(restored.read_bytes(), b'previous Chinese catalog')
+
+ def test_language_package_catalog_is_not_replaced_by_the_migration_backup(self):
+ original = self.root / 'usr/lib/lua/luci/i18n/argon-config.de.lmo'
+ original.parent.mkdir(parents=True)
+ original.write_bytes(b'old German catalog')
+ self.theme_preinst()
+ target = self.root / 'i18n/argon-config.de.lmo'
+ target.parent.mkdir()
+ target.write_bytes(b'new official language package')
+ self.initialize()
+ self.assertEqual(target.read_bytes(), b'new official language package')
+ self.assertFalse((self.root / 'etc/argon-config-migration').exists())
+
if __name__ == '__main__':
unittest.main()
diff --git a/luci-theme-argon/tests/test_update_rpc.py b/luci-theme-argon/tests/test_update_rpc.py
index ab885f5f8..2d1dd156c 100644
--- a/luci-theme-argon/tests/test_update_rpc.py
+++ b/luci-theme-argon/tests/test_update_rpc.py
@@ -25,9 +25,31 @@ class UpdateRpcTests(unittest.TestCase):
fakebin.mkdir()
scripts = {
'apk': '''case "$1" in
-list) test -n "$APK_VERSION" || exit 1; v=$APK_VERSION; [ ! -f "$INSTALLED" ] || v=$(cat "$INSTALLED"); test -n "$v" || exit 1; printf 'luci-theme-argon-%s noarch [installed]\\n' "$v" ;;
+list)
+ case "$3" in
+ luci-i18n-argon-config-*)
+ if [ -f "$LANG_INSTALLED" ]; then
+ while read -r name version; do
+ [ "$3" = 'luci-i18n-argon-config-*' ] || [ "$3" = "$name" ] || continue
+ printf '%s-%s noarch [installed]\\n' "$name" "$version"
+ done < "$LANG_INSTALLED"
+ fi
+ exit 0 ;;
+ esac
+ test -n "$APK_VERSION" || exit 1; v=$APK_VERSION; [ ! -f "$INSTALLED" ] || v=$(cat "$INSTALLED"); test -n "$v" || exit 1; printf 'luci-theme-argon-%s noarch [installed]\\n' "$v" ;;
version) test "$COMPARE_FAIL" != 1 || exit 1; [ "$3" = "$4" ] && printf '=\\n' || { [ "$3" = 3.0.0-r20261015 ] && printf '>\\n' || printf '<\\n'; } ;;
-add) printf '%s\\n' "$@" >> "$MUTATIONS"; test "$INSTALL_FAIL" != 1 || { echo 'database locked'; exit 1; }; test "$WRONG_VERSION" = 1 || printf '3.0.0-r2' > "$INSTALLED"; echo 'Theme installed' ;;
+add) printf '%s\\n' "$@" >> "$MUTATIONS"; test "$INSTALL_FAIL" != 1 || { echo 'database locked'; exit 1; }; test "$WRONG_VERSION" = 1 || printf '3.0.0-r2' > "$INSTALLED"
+ for file in "$@"; do
+ case "$file" in */luci-i18n-argon-config-*.apk)
+ name=${file##*/}; name=${name%-3.0.0-r2.apk}
+ if [ -f "$LANG_INSTALLED" ]; then
+ awk -v name="$name" '$1 != name' "$LANG_INSTALLED" > "$LANG_INSTALLED.tmp"
+ mv "$LANG_INSTALLED.tmp" "$LANG_INSTALLED"
+ fi
+ test "$WRONG_LANGUAGE_VERSION" = 1 || printf '%s 3.0.0-r2\\n' "$name" >> "$LANG_INSTALLED" ;;
+ esac
+ done
+ echo 'Theme installed' ;;
esac
''',
'opkg': '''if [ "$OPKG_QUERY_GUARD" = 1 ]; then
@@ -36,9 +58,23 @@ esac
sleep .05
fi
case "$1" in
-status) v=$OPKG_VERSION; [ ! -f "$INSTALLED" ] || v=$(cat "$INSTALLED"); test -n "$v" || exit 1; printf 'Package: luci-theme-argon\\nVersion: %s\\nStatus: install ok installed\\n' "$v" ;;
+list-installed) [ ! -f "$LANG_INSTALLED" ] || awk '{ print $1 " - " $2 }' "$LANG_INSTALLED" ;;
+status)
+ case "$2" in luci-i18n-argon-config-*)
+ v=$(awk -v name="$2" '$1 == name { v=$2 } END { print v }' "$LANG_INSTALLED" 2>/dev/null)
+ test -n "$v" || exit 0
+ printf 'Package: %s\\nVersion: %s\\nStatus: install ok installed\\n' "$2" "$v"; exit 0 ;;
+ esac
+ v=$OPKG_VERSION; [ ! -f "$INSTALLED" ] || v=$(cat "$INSTALLED"); test -n "$v" || exit 1; printf 'Package: luci-theme-argon\\nVersion: %s\\nStatus: install ok installed\\n' "$v" ;;
compare-versions) [ "$3" = "<<" ] && [ "$COMPARE_FAIL" != 1 ] && [ "$2" != "$4" ] && [ "$2" != 3.0.0-20261015 ] ;;
-install) printf '%s\\n' "$@" >> "$MUTATIONS"; test "$INSTALL_FAIL" != 1 || { echo 'database locked'; exit 1; }; test "$WRONG_VERSION" = 1 || printf '3.0.0-2' > "$INSTALLED"; echo 'Theme installed' ;;
+install) printf '%s\\n' "$@" >> "$MUTATIONS"; test "$INSTALL_FAIL" != 1 || { echo 'database locked'; exit 1; }; test "$WRONG_VERSION" = 1 || printf '3.0.0-2' > "$INSTALLED"
+ for file in "$@"; do
+ case "$file" in */luci-i18n-argon-config-*.ipk)
+ name=${file##*/}; name=${name%_v3.0.0-2_all.ipk}
+ test "$WRONG_LANGUAGE_VERSION" = 1 || printf '%s v3.0.0-2\\n' "$name" >> "$LANG_INSTALLED" ;;
+ esac
+ done
+ echo 'Theme installed' ;;
esac
''',
'df': 'printf "Filesystem 1024-blocks Used Available Capacity Mounted on\\nroot 100000 1000 %s 1%% /\\n" "${FREE_KB:-99000}"\n',
@@ -56,30 +92,45 @@ case "$destination" in
*primary.argon.test*) test "$PRIMARY_FAIL" != 1 || exit 8; cp "${PRIMARY_PAYLOAD:-$PAYLOAD}" "$destination" ;;
*) cp "$PAYLOAD" "$destination" ;;
esac ;;
-*) sleep "${DOWNLOAD_DELAY:-0}"; test "$DOWNLOAD_FAIL" != 1 || exit 8; cp "$PACKAGE_DATA" "$destination" ;;
+*) sleep "${DOWNLOAD_DELAY:-0}"; test "$DOWNLOAD_FAIL" != 1 || exit 8
+ case "$url" in
+ *luci-i18n-argon-config-*) test "$LANG_DOWNLOAD_FAIL" != 1 || exit 8; cp "$LANG_DATA" "$destination" ;;
+ *) cp "$PACKAGE_DATA" "$destination" ;;
+ esac ;;
esac
-'''
+''',
+ 'uci': 'test -z "$LUCI_LANGUAGE" || printf "%s\\n" "$LUCI_LANGUAGE"\n'
}
for name, content in scripts.items():
path = fakebin / name
path.write_text('#!/bin/sh\n' + content)
path.chmod(0o755)
helper = self.directory / 'json_fixture.py'
- helper.write_text('''import json,sys
+ helper.write_text('''import json,re,sys
root=json.load(sys.stdin); path=json.loads(sys.argv[1]); op=sys.argv[2]; args=sys.argv[3:]
obj=root
for key in path: obj=obj[int(key)] if isinstance(obj,list) else obj[key]
+def alias(key): return re.sub(r'[^a-zA-Z0-9_]', '_', str(key))
+def resolve(key):
+ if key in obj: return key
+ return next((name for name in reversed(list(obj)) if alias(name)==key), key)
if op=='select':
if args[0]=='..': path=path[:-1]
else:
- child=obj[int(args[0])] if isinstance(obj,list) else obj[args[0]]
+ key=args[0] if isinstance(obj,list) else resolve(args[0])
+ child=obj[int(key)] if isinstance(obj,list) else obj[key]
if not isinstance(child,(dict,list)): raise ValueError('not a container')
- path.append(args[0])
+ path.append(key)
print(json.dumps(path))
-elif op=='keys': print(' '.join(map(str,range(len(obj)) if isinstance(obj,list) else obj.keys())))
+elif op=='keys': print(' '.join(map(alias,range(len(obj)) if isinstance(obj,list) else obj.keys())))
elif op=='get':
- value=obj.get(args[0],'')
+ value=obj.get(resolve(args[0]),'')
print(int(value) if isinstance(value,bool) else '' if value is None else value)
+elif op=='type':
+ value=obj.get(resolve(args[0]))
+ print('object' if isinstance(value,dict) else 'array' if isinstance(value,list) else
+ 'boolean' if isinstance(value,bool) else 'int' if isinstance(value,int) else
+ 'string' if isinstance(value,str) else '')
elif op=='add':
obj[args[1]]=int(args[2]) if args[0]=='int' else bool(int(args[2])) if args[0]=='boolean' else {} if args[0]=='object' else args[2]
print(json.dumps(root))
@@ -92,6 +143,7 @@ json_load() {{ FIXTURE_JSON=$1; FIXTURE_PATH='[]'; fixture_json validate >/dev/n
json_load_file() {{ json_load "$(cat "$1")"; }}
json_init() {{ FIXTURE_JSON='{{}}'; FIXTURE_PATH='[]'; }}
json_get_var() {{ fixture_value=$(fixture_json get "$2"); export "$1=$fixture_value"; }}
+json_get_type() {{ fixture_value=$(fixture_json type "$2"); export "$1=$fixture_value"; }}
json_get_keys() {{ fixture_value=$(fixture_json keys); export "$1=$fixture_value"; }}
json_select() {{ fixture_value=$(fixture_json select "$1" 2>/dev/null) || return 1; FIXTURE_PATH=$fixture_value; }}
json_add_string() {{ FIXTURE_JSON=$(fixture_json add string "$1" "$2"); }}
@@ -100,8 +152,14 @@ json_add_boolean() {{ FIXTURE_JSON=$(fixture_json add boolean "$1" "$2"); }}
json_add_object() {{ FIXTURE_JSON=$(fixture_json add object "$1" ''); json_select "$1"; }}
json_close_object() {{ json_select ..; }}
json_set_namespace() {{
- if [ "$1" = upgrade_status ]; then FIXTURE_SAVED_JSON=$FIXTURE_JSON; FIXTURE_SAVED_PATH=$FIXTURE_PATH; export "$2=base";
- else FIXTURE_JSON=$FIXTURE_SAVED_JSON; FIXTURE_PATH=$FIXTURE_SAVED_PATH; fi
+ [ "$#" -lt 2 ] || export "$2=${{FIXTURE_NAMESPACE:-base}}"
+ printf '%s' "$FIXTURE_JSON" > '{self.directory}/namespace-'"${{FIXTURE_NAMESPACE:-base}}"'.json'
+ printf '%s' "$FIXTURE_PATH" > '{self.directory}/namespace-'"${{FIXTURE_NAMESPACE:-base}}"'.path'
+ FIXTURE_NAMESPACE=${{1:-base}}
+ if [ -f '{self.directory}/namespace-'"$FIXTURE_NAMESPACE"'.json' ]; then
+ FIXTURE_JSON=$(cat '{self.directory}/namespace-'"$FIXTURE_NAMESPACE"'.json')
+ FIXTURE_PATH=$(cat '{self.directory}/namespace-'"$FIXTURE_NAMESPACE"'.path')
+ else json_init; fi
}}
json_dump() {{ printf '%s\\n' "$FIXTURE_JSON"; }}
@@ -109,16 +167,22 @@ json_dump() {{ printf '%s\\n' "$FIXTURE_JSON"; }}
self.script = self.directory / 'rpc.sh'
sources = self.directory / 'sources.json'
sources.write_text(json.dumps({'primary': PRIMARY, 'fallback': FALLBACK}))
+ self.catalogs = self.directory / 'catalogs'
+ self.catalogs.mkdir()
self.script.write_text((ROOT / 'root/usr/libexec/rpcd/luci.argon_update').read_text()
.replace('/usr/share/libubox/jshn.sh', str(shim))
.replace('/usr/share/argon/update-sources.json', str(sources))
.replace('/var/run/argon-update/release.json', str(self.cache))
- .replace('/var/run/argon-update', str(self.directory / 'state')))
+ .replace('/var/run/argon-update', str(self.directory / 'state'))
+ .replace('/usr/lib/lua/luci/i18n', str(self.catalogs))
+ .replace('wget_bin=/usr/libexec/wget-ssl', 'wget_bin=' + str(fakebin / 'wget')))
self.env = dict(os.environ, PATH=str(fakebin) + os.pathsep + os.environ['PATH'],
APK_VERSION='3.0.0-r1', OPKG_VERSION='', PAYLOAD=str(self.payload),
REQUESTS=str(self.requests), FETCH_FAIL='0', INSTALLED=str(self.directory / 'installed'),
- MUTATIONS=str(self.directory / 'mutations'), PACKAGE_DATA=str(self.directory / 'package'))
+ MUTATIONS=str(self.directory / 'mutations'), PACKAGE_DATA=str(self.directory / 'package'),
+ LANG_DATA=str(self.directory / 'language'), LANG_INSTALLED=str(self.directory / 'languages-installed'))
(self.directory / 'package').write_bytes(b'argon-package')
+ (self.directory / 'language').write_bytes(b'argon-language')
self.release = {'schema': 1, 'repository': 'jerrykuku/luci-theme-argon', 'tag': 'v3.0.0',
'published_at': '2026-10-16T01:00:00Z', 'notes': '## 更新\n- 修复布局。',
'ipk': 'luci-theme-argon_3.0.0-2_all.ipk', 'apk': 'luci-theme-argon-3.0.0-r2.apk',
@@ -297,6 +361,92 @@ json_dump() {{ printf '%s\\n' "$FIXTURE_JSON"; }}
time.sleep(.05)
self.fail('worker did not finish')
+ def add_languages(self, *languages):
+ digest = hashlib.sha256((self.directory / 'language').read_bytes()).hexdigest()
+ self.release['translations'] = {language: {
+ 'apk': f'luci-i18n-argon-config-{language}-3.0.0-r2.apk',
+ 'ipk': f'luci-i18n-argon-config-{language}_v3.0.0-2_all.ipk',
+ 'apk_sha256': digest, 'ipk_sha256': digest,
+ 'apk_size': 14, 'ipk_size': 14,
+ } for language in languages}
+ self.payload.write_text(json.dumps(self.release))
+
+ def test_bundled_chinese_is_installed_with_the_theme_for_both_managers(self):
+ self.add_languages('zh-cn', 'de')
+ (self.catalogs / 'argon-config.zh-cn.lmo').write_bytes(b'bundled Chinese')
+ for manager in ['apk', 'opkg']:
+ with self.subTest(manager=manager):
+ for file in ['installed', 'languages-installed', 'mutations', 'requests']:
+ (self.directory / file).unlink(missing_ok=True)
+ self.env.update(APK_VERSION='3.0.0-r1' if manager == 'apk' else '',
+ OPKG_VERSION='3.0.0-1' if manager == 'opkg' else '')
+ self.assertTrue(self.call('check')['can_upgrade'])
+ self.assertEqual(self.start()['result'], 0)
+ done = self.finished()
+ self.assertEqual(done['upgrade']['phase'], 'complete', done)
+ command = (self.directory / 'mutations').read_text()
+ self.assertIn('luci-i18n-argon-config-zh-cn', command)
+ self.assertNotIn('luci-i18n-argon-config-de', command)
+ self.assertLess(command.index('luci-theme-argon'), command.index('luci-i18n-argon-config-zh-cn'))
+ self.assertNotIn('force-', command)
+
+ def test_missing_verified_language_metadata_blocks_theme_only_installation(self):
+ (self.catalogs / 'argon-config.zh-cn.lmo').write_bytes(b'bundled Chinese')
+ self.assertFalse(self.call('check')['can_upgrade'])
+ self.assertEqual(self.start()['result'], 3)
+ self.assertFalse((self.directory / 'mutations').exists())
+
+ def test_configured_locale_is_added_when_available_and_missing_catalog_packages_are_repaired(self):
+ self.add_languages('zh-cn', 'de')
+ self.env['LUCI_LANGUAGE'] = 'zh_Hans'
+ (self.directory / 'languages-installed').write_text('luci-i18n-argon-config-de 3.0.0-r1\n')
+ self.assertTrue(self.call('check')['can_upgrade'])
+ self.assertEqual(self.start()['result'], 0)
+ self.assertEqual(self.finished()['upgrade']['phase'], 'complete')
+ command = (self.directory / 'mutations').read_text()
+ for language in ['zh-cn', 'de']:
+ self.assertIn('luci-i18n-argon-config-' + language, command)
+
+ def test_language_download_or_checksum_failure_never_mutates_the_theme(self):
+ self.add_languages('zh-cn')
+ (self.catalogs / 'argon-config.zh-cn.lmo').touch()
+ self.call('check')
+ for failure in ['network', 'checksum']:
+ with self.subTest(failure=failure):
+ self.env['LANG_DOWNLOAD_FAIL'] = '1' if failure == 'network' else '0'
+ if failure == 'checksum':
+ (self.directory / 'language').write_bytes(b'corrupt')
+ self.assertEqual(self.start()['result'], 0)
+ done = self.finished()
+ self.assertEqual(done['upgrade']['phase'], 'failed')
+ self.assertEqual(done['upgrade']['error'], failure, done)
+ self.assertFalse((self.directory / 'mutations').exists())
+
+ def test_language_version_is_verified_before_reporting_complete(self):
+ self.add_languages('zh-cn')
+ (self.catalogs / 'argon-config.zh-cn.lmo').touch()
+ self.env['WRONG_LANGUAGE_VERSION'] = '1'
+ self.call('check')
+ self.assertEqual(self.start()['result'], 0)
+ self.assertEqual(self.finished()['upgrade']['error'], 'install')
+
+ def test_translation_metadata_is_validated_and_only_contract_fields_are_cached(self):
+ self.add_languages('zh-cn')
+ original = self.release['translations']['zh-cn'].copy()
+ for bad in [[], {'../zh-cn': original}, {'zh-cn': dict(original, apk_size=0)},
+ {'zh-cn': dict(original, ipk_sha256='bad')},
+ {'zh-cn': dict(original, apk='luci-i18n-argon-config-zh-cn-4.0.0-r1.apk')}]:
+ with self.subTest(metadata=bad):
+ (self.directory / 'state/retry_at').unlink(missing_ok=True)
+ self.payload.write_text(json.dumps(dict(self.release, translations=bad)))
+ self.assertNotEqual(self.call('check')['result'], 0)
+ self.assertFalse(self.cache.exists())
+ (self.directory / 'state/retry_at').unlink(missing_ok=True)
+ self.payload.write_text(json.dumps(dict(self.release, translations={'zh-cn': dict(original, url='https://untrusted.invalid/')})))
+ result = self.call('check')
+ self.assertEqual(result['translations']['zh-cn'], original)
+ self.assertNotIn('untrusted.invalid', self.requests.read_text())
+
def test_background_install_for_both_managers_and_status_survives_reloads(self):
for manager in ['apk', 'opkg']:
with self.subTest(manager=manager):
diff --git a/luci-theme-argon/tests/test_update_site.py b/luci-theme-argon/tests/test_update_site.py
index 37b033946..b2cd7cc4c 100644
--- a/luci-theme-argon/tests/test_update_site.py
+++ b/luci-theme-argon/tests/test_update_site.py
@@ -43,6 +43,45 @@ class UpdateSiteTests(unittest.TestCase):
def generate(self, release=None):
return SITE.generate(release or self.release, self.packages, 'jerrykuku/luci-theme-argon', self.output)
+ def add_language(self, language='zh-cn'):
+ metadata = SITE.resolve(self.release['tag_name'])
+ names = [f'luci-i18n-argon-config-{language}_{metadata["ipk_i18n_version"]}_all.ipk',
+ f'luci-i18n-argon-config-{language}-{metadata["apk_i18n_version"]}.apk']
+ for name in names:
+ data = ('translation bytes for ' + name).encode()
+ (self.packages / name).write_bytes(data)
+ self.release['assets'].append({'name': name, 'size': len(data),
+ 'digest': 'sha256:' + hashlib.sha256(data).hexdigest()})
+ return names
+
+ def test_language_packages_are_versioned_and_verified_in_both_formats(self):
+ names = self.add_language()
+ self.add_language('de')
+ manifest = self.generate()
+ self.assertEqual(set(manifest['translations']), {'zh-cn', 'de'})
+ for kind, name in zip(['ipk', 'apk'], names):
+ entry = manifest['translations']['zh-cn']
+ self.assertEqual(entry[kind], name)
+ self.assertEqual(entry[kind + '_sha256'], hashlib.sha256((self.packages / name).read_bytes()).hexdigest())
+ self.assertEqual(entry[kind + '_size'], (self.packages / name).stat().st_size)
+
+ def test_missing_corrupt_or_wrong_version_language_packages_block_publication(self):
+ for problem in ['missing-format', 'corrupt', 'wrong-version', 'duplicate']:
+ with self.subTest(problem=problem):
+ self.release = self.release_for('v3.1.0')
+ names = self.add_language()
+ if problem == 'missing-format':
+ self.release['assets'].pop()
+ elif problem == 'corrupt':
+ (self.packages / names[0]).write_bytes(b'corrupt translation')
+ elif problem == 'wrong-version':
+ self.release['assets'][-1]['name'] = names[1].replace('3.1.0', '3.0.0')
+ else:
+ self.release['assets'].append(self.release['assets'][-1])
+ with self.assertRaises(ValueError):
+ self.generate()
+ self.assertFalse(self.output.exists())
+
def test_manifest_contains_exact_revision_names_digests_sizes_and_notes(self):
for tag in ['v3.0.0', 'v3.1.0']:
release = self.release_for(tag)
diff --git a/luci-theme-argon/tests/theme-behavior.test.js b/luci-theme-argon/tests/theme-behavior.test.js
index 41ca2508b..fb1471a7f 100644
--- a/luci-theme-argon/tests/theme-behavior.test.js
+++ b/luci-theme-argon/tests/theme-behavior.test.js
@@ -294,8 +294,11 @@ jsonfilter() { return 1; }
try {
const script = path.join(dir, 'wallpaper.sh');
const cache = path.join(dir, 'wallpaper.url');
+ const downloader = path.join(dir, 'wget');
+ writeFileSync(downloader, '#!/bin/sh\nexit 1\n', { mode: 0o755 });
writeFileSync(cache, 'https://example.com/old.jpg\n');
writeFileSync(script, source.replace(imports, stub)
+ .replace('WGET=/usr/libexec/wget-ssl', `WGET="${downloader}"`)
.replace('CACHE="/var/run/argon_${WEB_PIC_SRC}.url"', 'CACHE="$TEST_CACHE"')
.replace('WRLOCK="/var/lock/argon_${WEB_PIC_SRC}.lock"', 'WRLOCK="$TEST_LOCK"'));
for (const wallpaper of ['unsplash', 'unsplash_123']) {
@@ -306,7 +309,7 @@ jsonfilter() { return 1; }
assert.deepEqual(JSON.parse(output), { url: '' });
}
rmSync(cache);
- const failedFetch = execFileSync('bash', [script, 'call', 'get_url'], {
+ const failedFetch = execFileSync('sh', [script, 'call', 'get_url'], {
input: '{}\n', encoding: 'utf8',
env: { ...process.env, TEST_WALLPAPER: 'unsplash', TEST_KEY: 'test-key', TEST_CACHE: cache, TEST_LOCK: path.join(dir, 'lock') }
});
diff --git a/luci-theme-argon/tests/wallpaper-rpc.test.js b/luci-theme-argon/tests/wallpaper-rpc.test.js
new file mode 100644
index 000000000..8965ad5cb
--- /dev/null
+++ b/luci-theme-argon/tests/wallpaper-rpc.test.js
@@ -0,0 +1,113 @@
+'use strict';
+
+const assert = require('node:assert/strict');
+const fs = require('node:fs');
+const os = require('node:os');
+const path = require('node:path');
+const { execFileSync } = require('node:child_process');
+const test = require('node:test');
+
+function fixture(t, budget = '6') {
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'argon-wallpaper-'));
+ t.after(() => fs.rmSync(dir, { recursive: true, force: true }));
+ const bin = path.join(dir, 'bin');
+ fs.mkdirSync(bin);
+ const cache = path.join(dir, 'wallpaper.url');
+ const requests = path.join(dir, 'requests');
+ const ssl = path.join(bin, 'wget-ssl');
+ const downloader = `#!/bin/sh
+printf '%s\\n' "$0 $*" >> "$REQUESTS"
+[ "$FETCH_MODE" != failure ] || exit 1
+[ "$FETCH_MODE" != hang ] || sleep 20
+printf '%s' "$FETCH_PAYLOAD"
+`;
+ for (const name of ['wget-ssl', 'uclient-fetch'])
+ fs.writeFileSync(path.join(bin, name), downloader, { mode: 0o755 });
+ fs.writeFileSync(path.join(bin, 'wget'), '#!/bin/sh\necho "HTTPS support not compiled in" >&2\nexit 1\n', { mode: 0o755 });
+ fs.writeFileSync(path.join(bin, 'jsonfilter'), `#!/usr/bin/env python3
+import json,re,sys
+try:
+ value=json.load(sys.stdin)
+ for key in re.findall(r'[a-zA-Z_]+|[0-9]+',sys.argv[-1]):
+ value=value[int(key)] if isinstance(value,list) else value[key]
+ print(value)
+except (ValueError,KeyError,IndexError,TypeError):
+ sys.exit(1)
+`, { mode: 0o755 });
+ const stub = `
+uci() {
+ case "$*" in
+ *online_wallpaper) printf '%s\\n' "$WALLPAPER_SOURCE" ;;
+ *use_api_key) printf '%s\\n' fixture-key ;;
+ *use_exact_resolution) printf '1\\n' ;;
+ esac
+}
+json_init() { json_url=''; }
+json_add_string() { json_url="$2"; }
+json_dump() { printf '{"url":"%s"}\\n' "$json_url"; }
+json_cleanup() { :; }
+`;
+ const script = path.join(dir, 'rpc.sh');
+ const source = fs.readFileSync(path.join(__dirname, '../root/usr/libexec/rpcd/luci.argon_wallpaper'), 'utf8')
+ .replace('. /lib/functions.sh\n. /usr/share/libubox/jshn.sh', stub)
+ .replace('CACHE="/var/run/argon_${WEB_PIC_SRC}.url"', `CACHE="${cache}"`)
+ .replace('WRLOCK="/var/lock/argon_${WEB_PIC_SRC}.lock"', `WRLOCK="${dir}/lock"`)
+ .replace('WGET=/usr/libexec/wget-ssl', `WGET="${ssl}"`)
+ .replace('timeout -k 1 6', `timeout -k 1 ${budget}`);
+ fs.writeFileSync(script, source);
+ return {
+ cache, ssl,
+ requests: () => fs.existsSync(requests) ? fs.readFileSync(requests, 'utf8').trim().split('\n') : [],
+ call(source = 'bing', body = { images: [{ url: '/th?id=Fixture_1920x1080.jpg' }] }, mode = '') {
+ return JSON.parse(execFileSync('sh', ['-c', 'ulimit -n 64; exec sh "$@"', 'sh', script, 'call', 'get_url'], {
+ input: '{}\n', encoding: 'utf8', timeout: 3000,
+ env: { ...process.env, PATH: bin + path.delimiter + process.env.PATH,
+ REQUESTS: requests, WALLPAPER_SOURCE: source, FETCH_PAYLOAD: JSON.stringify(body), FETCH_MODE: mode }
+ }));
+ }
+ };
+}
+
+test('cold wallpaper requests use TLS despite a non-SSL wget, then reuse the cache', t => {
+ for (const [source, body, expected] of [
+ ['bing', { images: [{ url: '/th?id=Fixture_1920x1080.jpg' }] }, 'https://www.bing.com/th?id=Fixture_UHD.jpg'],
+ ['unsplash', { urls: { regular: 'https://images.unsplash.com/fixture.jpg' } }, 'https://images.unsplash.com/fixture.jpg'],
+ ['wallhaven', { data: [{ path: 'https://w.wallhaven.cc/full/fixture.jpg' }] }, 'https://w.wallhaven.cc/full/fixture.jpg']
+ ]) {
+ const f = fixture(t);
+ assert.deepEqual(f.call(source, body), { url: expected });
+ assert.equal(fs.readFileSync(f.cache, 'utf8'), expected + '\n');
+ const first = f.requests();
+ assert.ok(first.length > 0 && first.every(line => line.startsWith(f.ssl + ' ')));
+ assert.deepEqual(f.call(source, body, 'failure'), { url: expected });
+ assert.deepEqual(f.requests(), first);
+ }
+});
+
+test('source deployments use uclient-fetch when the standalone TLS binary is absent', t => {
+ const f = fixture(t);
+ fs.unlinkSync(f.ssl);
+ assert.equal(f.call().url, 'https://www.bing.com/th?id=Fixture_UHD.jpg');
+ assert.ok(f.requests().every(line => line.includes('/uclient-fetch ')));
+});
+
+test('failed wallpaper fetches return a local fallback and retry after the cooldown', t => {
+ const f = fixture(t);
+ assert.deepEqual(f.call('bing', {}, 'failure'), { url: '' });
+ assert.equal(fs.readFileSync(f.cache, 'utf8'), '');
+ assert.equal(f.requests().length, 1);
+ assert.deepEqual(f.call(), { url: '' });
+ assert.equal(f.requests().length, 1);
+ const expired = new Date(Date.now() - 122000);
+ fs.utimesSync(f.cache, expired, expired);
+ assert.equal(f.call().url, 'https://www.bing.com/th?id=Fixture_UHD.jpg');
+ assert.equal(f.requests().length, 2);
+});
+
+test('a stalled downloader cannot hold the login wallpaper RPC indefinitely', t => {
+ const f = fixture(t, '0.2');
+ const start = Date.now();
+ assert.deepEqual(f.call('bing', {}, 'hang'), { url: '' });
+ assert.ok(Date.now() - start < 2000);
+ assert.equal(fs.readFileSync(f.cache, 'utf8'), '');
+});
diff --git a/luci-theme-vantage/Makefile b/luci-theme-vantage/Makefile
index cfe690611..586153063 100644
--- a/luci-theme-vantage/Makefile
+++ b/luci-theme-vantage/Makefile
@@ -11,7 +11,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-theme-vantage
PKG_VERSION:=1.0.15
-PKG_RELEASE:=33
+PKG_RELEASE:=34
PKG_LICENSE:=GPL-3.0-or-later
LUCI_TITLE:=Vantage theme
@@ -34,6 +34,11 @@ LUCI_MINIFY_CSS:=0
LUCI_BASENAME:=vantage-theme
PKG_PO_VERSION:=$(PKG_VERSION)-r$(PKG_RELEASE)
+# Appearance for every browser (Appearance under the colour-theme button)
+define Package/luci-theme-vantage/conffiles
+/etc/config/vantage_theme
+endef
+
define Package/luci-theme-vantage/postrm
#!/bin/sh
# opkg (24.10) also runs the old package's postrm on an upgrade, as
diff --git a/luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js b/luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js
index d32576cab..18673690d 100644
--- a/luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js
+++ b/luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js
@@ -30,6 +30,35 @@ const LOGIN_KEY = 'vantage.login'; /* read by the login page's login.js */
picked here when the dashboard is installed; the dashboard listens for BACKDROP_EVENT */
const BACKDROP_KEY = 'vantage.backdrop.v1';
const BACKDROP_EVENT = 'vantage:backdrop';
+/* Appearance for every browser: saved on the router, in
+ /etc/config/vantage_theme (section appearance), by whoever may (rpcd
+ group luci-theme-vantage); header.ut and sysauth.ut hand its values over
+ as data-vt-look-, and data-vt-look-save says whether this login
+ may save: 'yes', 'relogin' (it would at a new login: one from before
+ the group existed) or 'no'. A pick made without that right stays in
+ this browser (the own key) and wins here, but not for a login that may
+ save (those keys are dropped then); this browser's last pick (the old
+ key, also what the dashboard reads under another theme) counts until
+ the router has one. */
+const LOOK = {
+ theme: { own: 'vantage.theme.own', before: THEME_KEY, ok: [ 'auto', 'light', 'dark' ] },
+ login: { own: 'vantage.login.own', before: LOGIN_KEY, ok: [ 'grid', 'stars', 'none' ] },
+ backdrop: { own: 'vantage.backdrop.own', before: BACKDROP_KEY, ok: [ 'grid', 'stars', 'none' ] }
+};
+const LOOK_SYNC = 'vantage.look'; /* another tab saved one: { name, value } */
+const LOOK_SET_EVENT = 'vantage:backdrop-set'; /* the dashboard's own picker hands its pick over */
+/* The dashboard's Customize saves its chart style and layouts with the
+ Appearance, in one write when it is done: { values, done(ok) }. The
+ template reads them back with these same rules. */
+const VIEW_SAVE_EVENT = 'vantage:view-save';
+const VIEW_CHARTS = [ 'overlay', 'log', 'mirror', 'mirror-split', 'lanes' ];
+const VIEW_LAYOUT = /^(default|[a-z]{1,8}:[0-3]:[1-4](:h)?( [a-z]{1,8}:[0-3]:[1-4](:h)?){0,7})$/;
+const callLookSet = rpc.declare({ object: 'uci', method: 'set', params: [ 'config', 'section', 'values' ], reject: true });
+const callLookCommit = rpc.declare({ object: 'uci', method: 'commit', params: [ 'config' ], reject: true });
+/* While an apply awaits its rollback, rpcd refuses commit and revert alike, but not set: a pick set
+ then could not be taken back, and would go out unseen with the next Save & Apply. So a save starts
+ with this revert, which has nothing to undo and is refused in just that case. */
+const callLookRevert = rpc.declare({ object: 'uci', method: 'revert', params: [ 'config' ], reject: true });
/* 24px stroke icons, drawn for this theme: constant [tag, attributes] lists,
built with createElementNS (no markup parsing, no user data) */
@@ -124,6 +153,30 @@ function svg(name, size) {
}
function storageGet(k) { try { return localStorage.getItem(k); } catch (e) { return null; } }
+
+/* the value in force, from [ pending, own, router, before ]: the first
+ the theme knows, else the first choice (the default); the templates'
+ inline scripts and login.js do the same without the pending one */
+function lookValue(ok, list) {
+ for (const v of list) if (ok.indexOf(v) >= 0) return v;
+ return ok[0];
+}
+function lookWrite(values) {
+ return callLookRevert('vantage_theme')
+ .then(() => callLookSet('vantage_theme', 'appearance', values))
+ .then(() => callLookCommit('vantage_theme').catch(e => callLookRevert('vantage_theme').then(() => { throw e; }, () => { throw e; })));
+}
+function viewValue(name, value) {
+ if (name === 'chart') return VIEW_CHARTS.indexOf(value) >= 0;
+ return /^layout_(wide|mid|narrow)(_wired)?$/.test(name) && typeof value === 'string' && VIEW_LAYOUT.test(value);
+}
+
+/* the router's value of one, as the templates set it (literal names) */
+function setLookAttr(root, name, value) {
+ if (name === 'theme') root.setAttribute('data-vt-look-theme', value);
+ else if (name === 'login') root.setAttribute('data-vt-look-login', value);
+ else if (name === 'backdrop') root.setAttribute('data-vt-look-backdrop', value);
+}
function storageSet(k, v) { try { if (v == null) localStorage.removeItem(k); else localStorage.setItem(k, v); } catch (e) {} }
function isTyping(el) {
@@ -775,7 +828,7 @@ return baseclass.extend({
/* Appearance opened before the menu came in lacks the network
path's group (hasDashboard): add it now */
if (this.appear && this.hasDashboard() && !this.appear.querySelector('input[name="vt-backdrop"]')) {
- this.appear.appendChild(this.backdropGroup());
+ this.appear.insertBefore(this.backdropGroup(), this.appearNote);
this.syncAppearance();
}
this.dp = (L.env.dispatchpath || []).slice();
@@ -1423,14 +1476,56 @@ return baseclass.extend({
/* -------------------------------------------------------- theme */
+ /* may this login save Appearance for every browser (header.ut): yes, relogin or no */
+ lookState() {
+ const v = this.root.getAttribute('data-vt-look-save');
+ return v === 'yes' || v === 'relogin' ? v : 'no';
+ },
+
+ /* one Appearance setting (LOOK), the value in force */
+ lookPref(name) {
+ const k = LOOK[name], mine = this.lookState() === 'yes' ? null : storageGet(k.own);
+ return lookValue(k.ok, [ (this.lookPending || {})[name], mine, this.root.getAttribute('data-vt-look-' + name), storageGet(k.before) ]);
+ },
+
+ /* Save one for every browser where this login may, else for this
+ browser. Saves queue in order and only the latest pick of each is
+ written; `apply` shows it at once and again when done. A save that
+ fails leaves the pick shown on this page, with a note. */
+ setLook(name, value, apply) {
+ const k = LOOK[name];
+ const pending = this.lookPending || (this.lookPending = {});
+ if (k.ok.indexOf(value) < 0 || pending[name] === value) return;
+ if (this.lookState() !== 'yes') {
+ storageSet(k.own, value);
+ storageSet(k.before, value);
+ apply();
+ return;
+ }
+ const seqs = this.lookSeqs || (this.lookSeqs = {}), seq = seqs[name] = (seqs[name] || 0) + 1;
+ pending[name] = value;
+ this.lookFailed = false;
+ apply();
+ const latest = () => seqs[name] === seq;
+ this.lookChain = (this.lookChain || Promise.resolve()).then(() => {
+ if (!latest()) return;
+ return lookWrite({ [name]: value })
+ .then(() => {
+ /* the router's value first, so other tabs never see a gap */
+ setLookAttr(this.root, name, value);
+ storageSet(LOOK_SYNC, JSON.stringify({ name: name, value: value, at: Date.now() }));
+ storageSet(k.before, value);
+ if (latest()) delete pending[name];
+ }, () => { if (latest()) this.lookFailed = true; });
+ }).then(apply);
+ },
+
themePref() {
- const p = storageGet(THEME_KEY);
- return (p === 'light' || p === 'dark') ? p : 'auto';
+ return this.lookPref('theme');
},
setTheme(pref) {
- storageSet(THEME_KEY, pref === 'auto' ? null : pref);
- this.applyTheme();
+ this.setLook('theme', pref, () => this.applyTheme());
},
applyTheme() {
@@ -1450,8 +1545,7 @@ return baseclass.extend({
/* the login page's backdrop (login.js): grid packets unless set */
loginPref() {
- const p = storageGet(LOGIN_KEY);
- return (p === 'stars' || p === 'none') ? p : 'grid';
+ return this.lookPref('login');
},
loginNames() {
@@ -1459,8 +1553,7 @@ return baseclass.extend({
},
setLoginPref(pref) {
- storageSet(LOGIN_KEY, pref === 'grid' ? null : pref);
- this.syncAppearance();
+ this.setLook('login', pref, () => this.syncAppearance());
},
/* Vantage's dashboard, where this user may open it: its network path
@@ -1470,13 +1563,20 @@ return baseclass.extend({
},
backdropPref() {
- const p = storageGet(BACKDROP_KEY);
- return (p === 'stars' || p === 'none') ? p : 'grid';
+ return this.lookPref('backdrop');
},
setBackdropPref(pref) {
- storageSet(BACKDROP_KEY, pref === 'grid' ? null : pref);
- window.dispatchEvent(new CustomEvent(BACKDROP_EVENT));
+ this.setLook('backdrop', pref, () => this.applyBackdrop());
+ },
+
+ /* the dashboard reads the one in force from data-vt-backdrop */
+ applyBackdrop() {
+ const v = this.backdropPref();
+ if (this.root.getAttribute('data-vt-backdrop') !== v) {
+ this.root.setAttribute('data-vt-backdrop', v);
+ window.dispatchEvent(new CustomEvent(BACKDROP_EVENT));
+ }
this.syncAppearance();
},
@@ -1495,11 +1595,42 @@ return baseclass.extend({
}
const mq = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)');
if (mq && mq.addEventListener) mq.addEventListener('change', () => { if (this.themePref() === 'auto') this.applyTheme(); });
+ /* a login that may save: this browser's private picks no longer count */
+ if (this.lookState() === 'yes') Object.keys(LOOK).forEach(n => storageSet(LOOK[n].own, null));
+ /* another tab of this browser changed one, or saved one on the router */
+ const keys = [ LOOK_SYNC ];
+ Object.keys(LOOK).forEach(n => keys.push(LOOK[n].own, LOOK[n].before));
window.addEventListener('storage', ev => {
- if (ev.key === THEME_KEY) this.applyTheme();
- else if (ev.key === LOGIN_KEY || ev.key === BACKDROP_KEY) this.syncAppearance();
+ if (keys.indexOf(ev.key) < 0) return;
+ if (ev.key === LOOK_SYNC) {
+ let m = null;
+ try { m = JSON.parse(ev.newValue); } catch (e) {}
+ if (m && Object.prototype.hasOwnProperty.call(LOOK, m.name) && LOOK[m.name].ok.indexOf(m.value) >= 0)
+ setLookAttr(this.root, m.name, m.value);
+ }
+ this.applyTheme();
+ this.applyBackdrop();
+ });
+ /* the dashboard's own picker (Customize), saved as Appearance's */
+ window.addEventListener(LOOK_SET_EVENT, ev => {
+ if (ev.detail && LOOK.backdrop.ok.indexOf(ev.detail) >= 0) {
+ ev.preventDefault();
+ this.setBackdropPref(ev.detail);
+ }
+ });
+ /* Customize's Done, for a login that may save; for any other it
+ stays in that browser, which the dashboard says */
+ window.addEventListener(VIEW_SAVE_EVENT, ev => {
+ const d = ev.detail, values = {};
+ if (this.lookState() !== 'yes' || !d || !d.values || typeof d.done !== 'function') return;
+ Object.keys(d.values).forEach(n => { if (viewValue(n, d.values[n])) values[n] = d.values[n]; });
+ if (!Object.keys(values).length) return;
+ ev.preventDefault();
+ this.lookChain = (this.lookChain || Promise.resolve()).then(() => lookWrite(values))
+ .then(() => d.done(true), () => d.done(false)).catch(() => {});
});
this.applyTheme();
+ this.applyBackdrop();
},
/* Appearance, under the colour-theme button: the colour theme, the
@@ -1535,7 +1666,10 @@ return baseclass.extend({
[ 'auto', _('Auto', 'vantage-theme'), 'auto' ], [ 'light', _('Light', 'vantage-theme'), 'sun' ], [ 'dark', _('Dark', 'vantage-theme'), 'moon' ]
], v => this.setTheme(v)),
group('vt-login', _('Login background'), [ [ 'grid', login.grid ], [ 'stars', login.stars ], [ 'none', login.none ] ], v => this.setLoginPref(v))
- ].concat(this.hasDashboard() ? [ this.backdropGroup() ] : []));
+ ].concat(this.hasDashboard() ? [ this.backdropGroup() ] : [], [
+ /* where the picks are kept, when not for every browser (syncAppearance) */
+ (this.appearNote = E('p', { 'class': 'vt-appear-note', 'role': 'status', 'hidden': 'hidden' }))
+ ]));
box.addEventListener('keydown', ev => {
if (ev.key === 'Escape') { ev.preventDefault(); ev.stopPropagation(); this.closeAppearance(true); }
else if (ev.key === 'Tab') {
@@ -1561,6 +1695,14 @@ return baseclass.extend({
if (!this.appear) return;
const now = { 'vt-colour': this.themePref(), 'vt-login': this.loginPref(), 'vt-backdrop': this.backdropPref() };
Array.prototype.forEach.call(this.appear.querySelectorAll('input[type="radio"]'), r => { r.checked = (now[r.name] === r.value); });
+ const state = this.lookState();
+ const note = state === 'relogin' ? _('Log in again to save Appearance for every browser.')
+ : state !== 'yes' ? _('Saved in this browser only.')
+ : this.lookFailed ? _('Could not save this for every browser. Try again.') : '';
+ if (this.appearNote) {
+ if (this.appearNote.textContent !== note) this.appearNote.textContent = note;
+ this.appearNote.hidden = !note;
+ }
},
openAppearance(btn) {
diff --git a/luci-theme-vantage/htdocs/luci-static/vantage/login.js b/luci-theme-vantage/htdocs/luci-static/vantage/login.js
index 4a9d73928..901afc629 100644
--- a/luci-theme-vantage/htdocs/luci-static/vantage/login.js
+++ b/luci-theme-vantage/htdocs/luci-static/vantage/login.js
@@ -1,16 +1,19 @@
/*
* Vantage theme - login page backdrop, over the page grid: packets running
* along the grid lines (the default) or a starfield flown through, as
- * picked under Appearance (localStorage vantage.login, per browser: unset,
- * "stars" or "none"). One canvas, no libraries: a frame is a handful of
- * batched draws, at most about 60 a second, and nothing runs while the
+ * picked under Appearance: saved for every browser on the router
+ * (sysauth.ut's data-vt-look-login), else in this browser (localStorage
+ * vantage.login.own for one who may not save it for everyone, vantage.login
+ * from before; menu-vantage.js lookValue). One canvas, no libraries: a
+ * frame is a handful of batched draws, at most about 60 a second, and nothing runs while the
* window is in the background. With reduced motion it draws one still
* frame. Logging in speeds it up while the form posts.
*/
(function () {
'use strict';
- var pick = null;
- try { pick = localStorage.getItem('vantage.login'); } catch (e) {}
+ var v = [ null, document.documentElement.getAttribute('data-vt-look-login'), null ], ok = [ 'grid', 'stars', 'none' ], pick = 'grid', i;
+ try { v[0] = localStorage.getItem('vantage.login.own'); v[2] = localStorage.getItem('vantage.login'); } catch (e) {}
+ for (i = 2; i >= 0; i--) if (ok.indexOf(v[i]) >= 0) pick = v[i];
if (pick === 'none') return;
var cv = document.createElement('canvas'), ctx = cv.getContext && cv.getContext('2d');
if (!ctx || typeof Path2D !== 'function') return;
diff --git a/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css b/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css
index f865357ea..14f6d5ce2 100644
--- a/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css
+++ b/luci-theme-vantage/htdocs/luci-static/vantage/vantage.css
@@ -623,6 +623,9 @@ a.vt-crumb:hover { color: var(--text); }
}
.vt-appearance[hidden] { display: none; }
.vt-appear-set { min-width: 0; margin: 0; padding: 0; border: 0; }
+/* where the picks are kept, when not for every browser */
+.vt-appear-note { max-width: 32ch; margin: 0; color: var(--text-3); font-size: var(--fs-sm); line-height: 1.4; }
+.vt-appear-note[hidden] { display: none; }
.vt-appear-set > legend { margin: 0 0 6px; padding: 0; color: var(--text-3); font-size: var(--fs-micro); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; }
.vt-appear-track { display: flex; background: var(--seg-bg); border-radius: var(--r-lg); box-shadow: inset 0 0 0 1px var(--line); }
.vt-appear-opt {
diff --git a/luci-theme-vantage/po/templates/vantage-theme.pot b/luci-theme-vantage/po/templates/vantage-theme.pot
index 51f2b938a..719ca5668 100644
--- a/luci-theme-vantage/po/templates/vantage-theme.pot
+++ b/luci-theme-vantage/po/templates/vantage-theme.pot
@@ -13,7 +13,7 @@ msgid_plural "%d more chains at this hook"
msgstr[0] ""
msgstr[1] ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1350
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1403
msgctxt "vantage-theme"
msgid "%d result"
msgid_plural "%d results"
@@ -56,7 +56,7 @@ msgctxt "vantage-theme"
msgid "Accept"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1270
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1323
msgid "Actions"
msgstr ""
@@ -65,22 +65,22 @@ msgctxt "nft match any traffic"
msgid "Any packet"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1258
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1259
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1260
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1263
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1267
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1533
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:84
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1311
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1312
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1313
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1316
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1320
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1664
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:132
msgctxt "vantage-theme"
msgid "Appearance"
msgstr ""
-#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:41
+#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:48
msgid "Authorization Required"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1535
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1666
msgctxt "vantage-theme"
msgid "Auto"
msgstr ""
@@ -95,7 +95,7 @@ msgctxt "vantage-theme"
msgid "Back to the calling chain"
msgstr ""
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:72
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:120
msgctxt "vantage-theme"
msgid "Breadcrumb"
msgstr ""
@@ -113,17 +113,17 @@ msgctxt "vantage-theme"
msgid "Bridged between ports"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:409
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:462
msgid "Buffered"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:420
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:430
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:434
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:473
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:483
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:487
msgid "Cache"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:409
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:462
msgid "Cached"
msgstr ""
@@ -142,19 +142,19 @@ msgctxt "vantage-theme"
msgid "Chains no rule jumps to directly"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:491
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:544
msgid "Channel"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:897
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:950
msgid "Collapse navigation"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1534
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1665
msgid "Colour theme"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1294
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1347
msgid "Command palette"
msgstr ""
@@ -173,7 +173,11 @@ msgctxt "vantage-theme"
msgid "Continues in %s, then comes back here"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1535
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1701
+msgid "Could not save this for every browser. Try again."
+msgstr ""
+
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1666
msgctxt "vantage-theme"
msgid "Dark"
msgstr ""
@@ -197,8 +201,8 @@ msgstr ""
msgid "Egress"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:897
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:57
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:950
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:105
msgid "Expand navigation"
msgstr ""
@@ -215,7 +219,7 @@ msgid ""
"their counters see only its first packets."
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1260
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1313
msgid "Follow system theme"
msgstr ""
@@ -233,17 +237,17 @@ msgid ""
"if br_netfilter is enabled; the ruleset doesn't show that.)"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:421
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:435
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:474
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:488
msgctxt "vantage-theme"
msgid "Free"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1458
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1552
msgid "Grid packets"
msgstr ""
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:52
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:100
msgctxt "vantage-theme"
msgid "Home"
msgstr ""
@@ -260,9 +264,9 @@ msgstr ""
msgid "IPv6 traffic table \"%h\""
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:420
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:429
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:433
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:473
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:482
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:486
msgctxt "vantage-theme"
msgid "In use"
msgstr ""
@@ -276,11 +280,11 @@ msgctxt "vantage-theme"
msgid "Input"
msgstr ""
-#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:45
+#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:52
msgid "Invalid username and/or password! Please try again."
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1290
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1343
msgid "Jump to a page or action…"
msgstr ""
@@ -289,27 +293,31 @@ msgctxt "vantage-theme"
msgid "Leaves unmatched unchanged"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1535
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1666
msgctxt "vantage-theme"
msgid "Light"
msgstr ""
-#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:23
-#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:57
+#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:28
+#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:64
msgid "Log in"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1269
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:87
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1699
+msgid "Log in again to save Appearance for every browser."
+msgstr ""
+
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1322
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:135
msgid "Log out"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1263
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1537
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1316
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1668
msgid "Login background"
msgstr ""
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:51
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:99
msgctxt "vantage-theme"
msgid "Main navigation"
msgstr ""
@@ -319,13 +327,13 @@ msgctxt "vantage-theme"
msgid "Masquerade"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:404
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:419
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:457
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:472
msgid "Memory"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1806
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1823
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1948
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1965
msgctxt "vantage-theme"
msgid "More actions"
msgstr ""
@@ -343,8 +351,8 @@ msgstr ""
msgid "Network device table \"%h\""
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1267
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1526
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1320
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1657
msgid "Network path background"
msgstr ""
@@ -353,7 +361,7 @@ msgctxt "vantage-theme"
msgid "Next rule"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1348
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1401
msgid "No matching pages"
msgstr ""
@@ -367,17 +375,17 @@ msgctxt "vantage-theme"
msgid "No rules: %s"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1458
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1552
msgctxt "vantage-theme"
msgid "None"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1165
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1218
#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:17
msgid "Not found"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1185
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1238
msgid "Other pages in %s"
msgstr ""
@@ -391,7 +399,7 @@ msgctxt "vantage-theme"
msgid "Packet path"
msgstr ""
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:93
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:141
msgid "Page tabs"
msgstr ""
@@ -405,7 +413,7 @@ msgctxt "vantage-theme"
msgid "Passes unmatched"
msgstr ""
-#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:54
+#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:61
msgid "Password"
msgstr ""
@@ -434,7 +442,7 @@ msgctxt "vantage-theme"
msgid "Reject"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1292
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1345
msgctxt "vantage-theme"
msgid "Results"
msgstr ""
@@ -454,13 +462,17 @@ msgctxt "vantage-theme"
msgid "Rules table"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1290
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:75
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:77
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1700
+msgid "Saved in this browser only."
+msgstr ""
+
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1343
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:123
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:125
msgid "Search pages"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1269
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1322
msgid "Session"
msgstr ""
@@ -471,33 +483,33 @@ msgid_plural "Show %d more rules"
msgstr[0] ""
msgstr[1] ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1963
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:2105
msgid "Show full description"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1952
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:2094
msgid "Show full help: %s"
msgstr ""
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:48
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:96
msgid "Skip to content"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1458
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1552
msgid "Starfield"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:456
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:509
msgid "Storage"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:442
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:444
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:495
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:497
msgctxt "vantage-theme"
msgid "Swap"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:409
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:462
msgid "Swap free"
msgstr ""
@@ -506,12 +518,12 @@ msgctxt "vantage-theme"
msgid "This device"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:421
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:474
msgctxt "vantage-theme"
msgid "Total"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:408
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:461
msgid "Total Available"
msgstr ""
@@ -525,22 +537,29 @@ msgctxt "vantage-theme"
msgid "Unchanged"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1258
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1311
msgid "Use dark theme"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1259
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1312
msgid "Use light theme"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:408
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:461
msgid "Used"
msgstr ""
-#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:50
+#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:57
msgid "Username"
msgstr ""
+#: luci-theme-vantage/root/usr/share/rpcd/acl.d/luci-theme-vantage.json:3
+msgid ""
+"Vantage theme: save its Appearance (colour mode, login and network path "
+"backgrounds) and the dashboard's chart style and layouts for every browser, "
+"in /etc/config/vantage_theme only"
+msgstr ""
+
#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:454
msgctxt "vantage-theme"
msgid "Verdict map %s"
@@ -551,16 +570,16 @@ msgctxt "vantage-theme"
msgid "View"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:484
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:537
msgid "Wireless"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:425
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:478
msgctxt "vantage-theme"
msgid "available"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1300
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1353
msgid "close"
msgstr ""
@@ -574,12 +593,12 @@ msgctxt "vantage-theme"
msgid "drops unmatched %s"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:471
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:475
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:524
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:528
msgid "free"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1298
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1351
msgid "navigate"
msgstr ""
@@ -598,7 +617,7 @@ msgctxt "vantage-theme"
msgid "on %s"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1299
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1352
msgctxt "vantage-theme"
msgid "open"
msgstr ""
@@ -608,9 +627,9 @@ msgctxt "vantage-theme"
msgid "priority %d"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:420
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:430
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:434
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:473
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:483
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:487
msgid "reclaimable"
msgstr ""
@@ -619,12 +638,12 @@ msgctxt "vantage-theme"
msgid "rules drop some"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:471
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:475
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:524
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:528
msgid "total"
msgstr ""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:471
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:475
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:524
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:528
msgid "used"
msgstr ""
diff --git a/luci-theme-vantage/po/zh_Hans/vantage-theme.po b/luci-theme-vantage/po/zh_Hans/vantage-theme.po
index 349beedd2..a451d451e 100644
--- a/luci-theme-vantage/po/zh_Hans/vantage-theme.po
+++ b/luci-theme-vantage/po/zh_Hans/vantage-theme.po
@@ -21,7 +21,7 @@ msgid "%d more chain at this hook"
msgid_plural "%d more chains at this hook"
msgstr[0] "此钩子还有 %d 条链"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1350
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1403
msgctxt "vantage-theme"
msgid "%d result"
msgid_plural "%d results"
@@ -62,7 +62,7 @@ msgctxt "vantage-theme"
msgid "Accept"
msgstr "接受"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1270
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1323
msgid "Actions"
msgstr "操作"
@@ -71,22 +71,22 @@ msgctxt "nft match any traffic"
msgid "Any packet"
msgstr "任意数据包"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1258
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1259
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1260
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1263
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1267
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1533
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:84
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1311
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1312
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1313
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1316
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1320
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1664
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:132
msgctxt "vantage-theme"
msgid "Appearance"
msgstr "外观"
-#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:41
+#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:48
msgid "Authorization Required"
msgstr "需要授权"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1535
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1666
msgctxt "vantage-theme"
msgid "Auto"
msgstr "自动"
@@ -101,7 +101,7 @@ msgctxt "vantage-theme"
msgid "Back to the calling chain"
msgstr "返回调用链"
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:72
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:120
msgctxt "vantage-theme"
msgid "Breadcrumb"
msgstr "面包屑"
@@ -119,17 +119,17 @@ msgctxt "vantage-theme"
msgid "Bridged between ports"
msgstr "端口间桥接"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:409
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:462
msgid "Buffered"
msgstr "已缓冲"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:420
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:430
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:434
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:473
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:483
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:487
msgid "Cache"
msgstr "缓存"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:409
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:462
msgid "Cached"
msgstr "已缓存"
@@ -148,19 +148,19 @@ msgctxt "vantage-theme"
msgid "Chains no rule jumps to directly"
msgstr "没有规则直接跳转到的链"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:491
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:544
msgid "Channel"
msgstr "信道"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:897
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:950
msgid "Collapse navigation"
msgstr "收起导航"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1534
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1665
msgid "Colour theme"
msgstr "颜色主题"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1294
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1347
msgid "Command palette"
msgstr "命令面板"
@@ -179,7 +179,11 @@ msgctxt "vantage-theme"
msgid "Continues in %s, then comes back here"
msgstr "转入 %s,随后返回此处"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1535
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1701
+msgid "Could not save this for every browser. Try again."
+msgstr "无法为所有浏览器保存此设置,请重试。"
+
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1666
msgctxt "vantage-theme"
msgid "Dark"
msgstr "深色"
@@ -203,8 +207,8 @@ msgstr "丢弃未匹配流量"
msgid "Egress"
msgstr "出口"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:897
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:57
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:950
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:105
msgid "Expand navigation"
msgstr "展开导航"
@@ -223,7 +227,7 @@ msgstr ""
"流量卸载已开启:一条转发连接建立后,它的数据包可以跳过 prerouting、forward "
"和 postrouting,因此这些链和它们的计数器只会看到该连接最初的数据包。"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1260
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1313
msgid "Follow system theme"
msgstr "跟随系统主题"
@@ -244,17 +248,17 @@ msgstr ""
"达 input、forward 或 output 链,这里也没有桥接链会过滤它们。(启用 "
"br_netfilter 时内核可以把它们交给 IP 链;规则集不体现这一点。)"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:421
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:435
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:474
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:488
msgctxt "vantage-theme"
msgid "Free"
msgstr "空闲"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1458
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1552
msgid "Grid packets"
msgstr "网格数据包"
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:52
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:100
msgctxt "vantage-theme"
msgid "Home"
msgstr "首页"
@@ -271,9 +275,9 @@ msgstr "IPv4/IPv6 流量表 \"%h\""
msgid "IPv6 traffic table \"%h\""
msgstr "IPv6 流量表 \"%h\""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:420
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:429
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:433
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:473
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:482
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:486
msgctxt "vantage-theme"
msgid "In use"
msgstr "已用"
@@ -287,11 +291,11 @@ msgctxt "vantage-theme"
msgid "Input"
msgstr "输入"
-#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:45
+#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:52
msgid "Invalid username and/or password! Please try again."
msgstr "用户名或密码错误,请重试。"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1290
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1343
msgid "Jump to a page or action…"
msgstr "跳转到页面或操作…"
@@ -300,27 +304,31 @@ msgctxt "vantage-theme"
msgid "Leaves unmatched unchanged"
msgstr "未匹配流量保持原样"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1535
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1666
msgctxt "vantage-theme"
msgid "Light"
msgstr "浅色"
-#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:23
-#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:57
+#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:28
+#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:64
msgid "Log in"
msgstr "登录"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1269
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:87
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1699
+msgid "Log in again to save Appearance for every browser."
+msgstr "重新登录后即可为所有浏览器保存外观设置。"
+
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1322
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:135
msgid "Log out"
msgstr "退出登录"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1263
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1537
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1316
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1668
msgid "Login background"
msgstr "登录背景"
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:51
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:99
msgctxt "vantage-theme"
msgid "Main navigation"
msgstr "主导航"
@@ -330,13 +338,13 @@ msgctxt "vantage-theme"
msgid "Masquerade"
msgstr "伪装(NAT)"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:404
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:419
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:457
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:472
msgid "Memory"
msgstr "内存"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1806
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1823
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1948
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1965
msgctxt "vantage-theme"
msgid "More actions"
msgstr "更多操作"
@@ -354,8 +362,8 @@ msgstr "网络"
msgid "Network device table \"%h\""
msgstr "网络设备表 \"%h\""
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1267
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1526
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1320
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1657
msgid "Network path background"
msgstr "网络路径背景"
@@ -364,7 +372,7 @@ msgctxt "vantage-theme"
msgid "Next rule"
msgstr "下一条规则"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1348
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1401
msgid "No matching pages"
msgstr "没有匹配的页面"
@@ -378,17 +386,17 @@ msgctxt "vantage-theme"
msgid "No rules: %s"
msgstr "无规则:%s"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1458
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1552
msgctxt "vantage-theme"
msgid "None"
msgstr "无"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1165
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1218
#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:17
msgid "Not found"
msgstr "未找到"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1185
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1238
msgid "Other pages in %s"
msgstr "%s 中的其他页面"
@@ -402,7 +410,7 @@ msgctxt "vantage-theme"
msgid "Packet path"
msgstr "数据包路径"
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:93
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:141
msgid "Page tabs"
msgstr "页面标签页"
@@ -416,7 +424,7 @@ msgctxt "vantage-theme"
msgid "Passes unmatched"
msgstr "放行未匹配流量"
-#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:54
+#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:61
msgid "Password"
msgstr "密码"
@@ -445,7 +453,7 @@ msgctxt "vantage-theme"
msgid "Reject"
msgstr "拒绝"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1292
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1345
msgctxt "vantage-theme"
msgid "Results"
msgstr "结果"
@@ -465,13 +473,17 @@ msgctxt "vantage-theme"
msgid "Rules table"
msgstr "规则表"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1290
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:75
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:77
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1700
+msgid "Saved in this browser only."
+msgstr "仅保存在此浏览器中。"
+
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1343
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:123
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:125
msgid "Search pages"
msgstr "搜索页面"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1269
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1322
msgid "Session"
msgstr "会话"
@@ -481,33 +493,33 @@ msgid "Show %d more rule"
msgid_plural "Show %d more rules"
msgstr[0] "再显示 %d 条规则"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1963
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:2105
msgid "Show full description"
msgstr "显示完整描述"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1952
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:2094
msgid "Show full help: %s"
msgstr "显示完整帮助:%s"
-#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:48
+#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:96
msgid "Skip to content"
msgstr "跳至正文"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1458
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1552
msgid "Starfield"
msgstr "星空"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:456
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:509
msgid "Storage"
msgstr "存储"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:442
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:444
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:495
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:497
msgctxt "vantage-theme"
msgid "Swap"
msgstr "交换空间"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:409
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:462
msgid "Swap free"
msgstr "空闲交换空间"
@@ -516,12 +528,12 @@ msgctxt "vantage-theme"
msgid "This device"
msgstr "本设备"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:421
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:474
msgctxt "vantage-theme"
msgid "Total"
msgstr "总计"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:408
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:461
msgid "Total Available"
msgstr "总可用"
@@ -535,22 +547,29 @@ msgctxt "vantage-theme"
msgid "Unchanged"
msgstr "不变"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1258
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1311
msgid "Use dark theme"
msgstr "使用深色主题"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1259
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1312
msgid "Use light theme"
msgstr "使用浅色主题"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:408
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:461
msgid "Used"
msgstr "已用"
-#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:50
+#: luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut:57
msgid "Username"
msgstr "用户名"
+#: luci-theme-vantage/root/usr/share/rpcd/acl.d/luci-theme-vantage.json:3
+msgid ""
+"Vantage theme: save its Appearance (colour mode, login and network path "
+"backgrounds) and the dashboard's chart style and layouts for every browser, "
+"in /etc/config/vantage_theme only"
+msgstr "Vantage 主题:为所有浏览器保存其外观设置(颜色模式、登录页与网络路径背景)以及仪表盘的图表样式和布局,仅写入 /etc/config/vantage_theme"
+
#: luci-theme-vantage/htdocs/luci-static/resources/vantage-theme/nftflow.js:454
msgctxt "vantage-theme"
msgid "Verdict map %s"
@@ -561,16 +580,16 @@ msgctxt "vantage-theme"
msgid "View"
msgstr "视图"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:484
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:537
msgid "Wireless"
msgstr "无线"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:425
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:478
msgctxt "vantage-theme"
msgid "available"
msgstr "可用"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1300
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1353
msgid "close"
msgstr "关闭"
@@ -584,12 +603,12 @@ msgctxt "vantage-theme"
msgid "drops unmatched %s"
msgstr "丢弃未匹配的 %s"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:471
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:475
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:524
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:528
msgid "free"
msgstr "空闲"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1298
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1351
msgid "navigate"
msgstr "移动"
@@ -608,7 +627,7 @@ msgctxt "vantage-theme"
msgid "on %s"
msgstr "接口 %s"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1299
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1352
msgctxt "vantage-theme"
msgid "open"
msgstr "打开"
@@ -618,9 +637,9 @@ msgctxt "vantage-theme"
msgid "priority %d"
msgstr "优先级 %d"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:420
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:430
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:434
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:473
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:483
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:487
msgid "reclaimable"
msgstr "可回收"
@@ -629,16 +648,23 @@ msgctxt "vantage-theme"
msgid "rules drop some"
msgstr "部分规则会丢弃"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:471
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:475
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:524
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:528
msgid "total"
msgstr "总计"
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:471
-#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:475
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:524
+#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:528
msgid "used"
msgstr "已用"
+#~ msgid ""
+#~ "Vantage theme: save its Appearance (colour mode, login and network path "
+#~ "backgrounds) for every browser, in /etc/config/vantage_theme only"
+#~ msgstr ""
+#~ "Vantage 主题:为所有浏览器保存其外观设置(颜色模式、登录页与网络路径背"
+#~ "景),仅写入 /etc/config/vantage_theme"
+
#~ msgctxt "vantage-theme"
#~ msgid "Press"
#~ msgstr "按"
diff --git a/luci-theme-vantage/root/etc/config/vantage_theme b/luci-theme-vantage/root/etc/config/vantage_theme
new file mode 100644
index 000000000..2ca9ce0c3
--- /dev/null
+++ b/luci-theme-vantage/root/etc/config/vantage_theme
@@ -0,0 +1,14 @@
+# Vantage theme settings (luci-theme-vantage).
+#
+# Appearance for every browser on this router, as picked under the theme's
+# Appearance button; an option left out keeps each browser's own pick:
+#
+# option theme 'auto' auto, light or dark
+# option login 'grid' the login page's background: grid, stars or none
+# option backdrop 'grid' the dashboard's network path background, likewise
+#
+# The dashboard's Customize saves here too: its chart style (option chart) and
+# one layout per screen size (option layout_wide, layout_mid, layout_narrow and
+# the same with _wired), which are best changed there.
+
+config appearance 'appearance'
diff --git a/luci-theme-vantage/root/usr/share/rpcd/acl.d/luci-theme-vantage.json b/luci-theme-vantage/root/usr/share/rpcd/acl.d/luci-theme-vantage.json
new file mode 100644
index 000000000..c4bd30798
--- /dev/null
+++ b/luci-theme-vantage/root/usr/share/rpcd/acl.d/luci-theme-vantage.json
@@ -0,0 +1,11 @@
+{
+ "luci-theme-vantage": {
+ "description": "Vantage theme: save its Appearance (colour mode, login and network path backgrounds) and the dashboard's chart style and layouts for every browser, in /etc/config/vantage_theme only",
+ "write": {
+ "ubus": {
+ "uci": [ "set", "commit", "revert" ]
+ },
+ "uci": [ "vantage_theme" ]
+ }
+ }
+}
diff --git a/luci-theme-vantage/ucode/template/themes/vantage/header.ut b/luci-theme-vantage/ucode/template/themes/vantage/header.ut
index 5166f0b13..a73c52347 100644
--- a/luci-theme-vantage/ucode/template/themes/vantage/header.ut
+++ b/luci-theme-vantage/ucode/template/themes/vantage/header.ut
@@ -16,11 +16,48 @@
const found = !!dispatched?.action?.type && dispatched.action.type != 'firstchild';
const page_title = !authed ? null : !found ? _('Not found') : dispatched?.title ? striptags(_(dispatched.title)) : null;
const lang = entityencode(dispatcher.lang ?? 'en', true);
- const boardinfo = ubus.call("system", "board");
- const hostname = striptags(boardinfo?.hostname ?? '?');
+ /* Appearance for every browser (/etc/config/vantage_theme): a value the
+ theme knows, else '' (each browser keeps its own pick). Logged in only:
+ nothing is read for an anonymous 404 or CSRF page */
+ const look = (opt, ok) => { const v = authed ? uci.get('vantage_theme', 'appearance', opt) : null; return (type(v) == 'string' && index(ok, v) >= 0) ? v : ''; };
+ const look_theme = look('theme', [ 'auto', 'light', 'dark' ]);
+ const look_login = look('login', [ 'grid', 'stars', 'none' ]);
+ const look_backdrop = look('backdrop', [ 'grid', 'stars', 'none' ]);
+ /* The dashboard's chart style and layouts, saved with it. A layout passes
+ only in the form vantage.layout reads, 'wide=hero:0:4 chart:0:2:h;mid=default' */
+ const look_chart = look('chart', [ 'overlay', 'log', 'mirror', 'mirror-split', 'lanes' ]);
+ const look_layout = (() => {
+ let out = [];
+ if (authed)
+ for (let k in [ 'wide', 'mid', 'narrow', 'wide_wired', 'mid_wired', 'narrow_wired' ]) {
+ const v = uci.get('vantage_theme', 'appearance', 'layout_' + k);
+ if (type(v) == 'string' && match(v, /^(default|[a-z]{1,8}:[0-3]:[1-4](:h)?( [a-z]{1,8}:[0-3]:[1-4](:h)?){0,7})$/))
+ push(out, k + '=' + v);
+ }
+ return join(';', out);
+ })();
+ /* May this login save it for every browser? 'yes'; 'relogin' when rpcd
+ would grant the theme's group at a new login and no reload of rpcd
+ has given it to this one yet (the install's reload reaches open
+ logins); 'no' otherwise, and without the config's section. Only the
+ word reaches the page. */
+ const look_save = (() => {
+ if (!authed || type(uci.get_all('vantage_theme', 'appearance')) != 'object') return 'no';
+ const held = ctx.authacl?.['access-group']?.['luci-theme-vantage'];
+ if (type(held) == 'array' && index(held, 'write') >= 0) return 'yes';
+ let would = false;
+ uci.foreach('rpcd', 'login', s => {
+ if (s.username !== ctx.authuser) return;
+ for (let p in (type(s.write) == 'array' ? s.write : [ s.write ]))
+ if (type(p) == 'string' && wildcard('luci-theme-vantage', p)) would = true;
+ });
+ return would ? 'relogin' : 'no';
+ })();
+const boardinfo = ubus.call("system", "board");
+const hostname = striptags(boardinfo?.hostname ?? '?');
-%}
-
+
@@ -28,11 +65,22 @@
{{ page_title ? entityencode(page_title, true) + ' · ' : '' }}LuCI
diff --git a/luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut b/luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut
index 30354fe88..23c4704e7 100644
--- a/luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut
+++ b/luci-theme-vantage/ucode/template/themes/vantage/sysauth.ut
@@ -5,18 +5,23 @@
fuser is attacker-controlled (formvalue also reads the query string): it is
only tested, never echoed; the error is generic. The form posts back to the
requested URL (no action attribute). The inline script is data-free: the
- HTTPS probe reads its port list from an entity-encoded data attribute.
+ HTTPS probe reads its port list from an entity-encoded data attribute. The
+ Appearance saved for every browser (/etc/config/vantage_theme) comes as
+ data attributes of values the theme knows only.
-#}
{%
let tls = uci.get('uhttpd', 'main', 'listen_https') ?? [];
if (type(tls) == 'string')
tls = split(tls, /\s+/);
const tls_ports = uniq(filter(map(tls, e => +(match(e, /\d+$/)?.[0] ?? 0)), p => (p > 0 && p <= 65535)));
+ const look = (opt, ok) => { const v = uci.get('vantage_theme', 'appearance', opt); return (type(v) == 'string' && index(ok, v) >= 0) ? v : ''; };
+ const look_theme = look('theme', [ 'auto', 'light', 'dark' ]);
+ const look_login = look('login', [ 'grid', 'stars', 'none' ]);
const boardinfo = ubus.call("system", "board");
const hostname = striptags(boardinfo?.hostname ?? '?');
-%}
-
+
@@ -25,8 +30,10 @@
{{ entityencode(_('Log in'), true) }} · LuCI