Sync 2026-06-13 08:49:35

This commit is contained in:
github-actions[bot] 2026-06-13 08:49:35 +08:00
parent 6956ac30a6
commit a2112fa32e
11 changed files with 97 additions and 40 deletions

View File

@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-daede
PKG_VERSION:=1.10
PKG_RELEASE:=3
PKG_VERSION:=1.10.3
PKG_RELEASE:=4
PKG_MAINTAINER:=kenzok8
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)

View File

@ -19,6 +19,16 @@ return view.extend({
},
render: function(ctx) {
/* themes signal dark differently BootstrapDark sets data-darkmode,
Argon just loads a dark stylesheet with no flag. Detect dark from the
page background luminance and set data-darkmode so our dark rules
(keyed on it) fire uniformly across every theme's dark mode. */
try {
const bg = getComputedStyle(document.body).backgroundColor.match(/\d+/g);
if (bg && (0.299 * bg[0] + 0.587 * bg[1] + 0.114 * bg[2]) < 128)
document.documentElement.setAttribute('data-darkmode', 'true');
} catch (e) {}
const listenAddr = uci.get('daed', 'config', 'listen_addr') || backend.BACKENDS.daed.defaultListen;
const children = [
E('style', {}, styles.CSS),

View File

@ -110,7 +110,9 @@ const GEN = '/usr/share/luci-app-daede/gen-dae-config.sh';
stays visible in the edit dialog and on hover. */
function ellipsisCell(section_id) {
const v = this.cfgvalue(section_id) || '';
const short = v.length > 52 ? v.slice(0, 52) + '…' : v;
/* middle-ellipsis keeps the host head + tail visible (the meaningful parts
of a sub link) while staying short enough for one line on a phone */
const short = v.length > 30 ? v.slice(0, 18) + '…' + v.slice(-9) : v;
return E('span', { 'title': v, 'style': 'font-family:ui-monospace,Menlo,monospace;font-size:12px' }, short);
}
@ -224,7 +226,16 @@ function renderDaeForms(ctx) {
s.anonymous = true;
o = s.option(form.Value, 'name', _('Name'));
o.rmempty = false;
o.default = 'proxy'; /* real default value, editable — a bright placeholder looked filled and tripped the required check */
o.placeholder = 'proxy';
o.validate = function(sid, v) {
if (!v) return _('Name is required');
/* dae fatals on duplicate outbound names — keep group names unique */
const dup = (uci.sections('dae', 'group') || []).some(function(g) {
return g['.name'] !== sid && g.name === v;
});
return dup ? _('Group name must be unique') : true;
};
o = s.option(form.ListValue, 'policy', _('Policy'));
o.value('min_moving_avg', _('Min moving average latency'));
o.value('min', _('Min last latency'));
@ -256,6 +267,7 @@ function renderDaeForms(ctx) {
o.default = '0';
o = s.option(form.Value, 'fallback', _('Fallback group'),
_('Default outbound for everything else.'));
o.default = 'proxy'; /* matches the default proxy group so the box works out of the box */
if (groupNames.length)
groupNames.forEach(function(n) { o.value(n, n); });
else
@ -476,7 +488,10 @@ function renderDaeImportBanner() {
if (hasForms)
return Promise.resolve(null);
return fs.read_direct(backend.BACKENDS.dae.config, 'text').then(function(content) {
/* stat first (ubus): avoid a 404 when config.dae doesn't exist yet */
return fs.stat(backend.BACKENDS.dae.config).then(function() {
return fs.read_direct(backend.BACKENDS.dae.config, 'text');
}).then(function(content) {
if (!content || !/\b(subscription|node)\s*\{/.test(content))
return null;
@ -650,7 +665,11 @@ function renderDaeEditor() {
textarea.addEventListener('input', refreshPlaceholders);
function loadConfig() {
return fs.read_direct(backend.BACKENDS.dae.config, 'text').then(function(content) {
/* stat first (ubus, no HTTP): a fresh install has no config.dae yet, and
reading a missing file via fs.read_direct logs a noisy 404 */
return fs.stat(backend.BACKENDS.dae.config).then(function() {
return fs.read_direct(backend.BACKENDS.dae.config, 'text');
}).then(function(content) {
textarea.value = content || '';
}).catch(function() {
textarea.value = '';

View File

@ -69,9 +69,11 @@ const CSS = [
as an off-colour band on the white card keep it transparent */
'.dd-settings-card .cbi-section-table-titles,.dd-settings-card .cbi-section-table-titles .cbi-section-table-cell{background:transparent !important;background-image:none !important}',
'.dd-settings-card .cbi-section-table-cell:nth-child(1){width:14% !important}',
'.dd-settings-card .cbi-section-table-cell:nth-child(2){width:50% !important;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
'.dd-settings-card .cbi-section-table-cell:nth-child(3){width:12% !important}',
'.dd-settings-card .cbi-section-table-cell:nth-child(4){width:24% !important;min-width:210px}',
'.dd-settings-card .cbi-section-table-cell:nth-child(2){width:62% !important;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
'.dd-settings-card .cbi-section-table-cell:nth-child(3){width:10% !important}',
'.dd-settings-card .cbi-section-table-cell:nth-child(4){width:auto !important;min-width:0 !important;white-space:nowrap;text-align:right}',
/* icon row-action buttons stay narrow, never stretch to fill the cell */
'.dd-settings-card .cbi-section-actions .cbi-button-edit,.dd-settings-card .cbi-section-actions .cbi-button-remove{width:auto !important;min-width:0 !important;display:inline-block !important;flex:0 0 auto !important}',
/* proxy-test result coloring */
'.dd-meta.dd-ok{color:#3da66a;font-weight:600}',
'.dd-meta.dd-err{color:#d96d6d;font-weight:600}',
@ -89,9 +91,9 @@ const CSS = [
real editor (caret, selection, insert-at-cursor, jump-to-line all native) */
'.dd-edit-wrap{position:relative}',
'.dd-edit-wrap .dd-editor,.dd-edit-wrap .dd-hl{margin:0;padding:10px 12px;border-width:1px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;font-size:12px;line-height:1.5;letter-spacing:0;tab-size:4;white-space:pre-wrap;word-break:break-word;box-sizing:border-box}',
'.dd-edit-wrap .dd-hl{position:absolute;inset:0;margin:0;overflow:hidden;border:1px solid transparent;border-radius:6px 6px 0 0;pointer-events:none;background:transparent;color:#3b4252;z-index:1}',
'.dd-edit-wrap .dd-hl{position:absolute;inset:0;margin:0;overflow:hidden;border:1px solid transparent;border-radius:6px 6px 0 0;pointer-events:none;background:#f6f8fa;color:#3b4252;z-index:1}',
'.dd-edit-wrap .dd-hl code{font:inherit;white-space:inherit;word-break:inherit;display:block}',
'.dd-edit-wrap .dd-editor-hl{position:relative;z-index:2;color:transparent;background:transparent;caret-color:#2f7288;border:1px solid rgba(128,128,128,.28)}',
'.dd-edit-wrap .dd-editor-hl{position:relative;z-index:2;color:transparent !important;background:transparent !important;caret-color:#2f7288;border:1px solid rgba(128,128,128,.28)}',
'.dd-edit-wrap .dd-editor-hl::placeholder{color:rgba(128,128,128,.55)}',
'.dd-edit-wrap .dd-editor-hl::selection{background:rgba(56,134,161,.25)}',
'.dh-c{color:#8a919a;font-style:italic}',
@ -100,7 +102,7 @@ const CSS = [
'.dh-f{color:#2f7288}',
'.dh-o{color:#c2772a}',
'.dh-g{color:#b0226a}',
'html[data-darkmode="true"] .dd-edit-wrap .dd-hl,body.dark .dd-edit-wrap .dd-hl,html[data-bs-theme="dark"] .dd-edit-wrap .dd-hl{color:#c8cdd6}',
'html[data-darkmode="true"] .dd-edit-wrap .dd-hl,body.dark .dd-edit-wrap .dd-hl,html[data-bs-theme="dark"] .dd-edit-wrap .dd-hl{color:#c8cdd6;background:#1e2228}',
'html[data-darkmode="true"] .dd-edit-wrap .dd-editor-hl,body.dark .dd-edit-wrap .dd-editor-hl,html[data-bs-theme="dark"] .dd-edit-wrap .dd-editor-hl{caret-color:#7fd0e8}',
'html[data-darkmode="true"] .dh-c,body.dark .dh-c{color:#6b7280}',
'html[data-darkmode="true"] .dh-s,body.dark .dh-s{color:#7ec699}',
@ -150,15 +152,32 @@ const CSS = [
'body.dark .dd-card,html[data-theme="dark"] .dd-card,html[data-bs-theme="dark"] .dd-card,html[data-darkmode="true"] .dd-card{border-color:rgba(255,255,255,.08);background:rgba(255,255,255,.02)}',
'body.dark .dd-adv-bar,html[data-theme="dark"] .dd-adv-bar,html[data-bs-theme="dark"] .dd-adv-bar,html[data-darkmode="true"] .dd-adv-bar{background:rgba(255,255,255,.04);border-color:rgba(255,255,255,.10)}',
'body.dark .dd-settings-card .cbi-value-field input,body.dark .dd-settings-card .cbi-value-field select,body.dark .dd-settings-card .cbi-value-field textarea,html[data-theme="dark"] .dd-settings-card .cbi-value-field input,html[data-theme="dark"] .dd-settings-card .cbi-value-field select,html[data-theme="dark"] .dd-settings-card .cbi-value-field textarea,html[data-bs-theme="dark"] .dd-settings-card .cbi-value-field input,html[data-bs-theme="dark"] .dd-settings-card .cbi-value-field select,html[data-bs-theme="dark"] .dd-settings-card .cbi-value-field textarea,html[data-darkmode="true"] .dd-settings-card .cbi-value-field input,html[data-darkmode="true"] .dd-settings-card .cbi-value-field select,html[data-darkmode="true"] .dd-settings-card .cbi-value-field textarea{border-color:rgba(255,255,255,.18)}',
/* phone: render each subscription/node row as a self-contained card instead
of a cramped table (LuCI already block-stacks the cells; we add the card
frame, drop the desktop column widths, and shrink the action buttons) */
/* status card line-2 meta (backend · pid), below the badge+toggle line */
'.dd-status-meta{display:flex;flex-wrap:wrap;gap:10px;margin-top:6px}',
/* compact icon-only row actions the / text buttons are too wide
(esp. Bootstrap); show a pencil / trash glyph instead, both themes */
'.dd-settings-card .cbi-section-actions .cbi-button-edit,.dd-settings-card .cbi-section-actions .cbi-button-remove{font-size:0 !important;padding:4px 7px !important;min-width:0 !important}',
'.dd-settings-card .cbi-section-actions .cbi-button-edit::before{content:"\\270E";font-size:13px;line-height:1}',
'.dd-settings-card .cbi-section-actions .cbi-button-remove::before{content:"\\1F5D1\\FE0E";font-size:13px;line-height:1}',
/* phone: keep each subscription/node row on ONE line; the URL cell
middle-ellipsizes (via ellipsisCell) and flex-shrinks to fit the screen */
'@media (max-width:600px){',
'.dd-settings-card .cbi-section-table-cell:nth-child(1),.dd-settings-card .cbi-section-table-cell:nth-child(2),.dd-settings-card .cbi-section-table-cell:nth-child(3),.dd-settings-card .cbi-section-table-cell:nth-child(4){width:auto !important;min-width:0 !important;white-space:normal !important;overflow:visible !important;text-overflow:clip !important}',
'.dd-settings-card .cbi-section-table-row{display:block;border:1px solid rgba(128,128,128,.2);border-radius:8px;padding:6px 10px;margin:0 0 8px;background:rgba(128,128,128,.03)}',
'.dd-settings-card .cbi-section-table-cell{display:block;padding:3px 0 !important}',
'.dd-settings-card .cbi-section-actions{display:flex;flex-wrap:wrap;gap:6px;padding-top:6px !important}',
'.dd-settings-card .cbi-section-actions .cbi-button{width:auto;margin:0;flex:0 0 auto}',
'.dd-settings-card .cbi-section-table-titles{display:none !important}',
/* drop table layout so flex rows are constrained to the card width and the
URL cell can actually shrink (a flex <tr> inside table-layout:fixed grows
past the table and overflows the screen on narrow/Argon) */
'.dd-settings-card .cbi-section-table{display:block !important;table-layout:auto !important;width:auto !important;overflow:visible !important}',
'.dd-settings-card .cbi-section-table>tbody,.dd-settings-card .cbi-section-table>div{display:block !important;width:auto !important}',
'.dd-settings-card .cbi-section-table-row{display:flex !important;flex-wrap:nowrap !important;width:auto !important;align-items:center;gap:6px;padding:5px 0;margin:0;border:0;border-bottom:1px solid rgba(128,128,128,.15);background:transparent}',
/* target the real cells (td.cbi-value-field / actions) LuCI forces them
block+full-width at mobile, so override on the direct children */
'.dd-settings-card .cbi-section-table-row>td{display:inline-block !important;align-self:center !important;width:auto !important;padding:0 !important;border:0 !important;background:transparent !important;box-shadow:none !important;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0 !important}',
'.dd-settings-card .cbi-section-table-row>td::before{content:none !important;display:none !important}',
'.dd-settings-card .cbi-section-table-row>td input{vertical-align:middle !important;margin:0 !important}',
'.dd-settings-card .cbi-section-table-row>td:nth-child(1){flex:0 0 auto !important;max-width:60px;opacity:.6;font-size:11px}',
'.dd-settings-card .cbi-section-table-row>td:nth-child(2){flex:1 1 auto !important}',
'.dd-settings-card .cbi-section-table-row>td:nth-child(3){flex:0 0 auto !important;text-align:center}',
'.dd-settings-card .cbi-section-table-row>td.cbi-section-actions{flex:0 0 auto !important;display:flex;gap:4px}',
'}'
].join('');

View File

@ -140,8 +140,6 @@ function renderStatusCard(ctx, listenAddr) {
if (state.running && state.pid)
meta.push(E('span', { 'class': 'dd-meta' }, [ E('span', { 'class': 'dd-meta-label' }, 'PID'), state.pid ]));
if (be.hasWebUI)
meta.push(E('span', { 'class': 'dd-meta' }, [ E('span', { 'class': 'dd-meta-label' }, _('Listen')), listenAddr || be.defaultListen ]));
const swErr = E('span', { 'class': 'dd-meta dd-err', 'style': 'display:none' }, '');
const sw = E('button', { 'class': 'dd-switch' + (state.running ? ' is-on' : ''), 'type': 'button', 'aria-label': _('Toggle service') }, [
@ -173,15 +171,19 @@ function renderStatusCard(ctx, listenAddr) {
.finally(function() { sw.disabled = false; });
});
const row = E('div', { 'class': 'dd-status-row' }, [ badge ].concat(meta).concat([
/* line 1: badge + toggle (always aligned, never wraps); line 2: meta */
const row = E('div', { 'class': 'dd-status-row' }, [
badge,
E('span', { 'class': 'dd-grow' }),
swErr,
E('span', { 'class': 'dd-switch-wrap' }, [
E('span', { 'class': 'dd-switch-label' }, state.running ? 'ON' : 'OFF'),
sw
])
]));
]);
body.appendChild(row);
if (meta.length)
body.appendChild(E('div', { 'class': 'dd-status-meta' }, meta));
const actions = [];
if (be.hasWebUI && state.running) {

View File

@ -89,6 +89,9 @@ emit_group() {
config_get policy "$s" policy "min_moving_avg"
name="$(sanitize "$name")"
[ -n "$name" ] || return 0
# dae fatals on duplicate outbound names; keep the first, skip later dupes
case " $GROUP_NAMES_SEEN " in *" $name "*) return 0 ;; esac
GROUP_NAMES_SEEN="$GROUP_NAMES_SEEN $name"
[ -n "$FIRST_GROUP" ] || FIRST_GROUP="$name"
GROUP_BUF="${GROUP_BUF} ${name} {
@ -191,7 +194,7 @@ generate() {
config_get wan_interface config wan_interface "auto"
config_get lan_interface config lan_interface ""
SUB_BUF=""; NODE_BUF=""; GROUP_BUF=""; FIRST_GROUP=""
SUB_BUF=""; NODE_BUF=""; GROUP_BUF=""; FIRST_GROUP=""; GROUP_NAMES_SEEN=""
SUB_TAGS=""
config_foreach collect_subtag subscription
config_foreach emit_sub subscription

View File

@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-gecoosac
PKG_VERSION:=2.2
PKG_RELEASE:=7
PKG_RELEASE:=8
LUCI_TITLE:=LuCI Support for gecoosac
LUCI_DEPENDS:=+luci-compat +gecoosac

View File

@ -32,7 +32,7 @@ function act_status()
local enabled = cur:get("gecoosac", "config", "enabled") == "1"
local e = {
enabled = enabled,
running = service_running()
running = enabled and service_running()
}
luci.http.prepare_content("application/json")
luci.http.write_json(e)

View File

@ -1,5 +1,5 @@
#
# Copyright (C) 2025 gSpot (https://github.com/gSpotx2f/luci-app-log)
# Copyright (C) 2026 gSpot (https://github.com/gSpotx2f/luci-app-log)
#
# This is free software, licensed under the MIT License.
#
@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-log-viewer
PKG_VERSION:=1.5.0
PKG_RELEASE:=1
PKG_RELEASE:=2
LUCI_TITLE:=Advanced syslog and kernel log (tail, search, etc)
LUCI_DEPENDS:=+ucode +ucode-mod-fs
LUCI_PKGARCH:=all

View File

@ -11,29 +11,29 @@ Supported LuCI themes: luci-theme-bootstrap, luci-theme-material, luci-theme-ope
**OpenWrt >= 25.12:**
wget --no-check-certificate -O /tmp/luci-app-log-viewer-1.5.0-r2.apk https://github.com/gSpotx2f/packages-openwrt/raw/master/25.12/luci-app-log-viewer-1.5.0-r2.apk
apk --allow-untrusted add /tmp/luci-app-log-viewer-1.5.0-r2.apk
rm /tmp/luci-app-log-viewer-1.5.0-r2.apk
wget --no-check-certificate -O /tmp/luci-app-log-viewer-1.5.0-r3.apk https://github.com/gSpotx2f/packages-openwrt/raw/master/25.12/luci-app-log-viewer-1.5.0-r3.apk
apk --allow-untrusted add /tmp/luci-app-log-viewer-1.5.0-r3.apk
rm /tmp/luci-app-log-viewer-1.5.0-r3.apk
service rpcd restart
i18n-ru:
wget --no-check-certificate -O /tmp/luci-i18n-log-viewer-ru-1.5.0-r2.apk https://github.com/gSpotx2f/packages-openwrt/raw/master/25.12/luci-i18n-log-viewer-ru-1.5.0-r2.apk
apk --allow-untrusted add /tmp/luci-i18n-log-viewer-ru-1.5.0-r2.apk
rm /tmp/luci-i18n-log-viewer-ru-1.5.0-r2.apk
wget --no-check-certificate -O /tmp/luci-i18n-log-viewer-ru-1.5.0-r3.apk https://github.com/gSpotx2f/packages-openwrt/raw/master/25.12/luci-i18n-log-viewer-ru-1.5.0-r3.apk
apk --allow-untrusted add /tmp/luci-i18n-log-viewer-ru-1.5.0-r3.apk
rm /tmp/luci-i18n-log-viewer-ru-1.5.0-r3.apk
**OpenWrt <= 24.10:**
wget --no-check-certificate -O /tmp/luci-app-log-viewer_1.5.0-r2_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/24.10/luci-app-log-viewer_1.5.0-r2_all.ipk
opkg install /tmp/luci-app-log-viewer_1.5.0-r2_all.ipk
rm /tmp/luci-app-log-viewer_1.5.0-r2_all.ipk
wget --no-check-certificate -O /tmp/luci-app-log-viewer_1.5.0-r3_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/24.10/luci-app-log-viewer_1.5.0-r3_all.ipk
opkg install /tmp/luci-app-log-viewer_1.5.0-r3_all.ipk
rm /tmp/luci-app-log-viewer_1.5.0-r3_all.ipk
service rpcd restart
i18n-ru:
wget --no-check-certificate -O /tmp/luci-i18n-log-viewer-ru_1.5.0-r2_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/24.10/luci-i18n-log-viewer-ru_1.5.0-r2_all.ipk
opkg install /tmp/luci-i18n-log-viewer-ru_1.5.0-r2_all.ipk
rm /tmp/luci-i18n-log-viewer-ru_1.5.0-r2_all.ipk
wget --no-check-certificate -O /tmp/luci-i18n-log-viewer-ru_1.5.0-r3_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/24.10/luci-i18n-log-viewer-ru_1.5.0-r3_all.ipk
opkg install /tmp/luci-i18n-log-viewer-ru_1.5.0-r3_all.ipk
rm /tmp/luci-i18n-log-viewer-ru_1.5.0-r3_all.ipk
## Screenshots:

View File

@ -302,12 +302,15 @@ return baseclass.extend({
actionButtons : [],
htmlEntities(str) {
/*
return String(str).replace(
/&/g, '&#38;').replace(
/</g, '&#60;').replace(
/>/g, '&#62;').replace(
/"/g, '&#34;').replace(
/'/g, '&#39;');
*/
return str;
},
checkZeroValue(value) {
@ -721,6 +724,7 @@ return baseclass.extend({
if(!fPattern) {
return entriesArray;
};
fPattern = this.htmlEntities(fPattern);
return (this.msgFilterReValue) ?
this.setRegexpFilter(entriesArray, 5, fPattern) :
this.setStringFilter(entriesArray, 5, fPattern);