🛸 Sync 2026-10-18 10:48:36

This commit is contained in:
github-actions[bot] committed 2026-10-18 10:48:36 +08:00
1 parent 61e7ec8357
commit 2a4fb97efd
21 files changed
+1217 -823

No files matched your search

+2 -2
View File
@@ -11,8 +11,8 @@ LUCI_DESCRIPTION:=Live firewall log table (firewall4/nft; iptables-tagged lines
LUCI_DEPENDS:=+luci-base +logd +jsonfilter LUCI_DEPENDS:=+luci-base +logd +jsonfilter
LUCI_PKGARCH:=all LUCI_PKGARCH:=all
PKG_VERSION:=0.1.53 PKG_VERSION:=0.1.54
PKG_RELEASE:=69 PKG_RELEASE:=70
# Reproducible build: honor SOURCE_DATE_EPOCH from the build environment (set by docker-sdk.sh / CI). # Reproducible build: honor SOURCE_DATE_EPOCH from the build environment (set by docker-sdk.sh / CI).
ifdef SOURCE_DATE_EPOCH ifdef SOURCE_DATE_EPOCH
@@ -9,7 +9,7 @@
*/ */
return baseclass.extend({ return baseclass.extend({
/* Keep in sync with openwrt-feed/luci-app-fwlive/Makefile PKG_VERSION. */ /* Keep in sync with openwrt-feed/luci-app-fwlive/Makefile PKG_VERSION. */
APP_VERSION: '0.1.53', APP_VERSION: '0.1.54',
ROW_LIMIT_OPTIONS: [25, 50, 100, 250, 500, 1000, 2000], ROW_LIMIT_OPTIONS: [25, 50, 100, 250, 500, 1000, 2000],
DEFAULT_ROW_LIMIT: 100, DEFAULT_ROW_LIMIT: 100,
FETCH_MODE_OPTIONS: ['auto', 'manual'], FETCH_MODE_OPTIONS: ['auto', 'manual'],
@@ -11,5 +11,5 @@
* GENERATED — do not edit. Edit fwlive.css and run: node scripts/embed-fwlive-css.js * GENERATED — do not edit. Edit fwlive.css and run: node scripts/embed-fwlive-css.js
*/ */
return baseclass.extend({ return baseclass.extend({
styleText: "\n/* SPDX-License-Identifier: Apache-2.0 */\n.fwlive-map {\n\tmax-width: none;\n\twidth: 100%;\n\t--fwlive-pass-color: var(--success-color-high, var(--success-color, #46a546));\n\t--fwlive-deny-color: var(--error-color-high, var(--error-color, #ca3c3c));\n\t--fwlive-bg-medium: var(--background-color-medium, var(--white-color-low, #f9f9f9));\n\t--fwlive-paused-color: #b45309;\n}\n/* Wide page in Detail only — Simple keeps LuCI’s 940px column. */\n#maincontent.container:has(.fwlive-map[data-view=\"detailed\"]) {\n\tmax-width: none;\n\tpadding-left: 16px;\n\tpadding-right: 16px;\n}\n.fwlive-map[data-row-tint=\"accessible\"] {\n\t--fwlive-pass-color: #0d9488;\n\t--fwlive-deny-color: #c2410c;\n}\n.fwlive-map.fwlive-watch-paused .fwlive-title-row,\n.fwlive-map.fwlive-watch-paused .fwlive-watch-strip {\n\tbackground: rgba(180, 83, 9, 0.08);\n\tbackground: color-mix(in srgb, var(--fwlive-paused-color) 8%, transparent);\n}\n.fwlive-map.fwlive-watch-paused .fwlive-title-row {\n\tmargin: 0 -8px;\n\tpadding: 6px 8px 0;\n\tborder-radius: 3px 3px 0 0;\n}\n.fwlive-map.fwlive-watch-paused .fwlive-watch-strip {\n\tmargin: 0 -8px 10px;\n\tpadding: 8px;\n\tborder-radius: 0 0 3px 3px;\n\tborder-bottom-color: transparent;\n}\n.fwlive-title-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tjustify-content: space-between;\n\tgap: 8px 16px;\n\tmargin: 0 0 4px;\n}\n.fwlive-title-row h2 {\n\tmargin: 0;\n\tflex: 0 1 auto;\n}\n.fwlive-title-status {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n\tmargin-left: auto;\n}\n.fwlive-watch-strip {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: stretch;\n\tjustify-content: flex-start;\n\tgap: 0;\n\tmin-height: 40px;\n\tpadding: 8px 0 10px;\n\tborder-bottom: 1px solid var(--border-color-medium);\n\tmargin-bottom: 10px;\n}\n.fwlive-watch-group {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tmin-height: 28px;\n\tpadding: 0 10px;\n\tborder-left: 1px solid var(--border-color-medium);\n\tflex-wrap: wrap;\n}\n.fwlive-watch-group:last-child {\n\tpadding-right: 0;\n}\n.fwlive-watch-group-label {\n\tmargin-right: 2px;\n\tcolor: var(--text-color-medium);\n\tfont-size: 0.72em;\n\tfont-weight: 700;\n\tletter-spacing: 0.08em;\n\ttext-transform: uppercase;\n\twhite-space: nowrap;\n}\n.fwlive-watch-seg {\n\tdisplay: inline-flex;\n\talign-items: stretch;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\toverflow: hidden;\n}\n.fwlive-watch-seg .fwlive-seg-btn {\n\tmargin: 0;\n\tborder: 0;\n\tborder-radius: 0;\n\tborder-right: 1px solid var(--border-color-medium);\n\tbackground: transparent;\n\tpadding: 4px 10px;\n\tfont-size: 0.88em;\n\tline-height: 1.25;\n\tmin-height: 28px;\n}\n.fwlive-watch-seg .fwlive-seg-btn:last-child {\n\tborder-right: 0;\n}\n.fwlive-watch-seg .fwlive-seg-btn[aria-pressed=\"true\"] {\n\tbackground: rgba(26, 111, 156, 0.12);\n\tbackground: color-mix(in srgb, var(--primary-color-high) 12%, transparent);\n\tcolor: var(--primary-color-high);\n\tfont-weight: 600;\n}\n.fwlive-watch-label { font-weight: 600; }\n.fwlive-watch-paused .fwlive-watch-label { color: var(--fwlive-paused-color); }\n.fwlive-map.fwlive-watch-paused .fwlive-title-status .fwlive-watch-label { color: var(--fwlive-paused-color); }\n.fwlive-dot {\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 50%;\n\tbackground: var(--text-color-low, var(--border-color-high));\n\tdisplay: inline-block;\n\tflex-shrink: 0;\n}\n.fwlive-dot.fwlive-dot-on {\n\tbackground: var(--fwlive-pass-color);\n\tbox-shadow: 0 0 0 3px color-mix(in srgb, var(--fwlive-pass-color) 22%, transparent);\n}\n.fwlive-btn-ghost {\n\tbackground: transparent;\n\tborder-color: var(--border-color-medium);\n}\n.fwlive-btn-quiet {\n\tbackground: transparent;\n\tborder-color: var(--border-color-medium);\n\tcolor: var(--text-color-medium);\n\tfont-weight: 500;\n}\n.fwlive-log-merged {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 10px;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\tbackground: var(--background-color-medium, var(--white-color-low, var(--background-color-high)));\n\tcolor: var(--text-color-high);\n\tfont-weight: 500;\n\tfont-size: 0.88em;\n\tline-height: 1.25;\n\tmin-height: 28px;\n\tcursor: pointer;\n}\n.fwlive-log-merged:hover {\n\tbackground: var(--background-color-low, var(--background-color-medium));\n}\n.fwlive-log-merged:disabled {\n\topacity: 0.65;\n\tcursor: default;\n}\n.fwlive-log-on-dot {\n\twidth: 6px;\n\theight: 6px;\n\tborder-radius: 50%;\n\tbackground: var(--fwlive-pass-color);\n\tflex-shrink: 0;\n}\n.fwlive-log-rate {\n\tcolor: var(--text-color-medium);\n\tfont-weight: 400;\n}\n.fwlive-display-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px 14px;\n\tmargin: 0 0 12px;\n\tpadding: 8px 12px;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\tbackground: var(--background-color-high);\n}\n.fwlive-dLine truncated styleText: "\n/* SPDX-License-Identifier: Apache-2.0 */\n.fwlive-map {\n\tmax-width: none;\n\twidth: 100%;\n\t--fwlive-pass-color: var(--success-color-high, var(--success-color, #46a546));\n\t--fwlive-deny-color: var(--error-color-high, var(--error-color, #ca3c3c));\n\t--fwlive-bg-medium: var(--background-color-medium, var(--white-color-low, #f9f9f9));\n\t--fwlive-paused-color: #b45309;\n}\n/* Wide page in Detail only — Simple keeps LuCI’s 940px column. */\n#maincontent.container:has(.fwlive-map[data-view=\"detailed\"]) {\n\tmax-width: none;\n\tpadding-left: 16px;\n\tpadding-right: 16px;\n}\n.fwlive-map[data-row-tint=\"accessible\"] {\n\t--fwlive-pass-color: #0d9488;\n\t--fwlive-deny-color: #c2410c;\n}\n.fwlive-map.fwlive-watch-paused .fwlive-title-row,\n.fwlive-map.fwlive-watch-paused .fwlive-watch-strip {\n\tbackground: rgba(180, 83, 9, 0.08);\n\tbackground: color-mix(in srgb, var(--fwlive-paused-color) 8%, transparent);\n}\n.fwlive-map.fwlive-watch-paused .fwlive-title-row {\n\tmargin: 0 -8px;\n\tpadding: 6px 8px 0;\n\tborder-radius: 3px 3px 0 0;\n}\n.fwlive-map.fwlive-watch-paused .fwlive-watch-strip {\n\tmargin: 0 -8px 10px;\n\tpadding: 8px;\n\tborder-radius: 0 0 3px 3px;\n\tborder-bottom-color: transparent;\n}\n.fwlive-title-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tjustify-content: space-between;\n\tgap: 8px 16px;\n\tmargin: 0 0 4px;\n}\n.fwlive-title-row h2 {\n\tmargin: 0;\n\tflex: 0 1 auto;\n}\n.fwlive-title-status {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n\tmargin-left: auto;\n}\n.fwlive-watch-strip {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: stretch;\n\tjustify-content: flex-start;\n\tgap: 0;\n\tmin-height: 40px;\n\tpadding: 8px 0 10px;\n\tborder-bottom: 1px solid var(--border-color-medium);\n\tmargin-bottom: 10px;\n}\n.fwlive-watch-group {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tmin-height: 28px;\n\tpadding: 0 10px;\n\tborder-left: 1px solid var(--border-color-medium);\n\tflex-wrap: wrap;\n}\n.fwlive-watch-group:last-child {\n\tpadding-right: 0;\n}\n.fwlive-watch-group-label {\n\tmargin-right: 2px;\n\tcolor: var(--text-color-medium);\n\tfont-size: 0.72em;\n\tfont-weight: 700;\n\tletter-spacing: 0.08em;\n\ttext-transform: uppercase;\n\twhite-space: nowrap;\n}\n.fwlive-watch-seg {\n\tdisplay: inline-flex;\n\talign-items: stretch;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\toverflow: hidden;\n}\n.fwlive-watch-seg .fwlive-seg-btn {\n\tmargin: 0;\n\tborder: 0;\n\tborder-radius: 0;\n\tborder-right: 1px solid var(--border-color-medium);\n\tbackground: transparent;\n\tpadding: 4px 10px;\n\tfont-size: 0.88em;\n\tline-height: 1.25;\n\tmin-height: 28px;\n}\n.fwlive-watch-seg .fwlive-seg-btn:last-child {\n\tborder-right: 0;\n}\n.fwlive-watch-seg .fwlive-seg-btn[aria-pressed=\"true\"] {\n\tbackground: rgba(26, 111, 156, 0.12);\n\tbackground: color-mix(in srgb, var(--primary-color-high) 12%, transparent);\n\tcolor: var(--primary-color-high);\n\tfont-weight: 600;\n}\n.fwlive-watch-label { font-weight: 600; }\n.fwlive-watch-paused .fwlive-watch-label { color: var(--fwlive-paused-color); }\n.fwlive-map.fwlive-watch-paused .fwlive-title-status .fwlive-watch-label { color: var(--fwlive-paused-color); }\n.fwlive-dot {\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 50%;\n\tbackground: var(--text-color-low, var(--border-color-high));\n\tdisplay: inline-block;\n\tflex-shrink: 0;\n}\n.fwlive-dot.fwlive-dot-on {\n\tbackground: var(--fwlive-pass-color);\n\tbox-shadow: 0 0 0 3px color-mix(in srgb, var(--fwlive-pass-color) 22%, transparent);\n}\n.fwlive-btn-ghost {\n\tbackground: transparent;\n\tborder-color: var(--border-color-medium);\n}\n.fwlive-btn-quiet {\n\tbackground: transparent;\n\tborder-color: var(--border-color-medium);\n\tcolor: var(--text-color-medium);\n\tfont-weight: 500;\n}\n.fwlive-log-merged {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 10px;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\tbackground: var(--background-color-medium, var(--white-color-low, var(--background-color-high)));\n\tcolor: var(--text-color-high);\n\tfont-weight: 500;\n\tfont-size: 0.88em;\n\tline-height: 1.25;\n\tmin-height: 28px;\n\tcursor: pointer;\n}\n.fwlive-log-merged:hover {\n\tbackground: var(--background-color-low, var(--background-color-medium));\n}\n.fwlive-log-merged:disabled {\n\topacity: 0.65;\n\tcursor: default;\n}\n.fwlive-log-on-dot {\n\twidth: 6px;\n\theight: 6px;\n\tborder-radius: 50%;\n\tbackground: var(--fwlive-pass-color);\n\tflex-shrink: 0;\n}\n.fwlive-log-rate {\n\tcolor: var(--text-color-medium);\n\tfont-weight: 400;\n}\n.fwlive-display-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px 14px;\n\tmargin: 0 0 12px;\n\tpadding: 8px 12px;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\tbackground: var(--background-color-high);\n}\n.fwlive-dLine truncated
}); });
@@ -714,6 +714,8 @@
background: color-mix(in srgb, var(--warn-color-high) 10%, transparent); background: color-mix(in srgb, var(--warn-color-high) 10%, transparent);
} }
.fwlive-map[data-view="simple"] #fwlive-msg-group { display: none; } .fwlive-map[data-view="simple"] #fwlive-msg-group { display: none; }
.fwlive-map[data-view="simple"] label[for="fwlive-fetch-mode"],
.fwlive-map[data-view="simple"] label[for="fwlive-manual-lines"] { display: none; }
@media (max-width: 850px) { @media (max-width: 850px) {
.fwlive-title-status { .fwlive-title-status {
flex-basis: 100%; flex-basis: 100%;
@@ -231,8 +231,37 @@ return baseclass.extend({
return String(message).replace(this.KV_SPAN, ''); return String(message).replace(this.KV_SPAN, '');
}, },
isClassifyActionWord: function (token) {
const prefix = (token || '').toUpperCase();
const words = this.CLASSIFY_SPEC.actionWords;
for (let i = 0; i < words.length; i++) {
if (words[i] === prefix) return true;
}
return false;
},
messageForDetectAction: function (message) {
let msg = this.normalizeNetfilterMessage(message || '').trim();
msg = msg.replace(/^\[\s*[\d.]+\]\s*/, '');
if (/^fw4:\s*/i.test(msg)) msg = msg.replace(/^fw4:\s*/i, '');
const beforeKv = msg.match(/^([A-Za-z0-9_.-]+)(?::|\s+)(?=IN=|OUT=|SRC=|DST=|PROTO=)/);
if (beforeKv && !this.isClassifyActionWord(beforeKv[1]))
return msg.slice(beforeKv[0].length);
const colon = msg.match(/^([A-Za-z0-9_.-]+):/);
if (colon) {
const tag = colon[1].toLowerCase();
if (tag !== 'kernel' && tag !== 'iptables' && !this.isClassifyActionWord(colon[1]))
return msg.slice(colon[0].length).replace(/^\s*/, '');
}
return msg;
},
detectAction: function (message) { detectAction: function (message) {
const m = this.stripKvSpans(message).match(this.ACTION_RE); const m = this.stripKvSpans(this.messageForDetectAction(message)).match(this.ACTION_RE);
return m ? m[2].toUpperCase() : 'UNKNOWN'; return m ? m[2].toUpperCase() : 'UNKNOWN';
}, },
@@ -7,6 +7,11 @@
/* Own queued render intent and the token bucket; the view owns DOM work. /* Own queued render intent and the token bucket; the view owns DOM work.
* Adapters supply the epoch, paint callback, cost policy, clock and frame APIs. * Adapters supply the epoch, paint callback, cost policy, clock and frame APIs.
* Without a frame API, schedule() paints synchronously. */ * Without a frame API, schedule() paints synchronously. */
function headIdentity(rows) {
/* logd may reuse IDs after restart; the view preserves raw time/message. */
return rows.length ? rows[0]._clearKey || rows[0].id : '';
}
function createScheduler(options) { function createScheduler(options) {
const { getEpoch, render, renderCost, capacity, requestFrame, cancelFrame } = options; const { getEpoch, render, renderCost, capacity, requestFrame, cancelFrame } = options;
if (!Number.isFinite(capacity) || capacity <= 0) if (!Number.isFinite(capacity) || capacity <= 0)
@@ -71,7 +76,7 @@ function createScheduler(options) {
const cost = renderCost({ const cost = renderCost({
visibleRowCount: rows.length, visibleRowCount: rows.length,
visibleHeadId: rows.length ? rows[0].id : '', visibleHeadId: headIdentity(rows),
lastRenderedRowCount: lastRenderedRowCount, lastRenderedRowCount: lastRenderedRowCount,
lastRenderedHeadId: lastRenderedHeadId, lastRenderedHeadId: lastRenderedHeadId,
lastBatchNewIdCount: lastBatchNewIdCount lastBatchNewIdCount: lastBatchNewIdCount
@@ -101,7 +106,7 @@ function createScheduler(options) {
function markRendered(rows) { function markRendered(rows) {
lastRenderedRowCount = rows.length; lastRenderedRowCount = rows.length;
lastRenderedHeadId = rows.length ? rows[0].id : ''; lastRenderedHeadId = headIdentity(rows);
} }
function resetBudget() { function resetBudget() {
@@ -152,6 +152,10 @@ return view.extend({
entries: [], entries: [],
filteredRowsCache: null, filteredRowsCache: null,
sessionSeen: null, sessionSeen: null,
/* Recent identities follow poll recency, independently of session-new counts.
* Clear snapshots them so counter-cache eviction cannot resurrect rows. */
recentEntryKeys: null,
clearedEntryKeys: null,
pauseBufferLoading: false, pauseBufferLoading: false,
/* Freezes row rendering while polling, health, and cadence updates continue. */ /* Freezes row rendering while polling, health, and cadence updates continue. */
tablePaused: false, tablePaused: false,
@@ -210,6 +214,8 @@ return view.extend({
ruleTargets: {}, ruleTargets: {},
firewallBackend: 'nft', firewallBackend: 'nft',
viewMode: 'simple', viewMode: 'simple',
/* Hash diag=1: adaptive banner and unactionable Watching tags. */
diagnosticMode: false,
expandedRowId: null, expandedRowId: null,
loggingStatus: null, loggingStatus: null,
/* Invalidates status reads started before a newer toggle or refresh. */ /* Invalidates status reads started before a newer toggle or refresh. */
@@ -265,6 +271,7 @@ return view.extend({
parts.push('maxraw=%s'.format(encodeURIComponent(this.manualFetchLines))); parts.push('maxraw=%s'.format(encodeURIComponent(this.manualFetchLines)));
} }
if (this.viewMode === 'detailed') parts.push('view=detailed'); if (this.viewMode === 'detailed') parts.push('view=detailed');
if (this.diagnosticMode) parts.push('diag=1');
history.replaceState(history.state, '', '#' + parts.join('&')); history.replaceState(history.state, '', '#' + parts.join('&'));
}, },
@@ -420,12 +427,17 @@ return view.extend({
applyHash() { applyHash() {
this.resolveRpcPreferences(); this.resolveRpcPreferences();
this.diagnosticMode = false;
const entries = this.hashEntries(); const entries = this.hashEntries();
for (let i = 0; i < entries.length; i++) { for (let i = 0; i < entries.length; i++) {
const key = entries[i].key; const key = entries[i].key;
const val = entries[i].val; const val = entries[i].val;
if (key === 'limit' || key === 'poll' || key === 'maxraw') continue; if (key === 'limit' || key === 'poll' || key === 'maxraw') continue;
if (key === 'fetch-mode' || key === 'row-tint') continue; if (key === 'fetch-mode' || key === 'row-tint') continue;
if (key === 'diag') {
this.diagnosticMode = val === '1' || val === 'true';
continue;
}
if (key === 'view') { if (key === 'view') {
if (val === 'advanced' || val === 'detailed') this.viewMode = 'detailed'; if (val === 'advanced' || val === 'detailed') this.viewMode = 'detailed';
else if (val === 'simple') this.viewMode = 'simple'; else if (val === 'simple') this.viewMode = 'simple';
@@ -687,6 +699,7 @@ return view.extend({
this.updateDetailToggleUi(); this.updateDetailToggleUi();
this.renderThead(); this.renderThead();
this.updateHash(this.readFilters()); this.updateHash(this.readFilters());
this.updateAdaptiveBanner();
this.renderRows(true); this.renderRows(true);
}, },
@@ -1166,6 +1179,12 @@ return view.extend({
const row = this.enrichEntry(log.normalizeEntry(raw[i])); const row = this.enrichEntry(log.normalizeEntry(raw[i]));
if (seen[row.id]) continue; if (seen[row.id]) continue;
seen[row.id] = true; seen[row.id] = true;
/* Keep the original time precision: logd can reuse IDs after restart. */
const clearKey = JSON.stringify([row.id, raw[i].time, row.message]);
/* Free-text search enumerates row fields; this identity is private. */
Object.defineProperty(row, '_clearKey', { value: clearKey });
this.rememberRecentEntryKey(clearKey);
if (this.clearedEntryKeys && this.clearedEntryKeys.has(clearKey)) continue;
if (this.rememberSessionId(row.id)) pollNew++; if (this.rememberSessionId(row.id)) pollNew++;
normalized.push(row); normalized.push(row);
} }
@@ -1249,7 +1268,9 @@ return view.extend({
this.notePollRtt(rtt, false); this.notePollRtt(rtt, false);
this.updateAdaptiveBanner(); this.updateAdaptiveBanner();
if (this.clientBackoffEnabled()) { /* Server summaries cover the raw sample and cannot honor a browser Clear.
* Keep rows after Clear; cadence backoff and render throttling still apply. */
if (this.clientBackoffEnabled() && !this.clearedEntryKeys) {
if (this.summaryMode) { if (this.summaryMode) {
this.summaryData = this.summaryData =
reply.summary && reply.summary &&
@@ -1272,7 +1293,7 @@ return view.extend({
this.entries = buffer.applyFetchedEntries(this.entries, batch.rows, { this.entries = buffer.applyFetchedEntries(this.entries, batch.rows, {
/* buffer.js retains its public paused option; this is the view's table state. */ /* buffer.js retains its public paused option; this is the view's table state. */
paused: this.tablePaused, paused: this.tablePaused,
resumeMerge: resumeMerge || context.pausedAtStart, resumeMerge: resumeMerge || context.pausedAtStart || !!this.clearedEntryKeys,
rowLimit: this.rowLimit, rowLimit: this.rowLimit,
fetchLinesMax: constants.FETCH_LINES_MAX fetchLinesMax: constants.FETCH_LINES_MAX
}); });
@@ -1316,6 +1337,18 @@ return view.extend({
} }
}, },
rememberRecentEntryKey(key) {
if (!this.recentEntryKeys) this.recentEntryKeys = new Set();
/* logd returns oldest first. Touch hits as well as misses so a wider
* lookback cannot make still-reachable recent events the first evicted.
* The cache covers at least the maximum raw poll window. */
this.recentEntryKeys.delete(key);
this.recentEntryKeys.add(key);
const cap = Math.max(this.rowLimit * 2, constants.FETCH_LINES_MAX);
while (this.recentEntryKeys.size > cap)
this.recentEntryKeys.delete(this.recentEntryKeys.values().next().value);
},
rememberSessionId(id) { rememberSessionId(id) {
if (!this.sessionSeen) this.sessionSeen = new Set(); if (!this.sessionSeen) this.sessionSeen = new Set();
if (this.sessionSeen.has(id)) return false; if (this.sessionSeen.has(id)) return false;
@@ -1356,9 +1389,11 @@ return view.extend({
bits.push( bits.push(
_('display limited to %d rows').format(constants.WEAK_DEVICE_DISPLAY_ROW_CAP) _('display limited to %d rows').format(constants.WEAK_DEVICE_DISPLAY_ROW_CAP)
); );
if (this.degradedSampling) bits.push(_('polling slowed')); if (this.diagnosticMode) {
if (this.serverTruncated) bits.push(_('server limited fetch')); if (this.degradedSampling) bits.push(_('polling slowed'));
if (this.resolveLoadShed) bits.push(_('hostname lookup paused')); if (this.serverTruncated) bits.push(_('server limited fetch'));
if (this.resolveLoadShed) bits.push(_('hostname lookup paused'));
}
if (!this.tablePaused && !this.followLive) if (!this.tablePaused && !this.followLive)
bits.push(_('scroll frozen — scroll to top to follow live')); bits.push(_('scroll frozen — scroll to top to follow live'));
return bits.length ? ' — ' + bits.join(', ') : ''; return bits.length ? ' — ' + bits.join(', ') : '';
@@ -1554,7 +1589,7 @@ return view.extend({
const el = document.getElementById('fwlive-adaptive'); const el = document.getElementById('fwlive-adaptive');
if (!el) return; if (!el) return;
const parts = this.adaptiveBannerParts(); const parts = !this.diagnosticMode || this.summaryMode ? [] : this.adaptiveBannerParts();
if (parts.length) { if (parts.length) {
el.style.display = 'block'; el.style.display = 'block';
@@ -1653,6 +1688,7 @@ return view.extend({
this.summaryData = this.summaryData =
summary && typeof summary === 'object' && !Array.isArray(summary) ? summary : null; summary && typeof summary === 'object' && !Array.isArray(summary) ? summary : null;
this.renderSummary(); this.renderSummary();
this.updateAdaptiveBanner();
}, },
leaveSummaryMode() { leaveSummaryMode() {
@@ -1661,6 +1697,7 @@ return view.extend({
this.summaryRowsShown = false; this.summaryRowsShown = false;
this.summaryData = null; this.summaryData = null;
this.updateSummaryUi(); this.updateSummaryUi();
this.updateAdaptiveBanner();
if (this.tablePaused) { if (this.tablePaused) {
this.syncEmptyScrollVisibility(this.filteredRowsState().rows.length); this.syncEmptyScrollVisibility(this.filteredRowsState().rows.length);
this.updateStatus(); this.updateStatus();
@@ -1959,6 +1996,29 @@ return view.extend({
} }
}, },
onClearEntriesClick() {
this.clearedEntryKeys = new Set(this.recentEntryKeys || []);
for (let i = 0; i < this.entries.length; i++) {
const key = this.entries[i]._clearKey;
if (key) this.clearedEntryKeys.add(key);
}
this.entries = [];
this.expandedRowId = null;
this.lastBatchNewIdCount = 0;
this.fillingBuffer = false;
this.pauseBufferLoading = false;
this.invalidateFilteredRows();
this.ensureRenderScheduler().resetBudget();
if (this.summaryMode) {
this.summaryMode = false;
this.summaryRowsShown = false;
this.summaryData = null;
this.updateSummaryUi();
this.updateAdaptiveBanner();
}
this.renderRows(true);
},
onRowLimitChange(ev) { onRowLimitChange(ev) {
const n = parseInt(ev && ev.target ? ev.target.value : '', 10); const n = parseInt(ev && ev.target ? ev.target.value : '', 10);
if (!isFinite(n) || constants.ROW_LIMIT_OPTIONS.indexOf(n) < 0) return; if (!isFinite(n) || constants.ROW_LIMIT_OPTIONS.indexOf(n) < 0) return;
@@ -2426,6 +2486,9 @@ return view.extend({
const pauseBtn = document.getElementById('fwlive-pause'); const pauseBtn = document.getElementById('fwlive-pause');
if (pauseBtn) pauseBtn.addEventListener('click', this.onPauseClick.bind(this)); if (pauseBtn) pauseBtn.addEventListener('click', this.onPauseClick.bind(this));
const clearBtn = document.getElementById('fwlive-clear');
if (clearBtn) clearBtn.addEventListener('click', this.onClearEntriesClick.bind(this));
const limitSel = document.getElementById('fwlive-limit'); const limitSel = document.getElementById('fwlive-limit');
if (limitSel) limitSel.addEventListener('change', this.onRowLimitChange.bind(this)); if (limitSel) limitSel.addEventListener('change', this.onRowLimitChange.bind(this));
@@ -2562,7 +2625,10 @@ return view.extend({
{ {
'id': 'fwlive-fetch-mode', 'id': 'fwlive-fetch-mode',
'class': 'cbi-input-select', 'class': 'cbi-input-select',
'aria-controls': 'fwlive-manual-lines' 'aria-controls': 'fwlive-manual-lines',
'title': _(
'Auto reads extra kernel log lines so the table can fill; it is not the same as Limit.'
)
}, },
this.fetchModeOptions() this.fetchModeOptions()
) )
@@ -2628,6 +2694,11 @@ return view.extend({
'The table updates automatically when your firewall logs traffic. Use Pause if it moves too fast.' 'The table updates automatically when your firewall logs traffic. Use Pause if it moves too fast.'
) )
]), ]),
E('li', {}, [
_(
'Clear empties the table. Already seen events stay hidden; new ones still appear.'
)
]),
E('li', {}, [ E('li', {}, [
_( _(
'Enable logging turns on WAN zone drop/reject logging only (same as Network → Firewall). It does not add rules or log normal LAN browsing.' 'Enable logging turns on WAN zone drop/reject logging only (same as Network → Firewall). It does not add rules or log normal LAN browsing.'
@@ -2635,7 +2706,7 @@ return view.extend({
]), ]),
E('li', {}, [ E('li', {}, [
_( _(
'Display options set Limit, Fetch budget, Maximum raw lines, row tint, palette, and hostnames.' 'Display options set Limit, row tint, palette, and hostnames. Fetch budget is in Detail view.'
) )
]), ]),
E('li', {}, [ E('li', {}, [
@@ -2645,7 +2716,7 @@ return view.extend({
]), ]),
E('li', {}, [ E('li', {}, [
_( _(
'Fetch budget controls raw log lines per poll. Auto derives from Limit; Manual selects a bounded maximum.' 'Limit is how many events the table keeps. In Detail view, Fetch budget Auto reads extra kernel log lines so the table can fill; Manual selects that read size.'
) )
]), ]),
E('li', {}, [ E('li', {}, [
@@ -2772,6 +2843,16 @@ return view.extend({
}, },
[_('Pause')] [_('Pause')]
), ),
E(
'button',
{
'id': 'fwlive-clear',
'class': 'cbi-button fwlive-btn-ghost',
'type': 'button',
'title': _('Remove shown events. New events still appear.')
},
[_('Clear')]
),
E('span', { 'id': 'fwlive-logging-bar', 'class': 'fwlive-logging-bar' }, []) E('span', { 'id': 'fwlive-logging-bar', 'class': 'fwlive-logging-bar' }, [])
]), ]),
E('div', { 'class': 'fwlive-watch-group' }, [ E('div', { 'class': 'fwlive-watch-group' }, [
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+193 -172
View File
@@ -1,51 +1,51 @@
msgid "" msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8" msgstr "Content-Type: text/plain; charset=UTF-8"
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1791 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1828
msgid "%d matching · %d/%d stored" msgid "%d matching · %d/%d stored"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1756 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1793
msgid "%dd" msgid "%dd"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1755 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1792
msgid "%dh" msgid "%dh"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1754 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1791
msgid "%dm" msgid "%dm"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1753 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1790
msgid "%ds" msgid "%ds"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1517 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1552
msgid "%s · requested up to %d raw lines · %d firewall messages returned" msgid "%s · requested up to %d raw lines · %d firewall messages returned"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1507 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1542
msgid "" msgid ""
"%s · requested up to %d raw lines · server limited fetch to %d · %d firewall " "%s · requested up to %d raw lines · server limited fetch to %d · %d firewall "
"messages returned" "messages returned"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:580 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:609
msgid "%s: %s" msgid "%s: %s"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1793 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1830
msgid "0 matching · %d/%d stored" msgid "0 matching · %d/%d stored"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:487 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:499
msgid "Accessible (teal/orange)" msgid "Accessible (teal/orange)"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:440 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:469
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:38 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:38
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2896 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2977
msgid "Action" msgid "Action"
msgstr "" msgstr ""
@@ -54,11 +54,11 @@ msgid ""
"Activate the message button or click a row to show or hide the full message" "Activate the message button or click a row to show or hide the full message"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:998 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1011
msgid "Administrator access is required to disable logging." msgid "Administrator access is required to disable logging."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:982 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:995
msgid "Administrator access is required to enable logging." msgid "Administrator access is required to enable logging."
msgstr "" msgstr ""
@@ -66,7 +66,7 @@ msgstr ""
msgid "Allow/deny rules, LAN logging, or anything else." msgid "Allow/deny rules, LAN logging, or anything else."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2004 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2064
msgid "Also seen" msgid "Also seen"
msgstr "" msgstr ""
@@ -80,19 +80,25 @@ msgid ""
"state." "state."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2899 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2980
msgid "Any action" msgid "Any action"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1997 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2057
msgid "Any protocol" msgid "Any protocol"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1498 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1533
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1570 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1605
msgid "Auto" msgid "Auto"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2630
msgid ""
"Auto reads extra kernel log lines so the table can fill; it is not the same "
"as Limit."
msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/logging.js:379 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/logging.js:379
msgid "Before you enable logging" msgid "Before you enable logging"
msgstr "" msgstr ""
@@ -105,33 +111,43 @@ msgstr ""
msgid "Changes:" msgid "Changes:"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:486 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:498
msgid "Classic (green/red)" msgid "Classic (green/red)"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2604 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2670
msgid "Classic uses green/red; Accessible uses teal/orange" msgid "Classic uses green/red; Accessible uses teal/orange"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2854
msgid "Clear"
msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/chips.js:94 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/chips.js:94
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/chips.js:274 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/chips.js:274
msgid "Clear all" msgid "Clear all"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2972 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2699
msgid ""
"Clear empties the table. Already seen events stay hidden; new ones still "
"appear."
msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:3053
msgid "" msgid ""
"Click a cell to filter · ≠ on a chip to exclude · Ctrl+click a rule for " "Click a cell to filter · ≠ on a chip to exclude · Ctrl+click a rule for "
"firewall settings · in Simple view, activate the message button or click a " "firewall settings · in Simple view, activate the message button or click a "
"row to show or hide the full message" "row to show or hide the full message"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2684 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2755
msgid "" msgid ""
"Click an IP, action, or protocol to filter; use the Protocol menu (or ≠ on a " "Click an IP, action, or protocol to filter; use the Protocol menu (or ≠ on a "
"chip) to exclude." "chip) to exclude."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1998 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2058
msgid "Common" msgid "Common"
msgstr "" msgstr ""
@@ -141,7 +157,7 @@ msgid ""
"it; kernel/logd may still constrain total log volume." "it; kernel/logd may still constrain total log volume."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1804 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1841
msgid "Connection lost — retrying…" msgid "Connection lost — retrying…"
msgstr "" msgstr ""
@@ -153,49 +169,49 @@ msgstr ""
msgid "Could not clear the WAN zone log option." msgid "Could not clear the WAN zone log option."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:804 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:817
msgid "Could not create a temporary file for rule names." msgid "Could not create a temporary file for rule names."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:993 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1006
msgid "Could not disable logging." msgid "Could not disable logging."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:971 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:984
msgid "Could not enable logging." msgid "Could not enable logging."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:907 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:920
msgid "Could not load logging status." msgid "Could not load logging status."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:810 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:823
msgid "Could not load rule names." msgid "Could not load rule names."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:806 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:819
msgid "Could not process firewall rule names." msgid "Could not process firewall rule names."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:950 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:963
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:983 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:996
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:999 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1012
msgid "Could not reach the router; check the current logging state." msgid "Could not reach the router; check the current logging state."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:808 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:821
msgid "Could not read the active firewall rules." msgid "Could not read the active firewall rules."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:906 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:919
msgid "Could not refresh logging status; showing the last known state." msgid "Could not refresh logging status; showing the last known state."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:815 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:828
msgid "Could not refresh rule names." msgid "Could not refresh rule names."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:813 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:826
msgid "Could not refresh rule names; previously loaded names are still shown." msgid "Could not refresh rule names; previously loaded names are still shown."
msgstr "" msgstr ""
@@ -215,7 +231,7 @@ msgstr ""
msgid "Could not write the WAN zone log option." msgid "Could not write the WAN zone log option."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2927 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:3008
msgid "Custom protocol (prefix ! to exclude). Overrides the menu when set." msgid "Custom protocol (prefix ! to exclude). Overrides the menu when set."
msgstr "" msgstr ""
@@ -223,28 +239,28 @@ msgstr ""
msgid "DPort" msgid "DPort"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:444 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:473
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:46 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:46
msgid "Destination" msgid "Destination"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2957 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:3038
msgid "Destination IP contains (! to exclude)" msgid "Destination IP contains (! to exclude)"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:446 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:475
msgid "Destination port" msgid "Destination port"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2962 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:3043
msgid "Destination port (! to exclude)" msgid "Destination port (! to exclude)"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2807 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2888
msgid "Detail" msgid "Detail"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2760 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2831
msgid "Details" msgid "Details"
msgstr "" msgstr ""
@@ -256,20 +272,20 @@ msgstr ""
msgid "Disabling…" msgid "Disabling…"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1547 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1582
msgid "" msgid ""
"Display limited to %d rows on this device; the larger Limit still buffers " "Display limited to %d rows on this device; the larger Limit still buffers "
"rows." "rows."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2545 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2608
msgid "Display options" msgid "Display options"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2638 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2709
msgid "" msgid ""
"Display options set Limit, Fetch budget, Maximum raw lines, row tint, " "Display options set Limit, row tint, palette, and hostnames. Fetch budget is "
"palette, and hostnames." "in Detail view."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/logging.js:387 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/logging.js:387
@@ -288,7 +304,7 @@ msgstr ""
msgid "Enable logging" msgid "Enable logging"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2633 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2704
msgid "" msgid ""
"Enable logging turns on WAN zone drop/reject logging only (same as Network → " "Enable logging turns on WAN zone drop/reject logging only (same as Network → "
"Firewall). It does not add rules or log normal LAN browsing." "Firewall). It does not add rules or log normal LAN browsing."
@@ -298,7 +314,7 @@ msgstr ""
msgid "Enabling…" msgid "Enabling…"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2011 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2071
msgid "Exclude" msgid "Exclude"
msgstr "" msgstr ""
@@ -307,20 +323,14 @@ msgstr ""
msgid "Exclude instead" msgid "Exclude instead"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2559 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2622
msgid "Fetch budget" msgid "Fetch budget"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2648
msgid ""
"Fetch budget controls raw log lines per poll. Auto derives from Limit; "
"Manual selects a bounded maximum."
msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/links.js:63 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/links.js:63
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/links.js:84 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/links.js:84
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/links.js:149 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/links.js:149
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2896 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2977
msgid "Filter by %s" msgid "Filter by %s"
msgstr "" msgstr ""
@@ -328,12 +338,12 @@ msgstr ""
msgid "Filter logs by rule (hint: %s). Ctrl+click to open firewall settings." msgid "Filter logs by rule (hint: %s). Ctrl+click to open firewall settings."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2722 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2793
#: openwrt-feed/luci-app-fwlive/root/usr/share/luci/menu.d/luci-app-fwlive.json:3 #: openwrt-feed/luci-app-fwlive/root/usr/share/luci/menu.d/luci-app-fwlive.json:3
msgid "Firewall Live View" msgid "Firewall Live View"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1771 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1808
msgid "Firewall log has no current entries; showing rows last received %s ago." msgid "Firewall log has no current entries; showing rows last received %s ago."
msgstr "" msgstr ""
@@ -345,7 +355,7 @@ msgstr ""
msgid "Flow" msgid "Flow"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2658 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2729
msgid "" msgid ""
"For a responsive table on a weak device, keep Limit at 250 rows or below. " "For a responsive table on a weak device, keep Limit at 250 rows or below. "
"The weak-device cap affects rendered rows; the buffer can still retain more." "The weak-device cap affects rendered rows; the buffer can still retain more."
@@ -359,7 +369,7 @@ msgstr ""
msgid "Grant access to firewall live log view" msgid "Grant access to firewall live log view"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2624 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2690
msgid "Help" msgid "Help"
msgstr "" msgstr ""
@@ -367,15 +377,15 @@ msgstr ""
msgid "Hide full message" msgid "Hide full message"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1645 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1680
msgid "Hide rows" msgid "Hide rows"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1543 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1578
msgid "Hostname lookup paused while the router is under load." msgid "Hostname lookup paused while the router is under load."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2002 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2062
msgid "ICMPv6" msgid "ICMPv6"
msgstr "" msgstr ""
@@ -383,7 +393,7 @@ msgstr ""
msgid "IN" msgid "IN"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2695 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2766
msgid "" msgid ""
"If Row tint looks missing, the active LuCI theme may omit success/error or " "If Row tint looks missing, the active LuCI theme may omit success/error or "
"info/warn CSS variables; fwlive falls back to local colors (air-gapped, no " "info/warn CSS variables; fwlive falls back to local colors (air-gapped, no "
@@ -396,7 +406,7 @@ msgid ""
"Help / the enabling-logs guide." "Help / the enabling-logs guide."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2679 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2750
msgid "" msgid ""
"In Simple view, activate the message button or click a row to show or hide " "In Simple view, activate the message button or click a row to show or hide "
"the full message." "the full message."
@@ -417,16 +427,16 @@ msgid ""
"release, then reload the firewall." "release, then reload the firewall."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1802 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1839
msgid "Installation is incomplete. Reinstall luci-app-fwlive." msgid "Installation is incomplete. Reinstall luci-app-fwlive."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:441 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:470
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:40 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:40
msgid "Interface" msgid "Interface"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2942 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:3023
msgid "Interface (prefix ! to exclude)" msgid "Interface (prefix ! to exclude)"
msgstr "" msgstr ""
@@ -443,11 +453,18 @@ msgstr ""
msgid "Len" msgid "Len"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2548 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2611
msgid "Limit" msgid "Limit"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:861 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2719
msgid ""
"Limit is how many events the table keeps. In Detail view, Fetch budget Auto "
"reads extra kernel log lines so the table can fill; Manual selects that read "
"size."
msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:874
msgid "Live view may be incomplete — a legacy iptables table is registered" msgid "Live view may be incomplete — a legacy iptables table is registered"
msgstr "" msgstr ""
@@ -455,16 +472,16 @@ msgstr ""
msgid "Logging is off on this router" msgid "Logging is off on this router"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1498 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1533
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1571 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1606
msgid "Manual" msgid "Manual"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2577 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2643
msgid "Manual still uses server protection and poll cadence" msgid "Manual still uses server protection and poll cadence"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2653 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2724
msgid "" msgid ""
"Manual still uses server protection and poll cadence; it changes the fetch " "Manual still uses server protection and poll cadence; it changes the fetch "
"budget, not the polling interval." "budget, not the polling interval."
@@ -474,18 +491,18 @@ msgstr ""
msgid "Manual test (System → Terminal):" msgid "Manual test (System → Terminal):"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2571 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2637
msgid "Maximum raw lines" msgid "Maximum raw lines"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:52 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:52
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:377 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:377
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2819 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2900
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2826 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2907
msgid "Message" msgid "Message"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2937 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:3018
msgid "More filters" msgid "More filters"
msgstr "" msgstr ""
@@ -528,7 +545,7 @@ msgstr ""
msgid "OUT" msgid "OUT"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2849 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2930
msgid "One line" msgid "One line"
msgstr "" msgstr ""
@@ -555,34 +572,34 @@ msgstr ""
msgid "Outbound" msgid "Outbound"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2598 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2664
msgid "Palette" msgid "Palette"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1865 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1902
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2773 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2844
msgid "Pause" msgid "Pause"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1864 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1901
msgid "Paused" msgid "Paused"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1530 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1565
msgid "" msgid ""
"Polling slowed: the router is responding slowly, so polls run less often." "Polling slowed: the router is responding slowly, so polls run less often."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:442 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:471
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:44 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:44
msgid "Proto" msgid "Proto"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2918 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2999
msgid "Protocol — common values" msgid "Protocol — common values"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2889 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2970
msgid "Quick search" msgid "Quick search"
msgstr "" msgstr ""
@@ -596,22 +613,26 @@ msgstr ""
msgid "Remove filter" msgid "Remove filter"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1865 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2852
msgid "Remove shown events. New events still appear."
msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1902
msgid "Resume" msgid "Resume"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2588 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2654
msgid "Row tint" msgid "Row tint"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2689 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2760
msgid "" msgid ""
"Row tint shows pass/deny row backgrounds when checked. Choose Classic (green/" "Row tint shows pass/deny row backgrounds when checked. Choose Classic (green/"
"red, default) or Accessible (teal/orange). Action text stays colored either " "red, default) or Accessible (teal/orange). Action text stays colored either "
"way." "way."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2745 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2816
msgid "" msgid ""
"Row tint used a local color fallback because the active LuCI theme did not " "Row tint used a local color fallback because the active LuCI theme did not "
"apply pass/deny backgrounds." "apply pass/deny backgrounds."
@@ -621,19 +642,19 @@ msgstr ""
msgid "Rule" msgid "Rule"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2760 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2831
msgid "Rule name details" msgid "Rule name details"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:832 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:845
msgid "Rule-name lookup does not change your firewall rules." msgid "Rule-name lookup does not change your firewall rules."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:817 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:830
msgid "Rule-name lookup failed." msgid "Rule-name lookup failed."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:824 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:837
msgid "Rule-name lookup reached a safety limit." msgid "Rule-name lookup reached a safety limit."
msgstr "" msgstr ""
@@ -641,26 +662,26 @@ msgstr ""
msgid "SPort" msgid "SPort"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:439 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:468
msgid "Search" msgid "Search"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1527 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1562
msgid "Server adaptive protection is disabled." msgid "Server adaptive protection is disabled."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1535 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1570
msgid "" msgid ""
"Server limited fetch: the router is under load; at most %d log lines per " "Server limited fetch: the router is under load; at most %d log lines per "
"poll." "poll."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1540 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1575
msgid "" msgid ""
"Server limited fetch: this poll returned fewer lines to protect the router." "Server limited fetch: this poll returned fewer lines to protect the router."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1525 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1560
msgid "Server protection state is unknown." msgid "Server protection state is unknown."
msgstr "" msgstr ""
@@ -668,80 +689,80 @@ msgstr ""
msgid "Show full message" msgid "Show full message"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2615 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2681
msgid "Show hostnames" msgid "Show hostnames"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2586 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2652
msgid "Show pass/deny row background colors" msgid "Show pass/deny row background colors"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1645 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1680
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2872 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2953
msgid "Show rows" msgid "Show rows"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1605 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1640
msgid "Showing a compact summary of the top of the shown sample." msgid "Showing a compact summary of the top of the shown sample."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2796 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2877
msgid "Simple" msgid "Simple"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:835 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:848
msgid "" msgid ""
"Some entries may show names derived from their log prefixes. Searching by a " "Some entries may show names derived from their log prefixes. Searching by a "
"friendly rule name may miss those entries." "friendly rule name may miss those entries."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:855 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:868
msgid "Some rule names may be missing" msgid "Some rule names may be missing"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:443 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:472
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:45 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:45
msgid "Source" msgid "Source"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2947 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:3028
msgid "Source IP contains (! to exclude)" msgid "Source IP contains (! to exclude)"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:445 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:474
msgid "Source port" msgid "Source port"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2952 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:3033
msgid "Source port (! to exclude)" msgid "Source port (! to exclude)"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1607 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1642
msgid "Summary data is unavailable; show rows to inspect the sample." msgid "Summary data is unavailable; show rows to inspect the sample."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2863 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2944
msgid "Summary mode" msgid "Summary mode"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2643 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2714
msgid "" msgid ""
"Summary mode: when the router responds slowly, a compact summary replaces " "Summary mode: when the router responds slowly, a compact summary replaces "
"the table. Use Show rows to see the table; it returns automatically after " "the table. Use Show rows to see the table; it returns automatically after "
"three fast polls." "three fast polls."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1609 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1644
msgid "Summary was bounded before all categories could be included." msgid "Summary was bounded before all categories could be included."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2663 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2734
msgid "" msgid ""
"Switching tabs pauses polling; returning performs one catch-up poll. " "Switching tabs pauses polling; returning performs one catch-up poll. "
"Hostnames are off by default because lookups add work." "Hostnames are off by default because lookups add work."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1700 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1737
msgid "" msgid ""
"Table refresh throttled: the event rate is high, so the table repaints less " "Table refresh throttled: the event rate is high, so the table repaints less "
"often to protect the browser. The buffer still updates; refresh resumes " "often to protect the browser. The buffer still updates; refresh resumes "
@@ -752,7 +773,7 @@ msgstr ""
msgid "The firewall did not reload; saved and live logging may differ." msgid "The firewall did not reload; saved and live logging may differ."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2673 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2744
msgid "" msgid ""
"The rate shown for WAN logging is the configured WAN zone log_limit, not " "The rate shown for WAN logging is the configured WAN zone log_limit, not "
"proof the running fw4 supports it. The fw4 bundled with OpenWrt 23.05.5 " "proof the running fw4 supports it. The fw4 bundled with OpenWrt 23.05.5 "
@@ -760,23 +781,23 @@ msgid ""
"fwlive does not impose a limit." "fwlive does not impose a limit."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1803 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1840
msgid "The router could not read the firewall log — retrying…" msgid "The router could not read the firewall log — retrying…"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2668 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2739
msgid "" msgid ""
"The router log ring may evict older events before fwlive reads them. fwlive " "The router log ring may evict older events before fwlive reads them. fwlive "
"cannot recover evicted entries or change forwarding behavior." "cannot recover evicted entries or change forwarding behavior."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2628 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2694
msgid "" msgid ""
"The table updates automatically when your firewall logs traffic. Use Pause " "The table updates automatically when your firewall logs traffic. Use Pause "
"if it moves too fast." "if it moves too fast."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2748 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2819
msgid "Theme tint fallback" msgid "Theme tint fallback"
msgstr "" msgstr ""
@@ -793,15 +814,15 @@ msgstr ""
msgid "Time" msgid "Time"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1614 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1649
msgid "Top drops" msgid "Top drops"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1617 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1652
msgid "Top rules" msgid "Top rules"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1611 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1646
msgid "Top talkers" msgid "Top talkers"
msgstr "" msgstr ""
@@ -823,16 +844,16 @@ msgstr ""
msgid "Undo:" msgid "Undo:"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2692 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2763
msgid "Use Detail for all columns (flags, length, raw message)." msgid "Use Detail for all columns (flags, length, raw message)."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2778 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2859
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2784 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2865
msgid "View" msgid "View"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:994 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1007
msgid "WAN drop/reject logging is off." msgid "WAN drop/reject logging is off."
msgstr "" msgstr ""
@@ -842,13 +863,13 @@ msgid ""
"here. Normal LAN browsing will not." "here. Normal LAN browsing will not."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:975 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:988
msgid "" msgid ""
"WAN drop/reject logging is on. Blocked inbound traffic should appear here as " "WAN drop/reject logging is on. Blocked inbound traffic should appear here as "
"it happens — not normal LAN browsing." "it happens — not normal LAN browsing."
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:977 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:990
msgid "WAN logging is already enabled." msgid "WAN logging is already enabled."
msgstr "" msgstr ""
@@ -877,25 +898,25 @@ msgstr ""
msgid "Waiting for firewall events" msgid "Waiting for firewall events"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1864 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1901
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2736 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2807
msgid "Watching" msgid "Watching"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2838 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2919
msgid "Wrap" msgid "Wrap"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:74 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:74
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2901 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2982
msgid "block" msgid "block"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1348 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1381
msgid "buffer filling" msgid "buffer filling"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1352 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1385
msgid "buffer full" msgid "buffer full"
msgstr "" msgstr ""
@@ -907,7 +928,7 @@ msgstr ""
msgid "contains" msgid "contains"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1357 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1390
msgid "display limited to %d rows" msgid "display limited to %d rows"
msgstr "" msgstr ""
@@ -916,11 +937,11 @@ msgid "does not contain"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:75 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:75
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2902 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2983
msgid "drop" msgid "drop"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1361 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1395
msgid "hostname lookup paused" msgid "hostname lookup paused"
msgstr "" msgstr ""
@@ -928,11 +949,11 @@ msgstr ""
msgid "is" msgid "is"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1347 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1380
msgid "loading buffer" msgid "loading buffer"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1789 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1826
msgid "loading…" msgid "loading…"
msgstr "" msgstr ""
@@ -940,8 +961,8 @@ msgstr ""
msgid "no WAN rate limit configured" msgid "no WAN rate limit configured"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1587 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1622
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1596 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1631
msgid "none" msgid "none"
msgstr "" msgstr ""
@@ -949,98 +970,98 @@ msgstr ""
msgid "not" msgid "not"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2019 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2079
msgid "not AH" msgid "not AH"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2018 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2078
msgid "not ESP" msgid "not ESP"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2017 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2077
msgid "not GRE" msgid "not GRE"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2014 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2074
msgid "not ICMP" msgid "not ICMP"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2015 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2075
msgid "not ICMPv6" msgid "not ICMPv6"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2016 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2076
msgid "not IGMP" msgid "not IGMP"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2020 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2080
msgid "not SCTP" msgid "not SCTP"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2012 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2072
msgid "not TCP" msgid "not TCP"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2013 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2073
msgid "not UDP" msgid "not UDP"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2907 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2988
msgid "not block" msgid "not block"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2906 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2987
msgid "not drop" msgid "not drop"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2905 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2986
msgid "not pass" msgid "not pass"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2908 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2989
msgid "not reject" msgid "not reject"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2909 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2990
msgid "not unknown" msgid "not unknown"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2925 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:3006
msgid "or type…" msgid "or type…"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:73 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:73
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2900 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2981
msgid "pass" msgid "pass"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1359 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1393
msgid "polling slowed" msgid "polling slowed"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:76 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:76
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2903 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2984
msgid "reject" msgid "reject"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1363 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1398
msgid "scroll frozen — scroll to top to follow live" msgid "scroll frozen — scroll to top to follow live"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1360 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1394
msgid "server limited fetch" msgid "server limited fetch"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1354 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1387
msgid "table refresh throttled" msgid "table refresh throttled"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:65 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:65
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2904 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2985
msgid "unknown" msgid "unknown"
msgstr "" msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:797 #: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:810
msgid "using fw4" msgid "using fw4"
msgstr "" msgstr ""
File diff suppressed because it is too large. Load diff
@@ -54,8 +54,36 @@ function strip_kv(s, out, i, n, prev, rest) {
} }
return out return out
} }
function action_word_prefix(first, words, n, i) {
n = split("ACCEPT ALLOW PASS DROP REJECT DENY BLOCK", words, " ")
first = tolower(first)
for (i = 1; i <= n; i++) {
if (tolower(words[i]) == first) return 1
}
return 0
}
function strip_leading_rule_hint(s, first, rest) {
sub(/^\[[[:space:]]*[0-9.]+\][[:space:]]*/, "", s)
if (match(tolower(s), /^fw4:[[:space:]]*/))
s = substr(s, RSTART + RLENGTH)
if (match(s, "^[A-Za-z0-9_.-]+(:|[[:space:]]+)(IN=|OUT=|SRC=|DST=|PROTO=)")) {
match(s, "^[A-Za-z0-9_.-]+")
first = substr(s, RSTART, RLENGTH)
if (!action_word_prefix(first)) {
rest = substr(s, RSTART + RLENGTH)
match(rest, "^(:|[[:space:]]+)")
s = substr(rest, RSTART + RLENGTH)
}
}
else if (match(s, "^[A-Za-z0-9_.-]+:")) {
first = substr(s, RSTART, RLENGTH - 1)
if (tolower(first) != "kernel" && tolower(first) != "iptables" && !action_word_prefix(first))
s = substr(s, RSTART + RLENGTH)
}
return s
}
function detect_action(s, words, n, i, w, wl, lc, start, pos, before, afterc, best, bestpos) { function detect_action(s, words, n, i, w, wl, lc, start, pos, before, afterc, best, bestpos) {
s = strip_kv(s) s = strip_kv(strip_leading_rule_hint(s))
n = split("ACCEPT ALLOW PASS DROP REJECT DENY BLOCK", words, " ") n = split("ACCEPT ALLOW PASS DROP REJECT DENY BLOCK", words, " ")
lc = tolower(s) lc = tolower(s)
best = "" best = ""
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-open-box PKG_NAME:=luci-app-open-box
PKG_VERSION:=0.1.337 PKG_VERSION:=0.1.338
PKG_RELEASE:=34 PKG_RELEASE:=35
PKG_MAINTAINER:=liandu2024 PKG_MAINTAINER:=liandu2024
PKG_LICENSE:=GPL-3.0-or-later PKG_LICENSE:=GPL-3.0-or-later
@@ -85,7 +85,9 @@ const PodmanFormContainer = podmanView.form.extend({
field.value(name, name); field.value(name, name);
} }
}); });
field.description = _('Add the container to an existing pod. Network, hostname and port mappings come from the pod\'s infra container.'); field.description = _(
'Add the container to an existing pod. Network, hostname and port mappings come from the pod\'s infra container.'
);
field = this.section.option(form.Value, 'command', _('Command')); field = this.section.option(form.Value, 'command', _('Command'));
field.placeholder = '/bin/sh'; field.placeholder = '/bin/sh';
@@ -115,7 +117,8 @@ const PodmanFormContainer = podmanView.form.extend({
field.placeholder = '/host/path:/container/path:ro\nvolume-name:/data'; field.placeholder = '/host/path:/container/path:ro\nvolume-name:/data';
field.rows = 4; field.rows = 4;
field.optional = true; field.optional = true;
field.description = _('One per line. Format: source:destination[:options]. Options: ro, rw, Z, z'); field.description = _(
'One per line. Format: source:destination[:options]. Options: ro, rw, Z, z');
field = this.section.option(form.ListValue, 'network', _('Network')); field = this.section.option(form.ListValue, 'network', _('Network'));
field.depends('pod', ''); field.depends('pod', '');
@@ -254,15 +257,20 @@ const PodmanFormContainer = podmanView.form.extend({
const opts = parts.length > 2 ? parts[2].split(',') : []; const opts = parts.length > 2 ? parts[2].split(',') : [];
if (parts[0].includes('/')) { if (parts[0].includes('/')) {
const mount = { Source: parts[0], Destination: parts[1] }; const mount = {
if (opts.includes('ro')) mount.ReadOnly = true; Type: 'bind',
const selinux = opts.filter((o) => o === 'Z' || o === 'z'); Source: parts[0],
if (selinux.length > 0) mount.options = selinux; Destination: parts[1]
};
if (opts.length > 0) mount.Options = opts;
mounts.push(mount); mounts.push(mount);
return; return;
} }
const vol = { Name: parts[0], Dest: parts[1] }; const vol = {
Name: parts[0],
Dest: parts[1]
};
if (opts.length > 0) vol.Options = opts; if (opts.length > 0) vol.Options = opts;
volumes.push(vol); volumes.push(vol);
}); });
@@ -271,11 +279,17 @@ const PodmanFormContainer = podmanView.form.extend({
} }
if (!data.pod) { if (!data.pod) {
if (data.network === 'host') { if (data.network === 'host') {
spec.netns = { nsmode: 'host' }; spec.netns = {
nsmode: 'host'
};
} else if (data.network === 'none') { } else if (data.network === 'none') {
spec.netns = { nsmode: 'none' }; spec.netns = {
nsmode: 'none'
};
} else if (data.network && data.network !== 'bridge') { } else if (data.network && data.network !== 'bridge') {
spec.networks = { [data.network]: {} }; spec.networks = {
[data.network]: {}
};
} }
} }
if (data.restart !== 'no') spec.restart_policy = data.restart; if (data.restart !== 'no') spec.restart_policy = data.restart;
@@ -304,11 +318,15 @@ const PodmanFormContainer = podmanView.form.extend({
if (data.cpus || data.memory) { if (data.cpus || data.memory) {
spec.resource_limits = {}; spec.resource_limits = {};
if (data.cpus) { if (data.cpus) {
spec.resource_limits.cpu = { quota: parseFloat(data.cpus) * 100000 }; spec.resource_limits.cpu = {
quota: parseFloat(data.cpus) * 100000
};
} }
if (data.memory) { if (data.memory) {
const memBytes = podmanUtil.format.parseMemory(data.memory); const memBytes = podmanUtil.format.parseMemory(data.memory);
if (memBytes > 0) spec.resource_limits.memory = { limit: memBytes }; if (memBytes > 0) spec.resource_limits.memory = {
limit: memBytes
};
} }
} }
@@ -328,7 +346,7 @@ const PodmanFormContainer = podmanView.form.extend({
if (shouldStart) await container.start(); if (shouldStart) await container.start();
}; };
return this.super('handleCreate', [ createFn, _('Container') ]); return this.super('handleCreate', [createFn, _('Container')]);
}, },
}); });
@@ -135,7 +135,9 @@ const Container = Model.base.extend({
}, },
getStateBadge() { getStateBadge() {
return E('div', { class: `badge ${this.getState()}` }, [ this.getState() ]); return E('div', {
class: `badge ${this.getState()}`
}, [this.getState()]);
}, },
getAutoUpdateLabel() { getAutoUpdateLabel() {
@@ -164,7 +166,9 @@ const Container = Model.base.extend({
const networkSettings = this.NetworkSettings || {}; const networkSettings = this.NetworkSettings || {};
const mounts = this.Mounts || []; const mounts = this.Mounts || [];
const spec = { image: imageRef }; const spec = {
image: imageRef
};
// Name (strip leading slash added by Podman inspect) // Name (strip leading slash added by Podman inspect)
if (this.Name) spec.name = this.Name.replace(/^\//, ''); if (this.Name) spec.name = this.Name.replace(/^\//, '');
@@ -179,12 +183,36 @@ const Container = Model.base.extend({
if (config.Hostname) spec.hostname = config.Hostname; if (config.Hostname) spec.hostname = config.Hostname;
if (config.StopSignal) { if (config.StopSignal) {
const sigMap = { const sigMap = {
SIGHUP: 1, SIGINT: 2, SIGQUIT: 3, SIGILL: 4, SIGTRAP: 5, SIGHUP: 1,
SIGABRT: 6, SIGBUS: 7, SIGFPE: 8, SIGKILL: 9, SIGUSR1: 10, SIGINT: 2,
SIGSEGV: 11, SIGUSR2: 12, SIGPIPE: 13, SIGALRM: 14, SIGTERM: 15, SIGQUIT: 3,
SIGCHLD: 17, SIGCONT: 18, SIGSTOP: 19, SIGTSTP: 20, SIGTTIN: 21, SIGILL: 4,
SIGTTOU: 22, SIGURG: 23, SIGXCPU: 24, SIGXFSZ: 25, SIGVTALRM: 26, SIGTRAP: 5,
SIGPROF: 27, SIGWINCH: 28, SIGIO: 29, SIGPWR: 30, SIGSYS: 31, SIGABRT: 6,
SIGBUS: 7,
SIGFPE: 8,
SIGKILL: 9,
SIGUSR1: 10,
SIGSEGV: 11,
SIGUSR2: 12,
SIGPIPE: 13,
SIGALRM: 14,
SIGTERM: 15,
SIGCHLD: 17,
SIGCONT: 18,
SIGSTOP: 19,
SIGTSTP: 20,
SIGTTIN: 21,
SIGTTOU: 22,
SIGURG: 23,
SIGXCPU: 24,
SIGXFSZ: 25,
SIGVTALRM: 26,
SIGPROF: 27,
SIGWINCH: 28,
SIGIO: 29,
SIGPWR: 30,
SIGSYS: 31,
}; };
const sigStr = String(config.StopSignal).toUpperCase().replace(/^SIG/, ''); const sigStr = String(config.StopSignal).toUpperCase().replace(/^SIG/, '');
const sigNum = sigMap['SIG' + sigStr] ?? parseInt(config.StopSignal, 10); const sigNum = sigMap['SIG' + sigStr] ?? parseInt(config.StopSignal, 10);
@@ -213,9 +241,12 @@ const Container = Model.base.extend({
if (hostConfig.CapAdd && hostConfig.CapAdd.length) spec.cap_add = hostConfig.CapAdd; if (hostConfig.CapAdd && hostConfig.CapAdd.length) spec.cap_add = hostConfig.CapAdd;
if (hostConfig.CapDrop && hostConfig.CapDrop.length) spec.cap_drop = hostConfig.CapDrop; if (hostConfig.CapDrop && hostConfig.CapDrop.length) spec.cap_drop = hostConfig.CapDrop;
if (hostConfig.Dns && hostConfig.Dns.length) spec.dns_server = hostConfig.Dns; if (hostConfig.Dns && hostConfig.Dns.length) spec.dns_server = hostConfig.Dns;
if (hostConfig.DnsOptions && hostConfig.DnsOptions.length) spec.dns_option = hostConfig.DnsOptions; if (hostConfig.DnsOptions && hostConfig.DnsOptions.length) spec.dns_option = hostConfig
if (hostConfig.DnsSearch && hostConfig.DnsSearch.length) spec.dns_search = hostConfig.DnsSearch; .DnsOptions;
if (hostConfig.ExtraHosts && hostConfig.ExtraHosts.length) spec.hostadd = hostConfig.ExtraHosts; if (hostConfig.DnsSearch && hostConfig.DnsSearch.length) spec.dns_search = hostConfig
.DnsSearch;
if (hostConfig.ExtraHosts && hostConfig.ExtraHosts.length) spec.hostadd = hostConfig
.ExtraHosts;
if (hostConfig.GroupAdd && hostConfig.GroupAdd.length) spec.groups = hostConfig.GroupAdd; if (hostConfig.GroupAdd && hostConfig.GroupAdd.length) spec.groups = hostConfig.GroupAdd;
if (hostConfig.ShmSize) spec.shm_size = hostConfig.ShmSize; if (hostConfig.ShmSize) spec.shm_size = hostConfig.ShmSize;
if (hostConfig.OomScoreAdj) spec.oom_score_adj = hostConfig.OomScoreAdj; if (hostConfig.OomScoreAdj) spec.oom_score_adj = hostConfig.OomScoreAdj;
@@ -248,7 +279,10 @@ const Container = Model.base.extend({
const [port, protocol] = portProto.split('/'); const [port, protocol] = portProto.split('/');
const containerPort = parseInt(port, 10); const containerPort = parseInt(port, 10);
for (const b of bindings) { for (const b of bindings) {
const m = { container_port: containerPort, protocol: protocol || 'tcp' }; const m = {
container_port: containerPort,
protocol: protocol || 'tcp'
};
if (b.HostPort) m.host_port = parseInt(b.HostPort, 10); if (b.HostPort) m.host_port = parseInt(b.HostPort, 10);
if (b.HostIp && b.HostIp !== '0.0.0.0') m.host_ip = b.HostIp; if (b.HostIp && b.HostIp !== '0.0.0.0') m.host_ip = b.HostIp;
spec.portmappings.push(m); spec.portmappings.push(m);
@@ -260,9 +294,13 @@ const Container = Model.base.extend({
if (hostConfig.Memory > 0 || hostConfig.CpuQuota > 0) { if (hostConfig.Memory > 0 || hostConfig.CpuQuota > 0) {
spec.resource_limits = {}; spec.resource_limits = {};
if (hostConfig.Memory > 0) if (hostConfig.Memory > 0)
spec.resource_limits.memory = { limit: hostConfig.Memory }; spec.resource_limits.memory = {
limit: hostConfig.Memory
};
if (hostConfig.CpuQuota > 0) { if (hostConfig.CpuQuota > 0) {
spec.resource_limits.cpu = { quota: hostConfig.CpuQuota }; spec.resource_limits.cpu = {
quota: hostConfig.CpuQuota
};
if (hostConfig.CpuPeriod > 0) if (hostConfig.CpuPeriod > 0)
spec.resource_limits.cpu.period = hostConfig.CpuPeriod; spec.resource_limits.cpu.period = hostConfig.CpuPeriod;
} }
@@ -281,20 +319,28 @@ const Container = Model.base.extend({
} }
if (bindMounts.length) { if (bindMounts.length) {
spec.mounts = bindMounts.map(m => ({ spec.mounts = bindMounts.map(m => {
Source: m.Source, const options = (m.Options || []).slice();
Destination: m.Destination, if (!m.RW) options.push('ro');
ReadOnly: !m.RW, return {
options: m.Options || [] Type: 'bind',
})); Source: m.Source,
Destination: m.Destination,
Options: options
};
});
} }
// Network // Network
const nm = hostConfig.NetworkMode || ''; const nm = hostConfig.NetworkMode || '';
if (nm === 'host') { if (nm === 'host') {
spec.netns = { nsmode: 'host' }; spec.netns = {
nsmode: 'host'
};
} else if (nm === 'none') { } else if (nm === 'none') {
spec.netns = { nsmode: 'none' }; spec.netns = {
nsmode: 'none'
};
} else { } else {
const nets = networkSettings.Networks || {}; const nets = networkSettings.Networks || {};
const nonDefault = Object.keys(nets).filter(n => n !== 'bridge' && n !== 'default'); const nonDefault = Object.keys(nets).filter(n => n !== 'bridge' && n !== 'default');
@@ -364,7 +410,13 @@ const Container = Model.base.extend({
const portBindings = networkPorts[port] || []; const portBindings = networkPorts[port] || [];
if (portBindings.length === 0) { if (portBindings.length === 0) {
ports.push({ string: port, port: portOnly, protocol: protocol || '', hostPort: null, hostIp: null }); ports.push({
string: port,
port: portOnly,
protocol: protocol || '',
hostPort: null,
hostIp: null
});
return; return;
} }
@@ -393,16 +445,28 @@ const Container = Model.base.extend({
const cleanUrl = this.Image.split('@')[0]; const cleanUrl = this.Image.split('@')[0];
const lastColon = cleanUrl.lastIndexOf(':'); const lastColon = cleanUrl.lastIndexOf(':');
const lastSlash = cleanUrl.lastIndexOf('/'); const lastSlash = cleanUrl.lastIndexOf('/');
return { cleanUrl, lastColon, lastSlash }; return {
cleanUrl,
lastColon,
lastSlash
};
}, },
getImageRepo() { getImageRepo() {
const { cleanUrl, lastColon, lastSlash } = this._parseImageRef(); const {
cleanUrl,
lastColon,
lastSlash
} = this._parseImageRef();
return lastColon > lastSlash ? cleanUrl.substring(0, lastColon) : ''; return lastColon > lastSlash ? cleanUrl.substring(0, lastColon) : '';
}, },
getImageTag() { getImageTag() {
const { cleanUrl, lastColon, lastSlash } = this._parseImageRef(); const {
cleanUrl,
lastColon,
lastSlash
} = this._parseImageRef();
return lastColon > lastSlash ? cleanUrl.substring(lastColon + 1) : 'latest'; return lastColon > lastSlash ? cleanUrl.substring(lastColon + 1) : 'latest';
}, },
@@ -446,15 +510,17 @@ const Container = Model.base.extend({
text = constants.ICON.INIT_DISABLED; text = constants.ICON.INIT_DISABLED;
} }
return E('span', { class: `autostart-status autostart-${status || ''}` }, text); return E('span', {
class: `autostart-status autostart-${status || ''}`
}, text);
}, },
isRunning() { isRunning() {
const state = this.getState(); const state = this.getState();
return this.State?.Running return this.State?.Running ||
|| state === 'running' state === 'running' ||
|| state === 'starting' state === 'starting' ||
|| state === 'unhealthy'; state === 'unhealthy';
}, },
isStopped() { isStopped() {
@@ -530,7 +596,8 @@ const Container = Model.base.extend({
if (hasRestartPolicy && (initScriptStatus === 'none' || initScriptStatus === 'missing')) { if (hasRestartPolicy && (initScriptStatus === 'none' || initScriptStatus === 'missing')) {
await this.generateInitScript(); await this.generateInitScript();
await this.enableInitScript(); await this.enableInitScript();
} else if (!hasRestartPolicy && (initScriptStatus === 'enabled' || initScriptStatus === 'disabled')) { } else if (!hasRestartPolicy && (initScriptStatus === 'enabled' || initScriptStatus ===
'disabled')) {
await this.removeInitScript(); await this.removeInitScript();
} }
}, },
@@ -564,25 +631,39 @@ const Container = Model.base.extend({
}, },
async connect(networkName, payload) { async connect(networkName, payload) {
return Network.getSingleton({ name: networkName }).connect(Object.assign({ container: this.getID() }, payload)); return Network.getSingleton({
name: networkName
}).connect(Object.assign({
container: this.getID()
}, payload));
}, },
async disconnect(networkName) { async disconnect(networkName) {
return Network.getSingleton({ name: networkName }).disconnect({ Container: this.getID() }); return Network.getSingleton({
name: networkName
}).disconnect({
Container: this.getID()
});
}, },
streamTop(onChunk, delay, psargs) { streamTop(onChunk, delay, psargs) {
const params = new URLSearchParams({ delay: String(delay || 2) }); const params = new URLSearchParams({
delay: String(delay || 2)
});
if (psargs) params.set('ps_args', psargs); if (psargs) params.set('ps_args', psargs);
const url = L.url('admin/podman/stream/top', this.getID()) + '?' + params; const url = L.url('admin/podman/stream/top', this.getID()) + '?' + params;
return this._stream( return this._stream(
() => url, () => url,
(data) => { if (!data.raw && !data.Error) onChunk(data); } (data) => {
if (!data.raw && !data.Error) onChunk(data);
}
); );
}, },
streamStats(onChunk, interval) { streamStats(onChunk, interval) {
const params = new URLSearchParams({ interval: String(interval || 2) }); const params = new URLSearchParams({
interval: String(interval || 2)
});
const url = L.url('admin/podman/stream/stats', this.getID()) + '?' + params; const url = L.url('admin/podman/stream/stats', this.getID()) + '?' + params;
return this._stream( return this._stream(
() => url, () => url,
@@ -595,7 +676,12 @@ const Container = Model.base.extend({
); );
}, },
streamLogs(onChunk, { tail = 100, since = null, until = null, follow = true } = {}) { streamLogs(onChunk, {
tail = 100,
since = null,
until = null,
follow = true
} = {}) {
if (!follow) { if (!follow) {
// Historical fetch: single request, stop after completion (no reconnect) // Historical fetch: single request, stop after completion (no reconnect)
let handle; let handle;
@@ -632,7 +718,9 @@ const Container = Model.base.extend({
return L.url('admin/podman/stream/logs', this.getID()) + '?' + params; return L.url('admin/podman/stream/logs', this.getID()) + '?' + params;
}, },
onChunk, onChunk,
() => { reconnectSince = Date.now() / 1000; } () => {
reconnectSince = Date.now() / 1000;
}
); );
}, },
@@ -656,7 +744,9 @@ const Container = Model.base.extend({
const imageRef = image.getDisplayTag() || this.Image; const imageRef = image.getDisplayTag() || this.Image;
if (!imageRef || imageRef.startsWith('<none>')) if (!imageRef || imageRef.startsWith('<none>'))
return { hasUpdate: false }; return {
hasUpdate: false
};
const localArch = image.Architecture || 'amd64'; const localArch = image.Architecture || 'amd64';
const localOs = image.Os || 'linux'; const localOs = image.Os || 'linux';
@@ -666,7 +756,8 @@ const Container = Model.base.extend({
const remoteDigest = findArchDigest(manifest, localArch, localOs); const remoteDigest = findArchDigest(manifest, localArch, localOs);
const repoDigests = image.RepoDigests || []; const repoDigests = image.RepoDigests || [];
const hasUpdate = !!(remoteDigest && !repoDigests.some(rd => rd.includes(remoteDigest))); const hasUpdate = !!(remoteDigest && !repoDigests.some(rd => rd.includes(
remoteDigest)));
return { return {
hasUpdate, hasUpdate,
@@ -727,37 +818,58 @@ const Container = Model.base.extend({
if (wasRunning) { if (wasRunning) {
onProgress?.('→ ' + _('Stopping container') + '\n'); onProgress?.('→ ' + _('Stopping container') + '\n');
try { await this.stop(); } try {
catch (e) { throw new Error(_('Stop failed: %s').format(e.message || e)); } await this.stop();
} catch (e) {
throw new Error(_('Stop failed: %s').format(e.message || e));
}
} }
onProgress?.('→ ' + _('Removing container') + '\n'); onProgress?.('→ ' + _('Removing container') + '\n');
try { await this.remove(); } try {
catch (e) { throw new Error(_('Remove failed: %s').format(e.message || e)); } await this.remove();
} catch (e) {
throw new Error(_('Remove failed: %s').format(e.message || e));
}
onProgress?.('→ ' + _('Creating container') + '\n'); onProgress?.('→ ' + _('Creating container') + '\n');
let created; let created;
try { created = await ContainerRPC.create(spec); } try {
catch (e) { throw new Error(_('Create failed: %s').format(e.message || e)); } created = await ContainerRPC.create(spec);
} catch (e) {
throw new Error(_('Create failed: %s').format(e.message || e));
}
if (!created || created.error) if (!created || created.error)
throw new Error(_('Create failed: %s').format(created?.error || _('Failed to create container'))); throw new Error(_('Create failed: %s').format(created?.error || _(
'Failed to create container')));
if (wasRunning) { if (wasRunning) {
onProgress?.('→ ' + _('Starting container') + '\n'); onProgress?.('→ ' + _('Starting container') + '\n');
try { await ContainerRPC.start(created.Id); } try {
catch (e) { throw new Error(_('Start failed: %s').format(e.message || e)); } await ContainerRPC.start(created.Id);
} catch (e) {
throw new Error(_('Start failed: %s').format(e.message || e));
}
} }
onProgress?.('→ ' + _('Reinstating init script') + '\n'); onProgress?.('→ ' + _('Reinstating init script') + '\n');
try { await this._reinstateInitScript(initStatus); } try {
catch (e) { throw new Error(_('Init script reinstate failed: %s').format(e.message || e)); } await this._reinstateInitScript(initStatus);
} catch (e) {
throw new Error(_('Init script reinstate failed: %s').format(e.message || e));
}
onProgress?.('✓ ' + _('Updated to %s').format((newImageId || '').substring(0, 12)) + '\n'); onProgress?.('✓ ' + _('Updated to %s').format((newImageId || '').substring(0, 12)) +
return { oldImage: image }; '\n');
return {
oldImage: image
};
}, },
async getImage() { async getImage() {
const image = Image.getSingleton({ Id: this.ImageID || this.Image }); const image = Image.getSingleton({
Id: this.ImageID || this.Image
});
return Image.getSingleton(await image.inspect()); return Image.getSingleton(await image.inspect());
}, },
@@ -22,7 +22,6 @@
import { readfile, writefile, popen, stat, chmod, unlink, glob, access } from 'fs'; import { readfile, writefile, popen, stat, chmod, unlink, glob, access } from 'fs';
import { cursor } from 'uci'; import { cursor } from 'uci';
import { urlencode, ENCODE_FULL } from 'lucihttp'; // ucode-lsp disable import { urlencode, ENCODE_FULL } from 'lucihttp'; // ucode-lsp disable
import { init_enabled, init_action } from 'luci.sys'; // ucode-lsp disable
import * as podman_socket from 'luci.podman_socket'; // ucode-lsp disable import * as podman_socket from 'luci.podman_socket'; // ucode-lsp disable
import { API_BASE } from 'luci.podman_socket'; // ucode-lsp disable import { API_BASE } from 'luci.podman_socket'; // ucode-lsp disable
import { import {
@@ -33,6 +32,9 @@ import {
build_request, parse_status, parse_content_length, read_headers build_request, parse_status, parse_content_length, read_headers
} from 'luci.podman_http'; // ucode-lsp disable } from 'luci.podman_http'; // ucode-lsp disable
import { connect } from 'ubus';
let ubus = connect();
// --- Configuration --- // --- Configuration ---
const uci = cursor(); const uci = cursor();
@@ -897,14 +899,17 @@ const methods = {
let err = require_param('name', req.args.name) || validate_name(req.args.name); let err = require_param('name', req.args.name) || validate_name(req.args.name);
if (err) return { error: err }; if (err) return { error: err };
let script_path = init_script_path(req.args.name); let name = `${INIT_SCRIPT_PREFIX}${req.args.name}`;
let exists = !!stat(script_path); return ubus.defer(
let enabled = false; 'rc', 'list', { name: name },
function (rc, reply) {
if (exists) if (reply[name] == null) {
enabled = init_enabled(`${INIT_SCRIPT_PREFIX}${req.args.name}`); req.reply({ exists: false, enabled: false });
} else {
return { exists: exists, enabled: enabled }; req.reply({ exists: true, enabled: reply[name].enabled });
}
}
);
} }
}, },
@@ -918,12 +923,18 @@ const methods = {
if (!stat(script_path)) if (!stat(script_path))
return { error: 'Init script not found. Generate it first.' }; return { error: 'Init script not found. Generate it first.' };
let name = `${INIT_SCRIPT_PREFIX}${req.args.name}`;
let action = (req.args.enabled === true || req.args.enabled === 1) ? 'enable' : 'disable'; let action = (req.args.enabled === true || req.args.enabled === 1) ? 'enable' : 'disable';
let rc = init_action(`${INIT_SCRIPT_PREFIX}${req.args.name}`, action); return ubus.defer(
if (rc) 'rc', 'init', { name: name, action: action },
return { error: `Failed to ${action} service` }; function (rc, reply) {
if (rc == 0) {
return { success: true, enabled: (action === 'enable') }; req.reply({ success: true, enabled: (action === 'enable')});
} else {
req.reply({ error: `Failed to ${action} service: ${reply}`});
}
}
);
} }
}, },
@@ -938,13 +949,22 @@ const methods = {
return { success: true, message: 'Init script does not exist' }; return { success: true, message: 'Init script does not exist' };
// Disable before removing // Disable before removing
init_action(`${INIT_SCRIPT_PREFIX}${req.args.name}`, 'disable'); let name = `${INIT_SCRIPT_PREFIX}${req.args.name}`;
unlink(script_path); return ubus.call(
'rc', 'init', { name: name, action: 'disable' },
if (stat(script_path)) function (rc, reply) {
return { error: 'Failed to remove init script' }; if (rc == 0) {
unlink(script_path);
return { success: true }; if (stat(script_path)) {
req.reply({ error: 'failed to remove init script' });
} else {
req.reply({ success: true });
}
} else {
req.reply({ error: `Failed to disable service: ${reply}` });
}
}
);
} }
} }
}; };
@@ -678,7 +678,8 @@ function getDisplayTxPower(radioNet) {
if (isPlausibleTxPowerValue(info != null ? info.txpower : null, hwtype)) if (isPlausibleTxPowerValue(info != null ? info.txpower : null, hwtype))
return info.txpower; return info.txpower;
if (isPlausibleTxPowerValue(cfgvalue, hwtype)) // mt_dbdc configures power as a percentage, not dBm.
if (hwtype != 'mt_dbdc' && isPlausibleTxPowerValue(cfgvalue, hwtype))
return cfgvalue; return cfgvalue;
return null; return null;
@@ -1404,7 +1405,9 @@ function getDisplaySignalPercent(radioNet, hwtype, is_assoc, disabled) {
} }
function getDisplaySignalValue(radioNet, hwtype, is_assoc) { function getDisplaySignalValue(radioNet, hwtype, is_assoc) {
if ((hwtype == 'mt_dbdc' || (isQcaWifiHwtype(hwtype) && radioNet.getMode() == 'ap')) && is_assoc) if (hwtype == 'mt_dbdc' && radioNet.getMode() == 'ap')
return is_assoc ? getDisplayTxPower(radioNet) : null;
if (isQcaWifiHwtype(hwtype) && radioNet.getMode() == 'ap' && is_assoc)
return getDisplayTxPower(radioNet) ?? 30; return getDisplayTxPower(radioNet) ?? 30;
return radioNet.getSignal(); return radioNet.getSignal();
@@ -1437,7 +1440,7 @@ function renderStatusRow(pairs, className) {
return added ? row : null; return added ? row : null;
} }
function render_signal_badge(signalPercent, signalValue, noiseValue, wrap, mode) { function render_signal_badge(signalPercent, signalValue, noiseValue, wrap, mode, txpower = false) {
let icon = L.resource('icons/signal-075-100.svg'), title, value; let icon = L.resource('icons/signal-075-100.svg'), title, value;
switch(true) { switch(true) {
@@ -1459,13 +1462,13 @@ function render_signal_badge(signalPercent, signalValue, noiseValue, wrap, mode)
} }
else { else {
value = `${signalValue}\xa0${_('dBm')}`; value = `${signalValue}\xa0${_('dBm')}`;
title = `${_('Signal')} ${signalValue} ${_('dBm')}`; title = `${txpower ? _('Tx-Power') : _('Signal')} ${signalValue} ${_('dBm')}`;
} }
} }
else if (signalPercent > -1) { else if (signalPercent > -1) {
switch (mode) { switch (mode) {
case 'ap': case 'ap':
title = _('No client associated'); title = txpower ? _('Tx-Power') : _('No client associated');
break; break;
case 'sta': case 'sta':
@@ -1516,7 +1519,8 @@ function render_network_badge(radioNet) {
return render_signal_badge( return render_signal_badge(
getDisplaySignalPercent(radioNet, hwtype, is_assoc, disabled), getDisplaySignalPercent(radioNet, hwtype, is_assoc, disabled),
getDisplaySignalValue(radioNet, hwtype, is_assoc), getDisplaySignalValue(radioNet, hwtype, is_assoc),
getDisplayNoiseValue(radioNet, hwtype, is_assoc), false, radioNet.getMode()); getDisplayNoiseValue(radioNet, hwtype, is_assoc), false, radioNet.getMode(),
hwtype == 'mt_dbdc' && radioNet.getMode() == 'ap');
} }
function render_radio_status(radioDev, wifiNets) { function render_radio_status(radioDev, wifiNets) {
@@ -1591,7 +1595,8 @@ function render_modal_status(node, radioNet) {
dom.content(node.firstElementChild, render_signal_badge( dom.content(node.firstElementChild, render_signal_badge(
getDisplaySignalPercent(radioNet, hwtype, is_assoc, disabled), getDisplaySignalPercent(radioNet, hwtype, is_assoc, disabled),
getDisplaySignalValue(radioNet, hwtype, is_assoc), noise, true, radioNet.getMode())); getDisplaySignalValue(radioNet, hwtype, is_assoc), noise, true, radioNet.getMode(),
hwtype == 'mt_dbdc' && radioNet.getMode() == 'ap'));
L.itemlist(node.lastElementChild, [ L.itemlist(node.lastElementChild, [
_('Mode'), mode, _('Mode'), mode,
+2 -2
View File
@@ -14,8 +14,8 @@ MISE_HASH_x86_64:=3832f39c325e343f81fe3d92b2447c5d1a5eea1bc85092bb7b6c2580622264
MISE_HASH_aarch64:=06186cfbfe947049b21d58575fb0ea800cc26ed1375f20f4b678cb3a9d679437 MISE_HASH_aarch64:=06186cfbfe947049b21d58575fb0ea800cc26ed1375f20f4b678cb3a9d679437
PKG_NAME:=mise PKG_NAME:=mise
PKG_VERSION:=2026.10.12 PKG_VERSION:=2026.10.13
PKG_RELEASE:=36 PKG_RELEASE:=37
PKG_SOURCE:=$(PKG_NAME)-v$(PKG_VERSION)-linux-$(MISE_ARCH)-musl.tar.gz PKG_SOURCE:=$(PKG_NAME)-v$(PKG_VERSION)-linux-$(MISE_ARCH)-musl.tar.gz
PKG_SOURCE_URL:=https://github.com/jdx/mise/releases/download/v$(PKG_VERSION)/ PKG_SOURCE_URL:=https://github.com/jdx/mise/releases/download/v$(PKG_VERSION)/
PKG_HASH:=skip PKG_HASH:=skip
+2 -2
View File
@@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=natflow PKG_NAME:=natflow
PKG_VERSION:=20260930 PKG_VERSION:=20260930
PKG_RELEASE:=94 PKG_RELEASE:=95
PKG_SOURCE:=$(PKG_VERSION).tar.xz PKG_SOURCE:=$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=68cc4c87a23a1afbdb194bd3d3f9bb64d767f6ba PKG_SOURCE_VERSION:=51496417511f8dc4ebef2618206db11ddedd7773
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com> PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com>
PKG_LICENSE:=GPL-2.0 PKG_LICENSE:=GPL-2.0
+3 -3
View File
@@ -50,12 +50,12 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=wwand PKG_NAME:=wwand
PKG_VERSION:=1.7.0_pre33 PKG_VERSION:=1.8.0_pre3
PKG_RELEASE:=79 PKG_RELEASE:=80
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/ddimension/wwand.git PKG_SOURCE_URL:=https://github.com/ddimension/wwand.git
PKG_SOURCE_VERSION:=5281731de7f5465552a9bba1b909b082b3050fae PKG_SOURCE_VERSION:=8a170a136d1e1340ef54da2006edc8b622a87e43
PKG_MIRROR_HASH:=skip PKG_MIRROR_HASH:=skip
PKG_LICENSE:=GPL-2.0-only PKG_LICENSE:=GPL-2.0-only
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=Xray-core PKG_NAME:=Xray-core
PKG_VERSION:=26.10.10 PKG_VERSION:=26.10.17
PKG_RELEASE:=25 PKG_RELEASE:=26
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/XTLS/Xray-core/tar.gz/v$(PKG_VERSION)? PKG_SOURCE_URL:=https://codeload.github.com/XTLS/Xray-core/tar.gz/v$(PKG_VERSION)?