🛸 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_PKGARCH:=all
PKG_VERSION:=0.1.53
PKG_RELEASE:=69
PKG_VERSION:=0.1.54
PKG_RELEASE:=70
# Reproducible build: honor SOURCE_DATE_EPOCH from the build environment (set by docker-sdk.sh / CI).
ifdef SOURCE_DATE_EPOCH
@@ -9,7 +9,7 @@
*/
return baseclass.extend({
/* 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],
DEFAULT_ROW_LIMIT: 100,
FETCH_MODE_OPTIONS: ['auto', 'manual'],
@@ -11,5 +11,5 @@
* GENERATED — do not edit. Edit fwlive.css and run: node scripts/embed-fwlive-css.js
*/
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);
}
.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) {
.fwlive-title-status {
flex-basis: 100%;
@@ -231,8 +231,37 @@ return baseclass.extend({
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) {
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';
},
@@ -7,6 +7,11 @@
/* 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.
* 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) {
const { getEpoch, render, renderCost, capacity, requestFrame, cancelFrame } = options;
if (!Number.isFinite(capacity) || capacity <= 0)
@@ -71,7 +76,7 @@ function createScheduler(options) {
const cost = renderCost({
visibleRowCount: rows.length,
visibleHeadId: rows.length ? rows[0].id : '',
visibleHeadId: headIdentity(rows),
lastRenderedRowCount: lastRenderedRowCount,
lastRenderedHeadId: lastRenderedHeadId,
lastBatchNewIdCount: lastBatchNewIdCount
@@ -101,7 +106,7 @@ function createScheduler(options) {
function markRendered(rows) {
lastRenderedRowCount = rows.length;
lastRenderedHeadId = rows.length ? rows[0].id : '';
lastRenderedHeadId = headIdentity(rows);
}
function resetBudget() {
@@ -152,6 +152,10 @@ return view.extend({
entries: [],
filteredRowsCache: 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,
/* Freezes row rendering while polling, health, and cadence updates continue. */
tablePaused: false,
@@ -210,6 +214,8 @@ return view.extend({
ruleTargets: {},
firewallBackend: 'nft',
viewMode: 'simple',
/* Hash diag=1: adaptive banner and unactionable Watching tags. */
diagnosticMode: false,
expandedRowId: null,
loggingStatus: null,
/* 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)));
}
if (this.viewMode === 'detailed') parts.push('view=detailed');
if (this.diagnosticMode) parts.push('diag=1');
history.replaceState(history.state, '', '#' + parts.join('&'));
},
@@ -420,12 +427,17 @@ return view.extend({
applyHash() {
this.resolveRpcPreferences();
this.diagnosticMode = false;
const entries = this.hashEntries();
for (let i = 0; i < entries.length; i++) {
const key = entries[i].key;
const val = entries[i].val;
if (key === 'limit' || key === 'poll' || key === 'maxraw') continue;
if (key === 'fetch-mode' || key === 'row-tint') continue;
if (key === 'diag') {
this.diagnosticMode = val === '1' || val === 'true';
continue;
}
if (key === 'view') {
if (val === 'advanced' || val === 'detailed') this.viewMode = 'detailed';
else if (val === 'simple') this.viewMode = 'simple';
@@ -687,6 +699,7 @@ return view.extend({
this.updateDetailToggleUi();
this.renderThead();
this.updateHash(this.readFilters());
this.updateAdaptiveBanner();
this.renderRows(true);
},
@@ -1166,6 +1179,12 @@ return view.extend({
const row = this.enrichEntry(log.normalizeEntry(raw[i]));
if (seen[row.id]) continue;
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++;
normalized.push(row);
}
@@ -1249,7 +1268,9 @@ return view.extend({
this.notePollRtt(rtt, false);
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) {
this.summaryData =
reply.summary &&
@@ -1272,7 +1293,7 @@ return view.extend({
this.entries = buffer.applyFetchedEntries(this.entries, batch.rows, {
/* buffer.js retains its public paused option; this is the view's table state. */
paused: this.tablePaused,
resumeMerge: resumeMerge || context.pausedAtStart,
resumeMerge: resumeMerge || context.pausedAtStart || !!this.clearedEntryKeys,
rowLimit: this.rowLimit,
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) {
if (!this.sessionSeen) this.sessionSeen = new Set();
if (this.sessionSeen.has(id)) return false;
@@ -1356,9 +1389,11 @@ return view.extend({
bits.push(
_('display limited to %d rows').format(constants.WEAK_DEVICE_DISPLAY_ROW_CAP)
);
if (this.degradedSampling) bits.push(_('polling slowed'));
if (this.serverTruncated) bits.push(_('server limited fetch'));
if (this.resolveLoadShed) bits.push(_('hostname lookup paused'));
if (this.diagnosticMode) {
if (this.degradedSampling) bits.push(_('polling slowed'));
if (this.serverTruncated) bits.push(_('server limited fetch'));
if (this.resolveLoadShed) bits.push(_('hostname lookup paused'));
}
if (!this.tablePaused && !this.followLive)
bits.push(_('scroll frozen — scroll to top to follow live'));
return bits.length ? ' — ' + bits.join(', ') : '';
@@ -1554,7 +1589,7 @@ return view.extend({
const el = document.getElementById('fwlive-adaptive');
if (!el) return;
const parts = this.adaptiveBannerParts();
const parts = !this.diagnosticMode || this.summaryMode ? [] : this.adaptiveBannerParts();
if (parts.length) {
el.style.display = 'block';
@@ -1653,6 +1688,7 @@ return view.extend({
this.summaryData =
summary && typeof summary === 'object' && !Array.isArray(summary) ? summary : null;
this.renderSummary();
this.updateAdaptiveBanner();
},
leaveSummaryMode() {
@@ -1661,6 +1697,7 @@ return view.extend({
this.summaryRowsShown = false;
this.summaryData = null;
this.updateSummaryUi();
this.updateAdaptiveBanner();
if (this.tablePaused) {
this.syncEmptyScrollVisibility(this.filteredRowsState().rows.length);
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) {
const n = parseInt(ev && ev.target ? ev.target.value : '', 10);
if (!isFinite(n) || constants.ROW_LIMIT_OPTIONS.indexOf(n) < 0) return;
@@ -2426,6 +2486,9 @@ return view.extend({
const pauseBtn = document.getElementById('fwlive-pause');
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');
if (limitSel) limitSel.addEventListener('change', this.onRowLimitChange.bind(this));
@@ -2562,7 +2625,10 @@ return view.extend({
{
'id': 'fwlive-fetch-mode',
'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()
)
@@ -2628,6 +2694,11 @@ return view.extend({
'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', {}, [
_(
'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', {}, [
_(
'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', {}, [
@@ -2645,7 +2716,7 @@ return view.extend({
]),
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', {}, [
@@ -2772,6 +2843,16 @@ return view.extend({
},
[_('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('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 ""
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"
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"
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"
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"
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"
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"
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 ""
"%s · requested up to %d raw lines · server limited fetch to %d · %d firewall "
"messages returned"
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"
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"
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)"
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/view/status/fwlive.js:2896
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2977
msgid "Action"
msgstr ""
@@ -54,11 +54,11 @@ msgid ""
"Activate the message button or click a row to show or hide the full message"
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."
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."
msgstr ""
@@ -66,7 +66,7 @@ msgstr ""
msgid "Allow/deny rules, LAN logging, or anything else."
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"
msgstr ""
@@ -80,19 +80,25 @@ msgid ""
"state."
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"
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"
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:1570
#: 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:1605
msgid "Auto"
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
msgid "Before you enable logging"
msgstr ""
@@ -105,33 +111,43 @@ msgstr ""
msgid "Changes:"
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)"
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"
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:274
msgid "Clear all"
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 ""
"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 "
"row to show or hide the full message"
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 ""
"Click an IP, action, or protocol to filter; use the Protocol menu (or ≠ on a "
"chip) to exclude."
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"
msgstr ""
@@ -141,7 +157,7 @@ msgid ""
"it; kernel/logd may still constrain total log volume."
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…"
msgstr ""
@@ -153,49 +169,49 @@ msgstr ""
msgid "Could not clear the WAN zone log option."
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."
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."
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."
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."
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."
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."
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:983
#: 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:963
#: 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:1012
msgid "Could not reach the router; check the current logging state."
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."
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."
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."
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."
msgstr ""
@@ -215,7 +231,7 @@ msgstr ""
msgid "Could not write the WAN zone log option."
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."
msgstr ""
@@ -223,28 +239,28 @@ msgstr ""
msgid "DPort"
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
msgid "Destination"
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)"
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"
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)"
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"
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"
msgstr ""
@@ -256,20 +272,20 @@ msgstr ""
msgid "Disabling…"
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 ""
"Display limited to %d rows on this device; the larger Limit still buffers "
"rows."
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"
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 ""
"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."
msgstr ""
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/logging.js:387
@@ -288,7 +304,7 @@ msgstr ""
msgid "Enable logging"
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 ""
"Enable logging turns on WAN zone drop/reject logging only (same as Network → "
"Firewall). It does not add rules or log normal LAN browsing."
@@ -298,7 +314,7 @@ msgstr ""
msgid "Enabling…"
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"
msgstr ""
@@ -307,20 +323,14 @@ msgstr ""
msgid "Exclude instead"
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"
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:84
#: 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"
msgstr ""
@@ -328,12 +338,12 @@ msgstr ""
msgid "Filter logs by rule (hint: %s). Ctrl+click to open firewall settings."
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
msgid "Firewall Live View"
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."
msgstr ""
@@ -345,7 +355,7 @@ msgstr ""
msgid "Flow"
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 ""
"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."
@@ -359,7 +369,7 @@ msgstr ""
msgid "Grant access to firewall live log view"
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"
msgstr ""
@@ -367,15 +377,15 @@ msgstr ""
msgid "Hide full message"
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"
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."
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"
msgstr ""
@@ -383,7 +393,7 @@ msgstr ""
msgid "IN"
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 ""
"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 "
@@ -396,7 +406,7 @@ msgid ""
"Help / the enabling-logs guide."
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 ""
"In Simple view, activate the message button or click a row to show or hide "
"the full message."
@@ -417,16 +427,16 @@ msgid ""
"release, then reload the firewall."
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."
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
msgid "Interface"
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)"
msgstr ""
@@ -443,11 +453,18 @@ msgstr ""
msgid "Len"
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"
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"
msgstr ""
@@ -455,16 +472,16 @@ msgstr ""
msgid "Logging is off on this router"
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:1571
#: 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:1606
msgid "Manual"
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"
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 ""
"Manual still uses server protection and poll cadence; it changes the fetch "
"budget, not the polling interval."
@@ -474,18 +491,18 @@ msgstr ""
msgid "Manual test (System → Terminal):"
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"
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: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:2826
#: 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:2907
msgid "Message"
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"
msgstr ""
@@ -528,7 +545,7 @@ msgstr ""
msgid "OUT"
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"
msgstr ""
@@ -555,34 +572,34 @@ msgstr ""
msgid "Outbound"
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"
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:2773
#: 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:2844
msgid "Pause"
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"
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 ""
"Polling slowed: the router is responding slowly, so polls run less often."
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
msgid "Proto"
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"
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"
msgstr ""
@@ -596,22 +613,26 @@ msgstr ""
msgid "Remove filter"
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"
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"
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 ""
"Row tint shows pass/deny row backgrounds when checked. Choose Classic (green/"
"red, default) or Accessible (teal/orange). Action text stays colored either "
"way."
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 ""
"Row tint used a local color fallback because the active LuCI theme did not "
"apply pass/deny backgrounds."
@@ -621,19 +642,19 @@ msgstr ""
msgid "Rule"
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"
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."
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."
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."
msgstr ""
@@ -641,26 +662,26 @@ msgstr ""
msgid "SPort"
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"
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."
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 ""
"Server limited fetch: the router is under load; at most %d log lines per "
"poll."
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 ""
"Server limited fetch: this poll returned fewer lines to protect the router."
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."
msgstr ""
@@ -668,80 +689,80 @@ msgstr ""
msgid "Show full message"
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"
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"
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:2872
#: 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:2953
msgid "Show rows"
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."
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"
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 ""
"Some entries may show names derived from their log prefixes. Searching by a "
"friendly rule name may miss those entries."
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"
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
msgid "Source"
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)"
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"
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)"
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."
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"
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 ""
"Summary mode: when the router responds slowly, a compact summary replaces "
"the table. Use Show rows to see the table; it returns automatically after "
"three fast polls."
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."
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 ""
"Switching tabs pauses polling; returning performs one catch-up poll. "
"Hostnames are off by default because lookups add work."
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 ""
"Table refresh throttled: the event rate is high, so the table repaints less "
"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."
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 ""
"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 "
@@ -760,23 +781,23 @@ msgid ""
"fwlive does not impose a limit."
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…"
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 ""
"The router log ring may evict older events before fwlive reads them. fwlive "
"cannot recover evicted entries or change forwarding behavior."
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 ""
"The table updates automatically when your firewall logs traffic. Use Pause "
"if it moves too fast."
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"
msgstr ""
@@ -793,15 +814,15 @@ msgstr ""
msgid "Time"
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"
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"
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"
msgstr ""
@@ -823,16 +844,16 @@ msgstr ""
msgid "Undo:"
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)."
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:2784
#: 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:2865
msgid "View"
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."
msgstr ""
@@ -842,13 +863,13 @@ msgid ""
"here. Normal LAN browsing will not."
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 ""
"WAN drop/reject logging is on. Blocked inbound traffic should appear here as "
"it happens — not normal LAN browsing."
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."
msgstr ""
@@ -877,25 +898,25 @@ msgstr ""
msgid "Waiting for firewall events"
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:2736
#: 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:2807
msgid "Watching"
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"
msgstr ""
#: 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"
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"
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"
msgstr ""
@@ -907,7 +928,7 @@ msgstr ""
msgid "contains"
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"
msgstr ""
@@ -916,11 +937,11 @@ msgid "does not contain"
msgstr ""
#: 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"
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"
msgstr ""
@@ -928,11 +949,11 @@ msgstr ""
msgid "is"
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"
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…"
msgstr ""
@@ -940,8 +961,8 @@ msgstr ""
msgid "no WAN rate limit configured"
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:1596
#: 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:1631
msgid "none"
msgstr ""
@@ -949,98 +970,98 @@ msgstr ""
msgid "not"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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…"
msgstr ""
#: 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"
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"
msgstr ""
#: 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"
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"
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"
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"
msgstr ""
#: 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"
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"
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
}
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) {
s = strip_kv(s)
s = strip_kv(strip_leading_rule_hint(s))
n = split("ACCEPT ALLOW PASS DROP REJECT DENY BLOCK", words, " ")
lc = tolower(s)
best = ""
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-open-box
PKG_VERSION:=0.1.337
PKG_RELEASE:=34
PKG_VERSION:=0.1.338
PKG_RELEASE:=35
PKG_MAINTAINER:=liandu2024
PKG_LICENSE:=GPL-3.0-or-later
@@ -85,7 +85,9 @@ const PodmanFormContainer = podmanView.form.extend({
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.placeholder = '/bin/sh';
@@ -115,7 +117,8 @@ const PodmanFormContainer = podmanView.form.extend({
field.placeholder = '/host/path:/container/path:ro\nvolume-name:/data';
field.rows = 4;
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.depends('pod', '');
@@ -254,15 +257,20 @@ const PodmanFormContainer = podmanView.form.extend({
const opts = parts.length > 2 ? parts[2].split(',') : [];
if (parts[0].includes('/')) {
const mount = { Source: parts[0], Destination: parts[1] };
if (opts.includes('ro')) mount.ReadOnly = true;
const selinux = opts.filter((o) => o === 'Z' || o === 'z');
if (selinux.length > 0) mount.options = selinux;
const mount = {
Type: 'bind',
Source: parts[0],
Destination: parts[1]
};
if (opts.length > 0) mount.Options = opts;
mounts.push(mount);
return;
}
const vol = { Name: parts[0], Dest: parts[1] };
const vol = {
Name: parts[0],
Dest: parts[1]
};
if (opts.length > 0) vol.Options = opts;
volumes.push(vol);
});
@@ -271,11 +279,17 @@ const PodmanFormContainer = podmanView.form.extend({
}
if (!data.pod) {
if (data.network === 'host') {
spec.netns = { nsmode: 'host' };
spec.netns = {
nsmode: 'host'
};
} else if (data.network === 'none') {
spec.netns = { nsmode: 'none' };
spec.netns = {
nsmode: 'none'
};
} else if (data.network && data.network !== 'bridge') {
spec.networks = { [data.network]: {} };
spec.networks = {
[data.network]: {}
};
}
}
if (data.restart !== 'no') spec.restart_policy = data.restart;
@@ -304,11 +318,15 @@ const PodmanFormContainer = podmanView.form.extend({
if (data.cpus || data.memory) {
spec.resource_limits = {};
if (data.cpus) {
spec.resource_limits.cpu = { quota: parseFloat(data.cpus) * 100000 };
spec.resource_limits.cpu = {
quota: parseFloat(data.cpus) * 100000
};
}
if (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();
};
return this.super('handleCreate', [ createFn, _('Container') ]);
return this.super('handleCreate', [createFn, _('Container')]);
},
});
@@ -135,7 +135,9 @@ const Container = Model.base.extend({
},
getStateBadge() {
return E('div', { class: `badge ${this.getState()}` }, [ this.getState() ]);
return E('div', {
class: `badge ${this.getState()}`
}, [this.getState()]);
},
getAutoUpdateLabel() {
@@ -164,7 +166,9 @@ const Container = Model.base.extend({
const networkSettings = this.NetworkSettings || {};
const mounts = this.Mounts || [];
const spec = { image: imageRef };
const spec = {
image: imageRef
};
// Name (strip leading slash added by Podman inspect)
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.StopSignal) {
const sigMap = {
SIGHUP: 1, SIGINT: 2, SIGQUIT: 3, SIGILL: 4, SIGTRAP: 5,
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,
SIGHUP: 1,
SIGINT: 2,
SIGQUIT: 3,
SIGILL: 4,
SIGTRAP: 5,
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 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.CapDrop && hostConfig.CapDrop.length) spec.cap_drop = hostConfig.CapDrop;
if (hostConfig.Dns && hostConfig.Dns.length) spec.dns_server = hostConfig.Dns;
if (hostConfig.DnsOptions && hostConfig.DnsOptions.length) spec.dns_option = hostConfig.DnsOptions;
if (hostConfig.DnsSearch && hostConfig.DnsSearch.length) spec.dns_search = hostConfig.DnsSearch;
if (hostConfig.ExtraHosts && hostConfig.ExtraHosts.length) spec.hostadd = hostConfig.ExtraHosts;
if (hostConfig.DnsOptions && hostConfig.DnsOptions.length) spec.dns_option = hostConfig
.DnsOptions;
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.ShmSize) spec.shm_size = hostConfig.ShmSize;
if (hostConfig.OomScoreAdj) spec.oom_score_adj = hostConfig.OomScoreAdj;
@@ -248,7 +279,10 @@ const Container = Model.base.extend({
const [port, protocol] = portProto.split('/');
const containerPort = parseInt(port, 10);
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.HostIp && b.HostIp !== '0.0.0.0') m.host_ip = b.HostIp;
spec.portmappings.push(m);
@@ -260,9 +294,13 @@ const Container = Model.base.extend({
if (hostConfig.Memory > 0 || hostConfig.CpuQuota > 0) {
spec.resource_limits = {};
if (hostConfig.Memory > 0)
spec.resource_limits.memory = { limit: hostConfig.Memory };
spec.resource_limits.memory = {
limit: hostConfig.Memory
};
if (hostConfig.CpuQuota > 0) {
spec.resource_limits.cpu = { quota: hostConfig.CpuQuota };
spec.resource_limits.cpu = {
quota: hostConfig.CpuQuota
};
if (hostConfig.CpuPeriod > 0)
spec.resource_limits.cpu.period = hostConfig.CpuPeriod;
}
@@ -281,20 +319,28 @@ const Container = Model.base.extend({
}
if (bindMounts.length) {
spec.mounts = bindMounts.map(m => ({
Source: m.Source,
Destination: m.Destination,
ReadOnly: !m.RW,
options: m.Options || []
}));
spec.mounts = bindMounts.map(m => {
const options = (m.Options || []).slice();
if (!m.RW) options.push('ro');
return {
Type: 'bind',
Source: m.Source,
Destination: m.Destination,
Options: options
};
});
}
// Network
const nm = hostConfig.NetworkMode || '';
if (nm === 'host') {
spec.netns = { nsmode: 'host' };
spec.netns = {
nsmode: 'host'
};
} else if (nm === 'none') {
spec.netns = { nsmode: 'none' };
spec.netns = {
nsmode: 'none'
};
} else {
const nets = networkSettings.Networks || {};
const nonDefault = Object.keys(nets).filter(n => n !== 'bridge' && n !== 'default');
@@ -364,7 +410,13 @@ const Container = Model.base.extend({
const portBindings = networkPorts[port] || [];
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;
}
@@ -393,16 +445,28 @@ const Container = Model.base.extend({
const cleanUrl = this.Image.split('@')[0];
const lastColon = cleanUrl.lastIndexOf(':');
const lastSlash = cleanUrl.lastIndexOf('/');
return { cleanUrl, lastColon, lastSlash };
return {
cleanUrl,
lastColon,
lastSlash
};
},
getImageRepo() {
const { cleanUrl, lastColon, lastSlash } = this._parseImageRef();
const {
cleanUrl,
lastColon,
lastSlash
} = this._parseImageRef();
return lastColon > lastSlash ? cleanUrl.substring(0, lastColon) : '';
},
getImageTag() {
const { cleanUrl, lastColon, lastSlash } = this._parseImageRef();
const {
cleanUrl,
lastColon,
lastSlash
} = this._parseImageRef();
return lastColon > lastSlash ? cleanUrl.substring(lastColon + 1) : 'latest';
},
@@ -446,15 +510,17 @@ const Container = Model.base.extend({
text = constants.ICON.INIT_DISABLED;
}
return E('span', { class: `autostart-status autostart-${status || ''}` }, text);
return E('span', {
class: `autostart-status autostart-${status || ''}`
}, text);
},
isRunning() {
const state = this.getState();
return this.State?.Running
|| state === 'running'
|| state === 'starting'
|| state === 'unhealthy';
return this.State?.Running ||
state === 'running' ||
state === 'starting' ||
state === 'unhealthy';
},
isStopped() {
@@ -530,7 +596,8 @@ const Container = Model.base.extend({
if (hasRestartPolicy && (initScriptStatus === 'none' || initScriptStatus === 'missing')) {
await this.generateInitScript();
await this.enableInitScript();
} else if (!hasRestartPolicy && (initScriptStatus === 'enabled' || initScriptStatus === 'disabled')) {
} else if (!hasRestartPolicy && (initScriptStatus === 'enabled' || initScriptStatus ===
'disabled')) {
await this.removeInitScript();
}
},
@@ -564,25 +631,39 @@ const Container = Model.base.extend({
},
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) {
return Network.getSingleton({ name: networkName }).disconnect({ Container: this.getID() });
return Network.getSingleton({
name: networkName
}).disconnect({
Container: this.getID()
});
},
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);
const url = L.url('admin/podman/stream/top', this.getID()) + '?' + params;
return this._stream(
() => url,
(data) => { if (!data.raw && !data.Error) onChunk(data); }
(data) => {
if (!data.raw && !data.Error) onChunk(data);
}
);
},
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;
return this._stream(
() => 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) {
// Historical fetch: single request, stop after completion (no reconnect)
let handle;
@@ -632,7 +718,9 @@ const Container = Model.base.extend({
return L.url('admin/podman/stream/logs', this.getID()) + '?' + params;
},
onChunk,
() => { reconnectSince = Date.now() / 1000; }
() => {
reconnectSince = Date.now() / 1000;
}
);
},
@@ -656,7 +744,9 @@ const Container = Model.base.extend({
const imageRef = image.getDisplayTag() || this.Image;
if (!imageRef || imageRef.startsWith('<none>'))
return { hasUpdate: false };
return {
hasUpdate: false
};
const localArch = image.Architecture || 'amd64';
const localOs = image.Os || 'linux';
@@ -666,7 +756,8 @@ const Container = Model.base.extend({
const remoteDigest = findArchDigest(manifest, localArch, localOs);
const repoDigests = image.RepoDigests || [];
const hasUpdate = !!(remoteDigest && !repoDigests.some(rd => rd.includes(remoteDigest)));
const hasUpdate = !!(remoteDigest && !repoDigests.some(rd => rd.includes(
remoteDigest)));
return {
hasUpdate,
@@ -727,37 +818,58 @@ const Container = Model.base.extend({
if (wasRunning) {
onProgress?.('→ ' + _('Stopping container') + '\n');
try { await this.stop(); }
catch (e) { throw new Error(_('Stop failed: %s').format(e.message || e)); }
try {
await this.stop();
} catch (e) {
throw new Error(_('Stop failed: %s').format(e.message || e));
}
}
onProgress?.('→ ' + _('Removing container') + '\n');
try { await this.remove(); }
catch (e) { throw new Error(_('Remove failed: %s').format(e.message || e)); }
try {
await this.remove();
} catch (e) {
throw new Error(_('Remove failed: %s').format(e.message || e));
}
onProgress?.('→ ' + _('Creating container') + '\n');
let created;
try { created = await ContainerRPC.create(spec); }
catch (e) { throw new Error(_('Create failed: %s').format(e.message || e)); }
try {
created = await ContainerRPC.create(spec);
} catch (e) {
throw new Error(_('Create failed: %s').format(e.message || e));
}
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) {
onProgress?.('→ ' + _('Starting container') + '\n');
try { await ContainerRPC.start(created.Id); }
catch (e) { throw new Error(_('Start failed: %s').format(e.message || e)); }
try {
await ContainerRPC.start(created.Id);
} catch (e) {
throw new Error(_('Start failed: %s').format(e.message || e));
}
}
onProgress?.('→ ' + _('Reinstating init script') + '\n');
try { await this._reinstateInitScript(initStatus); }
catch (e) { throw new Error(_('Init script reinstate failed: %s').format(e.message || e)); }
try {
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');
return { oldImage: image };
onProgress?.('✓ ' + _('Updated to %s').format((newImageId || '').substring(0, 12)) +
'\n');
return {
oldImage: image
};
},
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());
},
@@ -22,7 +22,6 @@
import { readfile, writefile, popen, stat, chmod, unlink, glob, access } from 'fs';
import { cursor } from 'uci';
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 { API_BASE } from 'luci.podman_socket'; // ucode-lsp disable
import {
@@ -33,6 +32,9 @@ import {
build_request, parse_status, parse_content_length, read_headers
} from 'luci.podman_http'; // ucode-lsp disable
import { connect } from 'ubus';
let ubus = connect();
// --- Configuration ---
const uci = cursor();
@@ -897,14 +899,17 @@ const methods = {
let err = require_param('name', req.args.name) || validate_name(req.args.name);
if (err) return { error: err };
let script_path = init_script_path(req.args.name);
let exists = !!stat(script_path);
let enabled = false;
if (exists)
enabled = init_enabled(`${INIT_SCRIPT_PREFIX}${req.args.name}`);
return { exists: exists, enabled: enabled };
let name = `${INIT_SCRIPT_PREFIX}${req.args.name}`;
return ubus.defer(
'rc', 'list', { name: name },
function (rc, reply) {
if (reply[name] == null) {
req.reply({ exists: false, enabled: false });
} else {
req.reply({ exists: true, enabled: reply[name].enabled });
}
}
);
}
},
@@ -918,12 +923,18 @@ const methods = {
if (!stat(script_path))
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 rc = init_action(`${INIT_SCRIPT_PREFIX}${req.args.name}`, action);
if (rc)
return { error: `Failed to ${action} service` };
return { success: true, enabled: (action === 'enable') };
return ubus.defer(
'rc', 'init', { name: name, action: action },
function (rc, reply) {
if (rc == 0) {
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' };
// Disable before removing
init_action(`${INIT_SCRIPT_PREFIX}${req.args.name}`, 'disable');
unlink(script_path);
if (stat(script_path))
return { error: 'Failed to remove init script' };
return { success: true };
let name = `${INIT_SCRIPT_PREFIX}${req.args.name}`;
return ubus.call(
'rc', 'init', { name: name, action: 'disable' },
function (rc, reply) {
if (rc == 0) {
unlink(script_path);
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))
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 null;
@@ -1404,7 +1405,9 @@ function getDisplaySignalPercent(radioNet, hwtype, is_assoc, disabled) {
}
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 radioNet.getSignal();
@@ -1437,7 +1440,7 @@ function renderStatusRow(pairs, className) {
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;
switch(true) {
@@ -1459,13 +1462,13 @@ function render_signal_badge(signalPercent, signalValue, noiseValue, wrap, mode)
}
else {
value = `${signalValue}\xa0${_('dBm')}`;
title = `${_('Signal')} ${signalValue} ${_('dBm')}`;
title = `${txpower ? _('Tx-Power') : _('Signal')} ${signalValue} ${_('dBm')}`;
}
}
else if (signalPercent > -1) {
switch (mode) {
case 'ap':
title = _('No client associated');
title = txpower ? _('Tx-Power') : _('No client associated');
break;
case 'sta':
@@ -1516,7 +1519,8 @@ function render_network_badge(radioNet) {
return render_signal_badge(
getDisplaySignalPercent(radioNet, hwtype, is_assoc, disabled),
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) {
@@ -1591,7 +1595,8 @@ function render_modal_status(node, radioNet) {
dom.content(node.firstElementChild, render_signal_badge(
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, [
_('Mode'), mode,
+2 -2
View File
@@ -14,8 +14,8 @@ MISE_HASH_x86_64:=3832f39c325e343f81fe3d92b2447c5d1a5eea1bc85092bb7b6c2580622264
MISE_HASH_aarch64:=06186cfbfe947049b21d58575fb0ea800cc26ed1375f20f4b678cb3a9d679437
PKG_NAME:=mise
PKG_VERSION:=2026.10.12
PKG_RELEASE:=36
PKG_VERSION:=2026.10.13
PKG_RELEASE:=37
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_HASH:=skip
+2 -2
View File
@@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=natflow
PKG_VERSION:=20260930
PKG_RELEASE:=94
PKG_RELEASE:=95
PKG_SOURCE:=$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=68cc4c87a23a1afbdb194bd3d3f9bb64d767f6ba
PKG_SOURCE_VERSION:=51496417511f8dc4ebef2618206db11ddedd7773
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com>
PKG_LICENSE:=GPL-2.0
+3 -3
View File
@@ -50,12 +50,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=wwand
PKG_VERSION:=1.7.0_pre33
PKG_RELEASE:=79
PKG_VERSION:=1.8.0_pre3
PKG_RELEASE:=80
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/ddimension/wwand.git
PKG_SOURCE_VERSION:=5281731de7f5465552a9bba1b909b082b3050fae
PKG_SOURCE_VERSION:=8a170a136d1e1340ef54da2006edc8b622a87e43
PKG_MIRROR_HASH:=skip
PKG_LICENSE:=GPL-2.0-only
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=Xray-core
PKG_VERSION:=26.10.10
PKG_RELEASE:=25
PKG_VERSION:=26.10.17
PKG_RELEASE:=26
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/XTLS/Xray-core/tar.gz/v$(PKG_VERSION)?