Compare commits

..

No commits in common. "cbbb978e5031008f3b39fe17a6ca6b116bc30c5a" and "296c6ddff1ff78e11afb140908eb6a0a74ea4644" have entirely different histories.

3 changed files with 5 additions and 49 deletions

View File

@ -977,20 +977,14 @@ class AppsManager {
const passKeys = Object.keys(cfg).filter(k => loginKey('PASSWORD').test(k));
const emailVal = emailKeys[0] ? cfg[emailKeys[0]] : '';
const userVal = userKeys[0] ? cfg[userKeys[0]] : '';
// Only claim a username when the app actually declares one. This used to
// fall back to the literal 'admin', which invented a login name for
// password-only apps — speedtest has a single CFG_SPEEDTEST_PASSWORD_1 and
// no user concept at all, yet its card advertised "User: admin".
// eoCredList omits any row whose value is null, so passing undefined for
// either half renders just the half that exists.
const identifier = emailVal || userVal;
const userLabel = (emailVal || identifier.includes('@')) ? 'Email' : 'User';
const identifier = emailVal || userVal || 'admin';
const userLabel = (emailVal || (typeof identifier === 'string' && identifier.includes('@'))) ? 'Email' : 'User';
if (userKeys[0] || emailKeys[0] || passKeys[0]) {
creds.push({
title: `${app.name.split(' - ')[0]} Login`,
username: identifier || undefined,
username: identifier,
userLabel,
password: passKeys[0] ? (cfg[passKeys[0]] || '(not generated)') : undefined
password: cfg[passKeys[0]] || '(not generated)'
});
}

View File

@ -117,22 +117,6 @@
background: rgba(var(--text-rgb), .03);
border-color: rgba(var(--text-rgb), .08);
}
/* Rows whose action is just "go to that tab" are clickable end to end the
button inside remains the affordance (and the focusable control), the row
only widens the target. Hover lifts the whole row AND the button together so
it reads as one control, not a row that happens to sit under the cursor. */
.ov-board-row.ov-clickable { cursor: pointer; transition: background .12s ease, border-color .12s ease; }
.ov-board-row.ov-clickable:hover {
background: rgba(var(--page-rgb, var(--accent-rgb)), .11);
border-color: rgba(var(--page-rgb, var(--accent-rgb)), .28);
}
.ov-board-row.ov-clickable.ok:hover,
.ov-board-row.ov-clickable.none:hover {
background: rgba(var(--text-rgb), .06);
border-color: rgba(var(--text-rgb), .14);
}
/* Keep the button's own hover styling from reading as "only this bit is live". */
.ov-board-row.ov-clickable:hover .ov-board-actions .updater-btn { filter: brightness(1.08); }
.ov-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.ov-dot.ok { background: #36d399; }
.ov-dot.warn { background: #fbbd23; }

View File

@ -316,13 +316,6 @@ class OverviewManager {
if (oa) {
switch (oa.dataset.overviewAction) {
case 'goto':
// Whole-row navigation is a convenience over the row's own button —
// don't fire it when the click was really the end of a text drag
// inside the row. (Clicks on the button itself always count.)
if (oa.classList.contains('ov-board-row')) {
const sel = window.getSelection && window.getSelection();
if (sel && !sel.isCollapsed && String(sel).trim()) break;
}
// Board rows can land on Updates pre-filtered (e.g. Security → the
// affected apps only), so honor an optional data-filter on the way.
if (oa.dataset.filter) this.filter = oa.dataset.filter;
@ -432,7 +425,6 @@ class OverviewManager {
text: `${waiting.length} update${waiting.length === 1 ? '' : 's'} waiting for you`,
sub: `${esc(listOf(waiting))} — a recovery snapshot is taken before each update`
+ (selfing ? ` · ${selfing} more will install automatically` : ''),
nav: { tab: 'updates', filter: 'updates' },
actions: goto('updates', 'Review', 'updates')
+ `<button class="updater-btn updater-btn-primary" data-updater-action="update-all">Update all</button>`,
});
@ -446,7 +438,6 @@ class OverviewManager {
hue: 'updates', icon: '⬆️', kind: 'ok',
text: `${pending.length} update${pending.length === 1 ? '' : 's'} installing automatically${winBit}`,
sub: `${esc(listOf(pending))} — each is snapshotted first, and rolled back if it fails`,
nav: { tab: 'updates', filter: 'updates' },
actions: goto('updates', 'Review', 'updates'),
});
}
@ -478,7 +469,6 @@ class OverviewManager {
text: `${u.totalCves} known CVE${u.totalCves === 1 ? '' : 's'} across ${hit} app${hit === 1 ? '' : 's'}`,
badge: worst ? ` <span class="updater-badge sev-${worst}">${worst}</span>` : '',
sub: order.filter((s) => sev[s]).map((s) => `${sev[s]} ${s}`).join(' · '),
nav: { tab: 'updates', filter: 'security' },
actions: goto('updates', 'Review', 'security'),
});
} else {
@ -492,7 +482,6 @@ class OverviewManager {
hue: 'updater', icon: '✨', kind: 'warn',
text: `${u.improvements} signed improvement${u.improvements === 1 ? '' : 's'} ready to apply`,
sub: 'individually reversible — a snapshot is taken first',
nav: { tab: 'improvements' },
actions: goto('improvements', 'View'),
});
} else {
@ -508,7 +497,6 @@ class OverviewManager {
hue: 'backups', icon: '💾', kind: 'warn',
text: 'No backup location configured',
sub: 'apps cant be protected until theres somewhere to back them up to',
nav: { tab: 'backups' },
actions: goto('backups', 'Open Backups'),
});
} else if (b.never + b.old) {
@ -517,7 +505,6 @@ class OverviewManager {
hue: 'backups', icon: '💾', kind: 'warn',
text: `${n} app${n === 1 ? '' : 's'} need${n === 1 ? 's' : ''} a fresh backup`,
sub: [b.never && `${b.never} never backed up`, b.old && `${b.old} older than a week`].filter(Boolean).join(' · '),
nav: { tab: 'backups' },
actions: goto('backups', 'Open Backups'),
});
} else {
@ -529,17 +516,8 @@ class OverviewManager {
return rows;
}
// A row whose action is a plain "go to that tab" (Review / View / Open
// Backups) makes the WHOLE row a hit target for it — the button stays put as
// the visible affordance and the only focusable control, so the row is a
// mouse convenience layered on top rather than a nested role="button" (which
// would swallow the buttons it contains). Rows that only carry a real
// operation (Update all) or no action at all stay inert.
boardRow(r) {
const nav = r.nav
? ` data-overview-action="goto" data-tab="${r.nav.tab}"${r.nav.filter ? ` data-filter="${r.nav.filter}"` : ''}`
: '';
return `<div class="ov-board-row ${r.kind}${r.nav ? ' ov-clickable' : ''}"${nav} style="--page: var(--page-${r.hue}); --page-rgb: var(--page-${r.hue}-rgb);">
return `<div class="ov-board-row ${r.kind}" style="--page: var(--page-${r.hue}); --page-rgb: var(--page-${r.hue}-rgb);">
<span class="ov-dot ${r.kind}" aria-hidden="true"></span>
<span class="ov-board-icon" aria-hidden="true">${r.icon}</span>
<div class="ov-board-main">