Compare commits
No commits in common. "cbbb978e5031008f3b39fe17a6ca6b116bc30c5a" and "296c6ddff1ff78e11afb140908eb6a0a74ea4644" have entirely different histories.
cbbb978e50
...
296c6ddff1
@ -977,20 +977,14 @@ class AppsManager {
|
|||||||
const passKeys = Object.keys(cfg).filter(k => loginKey('PASSWORD').test(k));
|
const passKeys = Object.keys(cfg).filter(k => loginKey('PASSWORD').test(k));
|
||||||
const emailVal = emailKeys[0] ? cfg[emailKeys[0]] : '';
|
const emailVal = emailKeys[0] ? cfg[emailKeys[0]] : '';
|
||||||
const userVal = userKeys[0] ? cfg[userKeys[0]] : '';
|
const userVal = userKeys[0] ? cfg[userKeys[0]] : '';
|
||||||
// Only claim a username when the app actually declares one. This used to
|
const identifier = emailVal || userVal || 'admin';
|
||||||
// fall back to the literal 'admin', which invented a login name for
|
const userLabel = (emailVal || (typeof identifier === 'string' && identifier.includes('@'))) ? 'Email' : 'User';
|
||||||
// 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';
|
|
||||||
if (userKeys[0] || emailKeys[0] || passKeys[0]) {
|
if (userKeys[0] || emailKeys[0] || passKeys[0]) {
|
||||||
creds.push({
|
creds.push({
|
||||||
title: `${app.name.split(' - ')[0]} Login`,
|
title: `${app.name.split(' - ')[0]} Login`,
|
||||||
username: identifier || undefined,
|
username: identifier,
|
||||||
userLabel,
|
userLabel,
|
||||||
password: passKeys[0] ? (cfg[passKeys[0]] || '(not generated)') : undefined
|
password: cfg[passKeys[0]] || '(not generated)'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -117,22 +117,6 @@
|
|||||||
background: rgba(var(--text-rgb), .03);
|
background: rgba(var(--text-rgb), .03);
|
||||||
border-color: rgba(var(--text-rgb), .08);
|
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 { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
|
||||||
.ov-dot.ok { background: #36d399; }
|
.ov-dot.ok { background: #36d399; }
|
||||||
.ov-dot.warn { background: #fbbd23; }
|
.ov-dot.warn { background: #fbbd23; }
|
||||||
|
|||||||
@ -316,13 +316,6 @@ class OverviewManager {
|
|||||||
if (oa) {
|
if (oa) {
|
||||||
switch (oa.dataset.overviewAction) {
|
switch (oa.dataset.overviewAction) {
|
||||||
case 'goto':
|
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
|
// Board rows can land on Updates pre-filtered (e.g. Security → the
|
||||||
// affected apps only), so honor an optional data-filter on the way.
|
// affected apps only), so honor an optional data-filter on the way.
|
||||||
if (oa.dataset.filter) this.filter = oa.dataset.filter;
|
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`,
|
text: `${waiting.length} update${waiting.length === 1 ? '' : 's'} waiting for you`,
|
||||||
sub: `${esc(listOf(waiting))} — a recovery snapshot is taken before each update`
|
sub: `${esc(listOf(waiting))} — a recovery snapshot is taken before each update`
|
||||||
+ (selfing ? ` · ${selfing} more will install automatically` : ''),
|
+ (selfing ? ` · ${selfing} more will install automatically` : ''),
|
||||||
nav: { tab: 'updates', filter: 'updates' },
|
|
||||||
actions: goto('updates', 'Review', 'updates')
|
actions: goto('updates', 'Review', 'updates')
|
||||||
+ `<button class="updater-btn updater-btn-primary" data-updater-action="update-all">Update all</button>`,
|
+ `<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',
|
hue: 'updates', icon: '⬆️', kind: 'ok',
|
||||||
text: `${pending.length} update${pending.length === 1 ? '' : 's'} installing automatically${winBit}`,
|
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`,
|
sub: `${esc(listOf(pending))} — each is snapshotted first, and rolled back if it fails`,
|
||||||
nav: { tab: 'updates', filter: 'updates' },
|
|
||||||
actions: goto('updates', 'Review', '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'}`,
|
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>` : '',
|
badge: worst ? ` <span class="updater-badge sev-${worst}">${worst}</span>` : '',
|
||||||
sub: order.filter((s) => sev[s]).map((s) => `${sev[s]} ${s}`).join(' · '),
|
sub: order.filter((s) => sev[s]).map((s) => `${sev[s]} ${s}`).join(' · '),
|
||||||
nav: { tab: 'updates', filter: 'security' },
|
|
||||||
actions: goto('updates', 'Review', 'security'),
|
actions: goto('updates', 'Review', 'security'),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -492,7 +482,6 @@ class OverviewManager {
|
|||||||
hue: 'updater', icon: '✨', kind: 'warn',
|
hue: 'updater', icon: '✨', kind: 'warn',
|
||||||
text: `${u.improvements} signed improvement${u.improvements === 1 ? '' : 's'} ready to apply`,
|
text: `${u.improvements} signed improvement${u.improvements === 1 ? '' : 's'} ready to apply`,
|
||||||
sub: 'individually reversible — a snapshot is taken first',
|
sub: 'individually reversible — a snapshot is taken first',
|
||||||
nav: { tab: 'improvements' },
|
|
||||||
actions: goto('improvements', 'View'),
|
actions: goto('improvements', 'View'),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -508,7 +497,6 @@ class OverviewManager {
|
|||||||
hue: 'backups', icon: '💾', kind: 'warn',
|
hue: 'backups', icon: '💾', kind: 'warn',
|
||||||
text: 'No backup location configured',
|
text: 'No backup location configured',
|
||||||
sub: 'apps can’t be protected until there’s somewhere to back them up to',
|
sub: 'apps can’t be protected until there’s somewhere to back them up to',
|
||||||
nav: { tab: 'backups' },
|
|
||||||
actions: goto('backups', 'Open Backups'),
|
actions: goto('backups', 'Open Backups'),
|
||||||
});
|
});
|
||||||
} else if (b.never + b.old) {
|
} else if (b.never + b.old) {
|
||||||
@ -517,7 +505,6 @@ class OverviewManager {
|
|||||||
hue: 'backups', icon: '💾', kind: 'warn',
|
hue: 'backups', icon: '💾', kind: 'warn',
|
||||||
text: `${n} app${n === 1 ? '' : 's'} need${n === 1 ? 's' : ''} a fresh backup`,
|
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(' · '),
|
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'),
|
actions: goto('backups', 'Open Backups'),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -529,17 +516,8 @@ class OverviewManager {
|
|||||||
return rows;
|
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) {
|
boardRow(r) {
|
||||||
const nav = r.nav
|
return `<div class="ov-board-row ${r.kind}" style="--page: var(--page-${r.hue}); --page-rgb: var(--page-${r.hue}-rgb);">
|
||||||
? ` 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);">
|
|
||||||
<span class="ov-dot ${r.kind}" aria-hidden="true"></span>
|
<span class="ov-dot ${r.kind}" aria-hidden="true"></span>
|
||||||
<span class="ov-board-icon" aria-hidden="true">${r.icon}</span>
|
<span class="ov-board-icon" aria-hidden="true">${r.icon}</span>
|
||||||
<div class="ov-board-main">
|
<div class="ov-board-main">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user