'No installed apps to track.' was terse and gave no next step. Point the user
to the App Center so the empty Updates tab is actionable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
'No hotfix data yet — the automatic scan fetches the signed improvements index
within a couple of minutes.' leaked jargon (hotfix data, signed index) onto the
interface. Replace with a short, plain 'Checking for improvements…' line.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
Empty-state 'no data yet' messages rendered at rgba(text, 0.55) (and one at
text-muted), which is hard to read on the dark recessed panels. Switch them to
the theme's --text-secondary muted token so they stay de-emphasized but legible.
Covers .updater-empty, .updater-detail-empty, .sys-detail-empty, .eo-modal-empty.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
The fleet Overview area (Overview/Updates/Improvements/Backups/Migrate) now
lives at /apps/overview* instead of /overview*, reflecting that it belongs to
App Center. The Backups tab is therefore /apps/overview/backups, and the old
standalone Backup Center page is removed entirely:
- apps feature owns /apps/overview* (covered by the existing /apps* route); its
mount() dispatches /apps/overview -> fleet Overview before the grid check.
- _legacyRedirect() rewrites old short URLs so bookmarks/links keep working and
the address bar shows the canonical path:
/overview[/tab] -> /apps/overview[/tab]
/backup[/sub] -> /apps/overview/backups[/sub]
/updater, /peers redirects retargeted to /apps/overview*
- Removed the standalone backup feature: components/backup/{index.js,feature.json},
its manifest entry, the /backup route registrations and the dead handleBackup().
The BackupPage classes stay — the Overview Backups tab embeds them.
- Repointed every backups/overview link: the admin dashboard's 'Open backup
center', the app-card 'Open backup center' button + snapshot-overflow link,
the sidebar Overview entry, the improvements deep-link, and the Migrate
'go to locations' deep-link.
Also drop the redundant inline Check button from the Security empty state
(same rationale as Improvements: the host auto-scan repopulates it and the
header carries a manual Check).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
The Improvements tab's empty state ('No hotfix data yet …') rendered an
inline 'Check now' button. It was redundant: the embedding Overview header
already carries a manual Check, and the host-side auto-scan repopulates the
signed improvements index on its own within a couple of minutes (the empty
message already says so). Remove the button so the empty state is just the
self-explanatory, automation-backed message.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
Replace the click-to-scan-only flow with a self-throttled auto-scan that
rides the existing task-processor idle poll (the same shape as the
network-drift check — no new daemon, unit, or endpoint):
- 'libreportal updater check auto' gates on the age of the generated
updates.json vs CFG_UPDATER_SCAN_INTERVAL (minutes, default 30,
0 disables); a fresh file makes the 60s tick a single stat() + return.
Manual checks and post-update rescans reset the clock for free, and a
missing file means the first scan runs ~a minute after install.
- Eligible signed hotfixes keep flowing through artifactApplyAuto, which
only enqueues ordinary tasks — mutations stay on the task path.
- Open updater surfaces (standalone /updater and the fleet Overview's
headless UpdaterPage) follow along with a 60s static-JSON re-read that
repaints only when a generated_at stamp changed; timer released via
dispose() on unmount, ticks skipped while hidden.
- Empty states now say the first scan happens automatically; Check now
stays as the immediate manual override.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
Every fleet Overview tab now follows the per-app detail tab idiom the
rest of the app uses: title + description on the left, action buttons
on the right, a divider underneath, and the body inside the recessed
dark container (.tasks-container recipe).
- renderHeader() gains an action slot; Check/Check now/Update all move
out of in-body toolbars into the header (Updates keeps its filter
chips in the body; the Apps-tracked stat card drops its duplicate
Check button; UpdaterPage.renderImprovements can skip its toolbar).
- String tabs wrap their body in .ov-tab-body — margin/padding 16px,
rgba(bg,.2) panel — mirroring backup/tasks/updater containers.
- The Backups tab's embedded nested strip (Dashboard/Backups/Locations/
Configuration) now sits on the same surface as every other tab strip:
added to the nebula sidebar-bg anchor rule (it was stuck on the
lighter --hover-bg) and its buttons use .main-tab-button type.
Signed-off-by: librelad <librelad@digitalangels.vip>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The per-app Updates tab rendered a bare version/badge bar + detail with no
title, no dividers and no recessed container — unlike the Config / Backups /
Tasks tabs.
- Add a .updater-title block (⬆️ Updates + description, Check/Update actions,
bottom-border divider) mirroring .backup-title.
- Wrap the body in a .updater-detail-container recessed dark panel (same recipe
as .backup-snapshots-container / .tasks-container).
- Separate the Version/Security/Recovery/History sections with divider lines
(scoped to the container; fleet row-details keep their gap-only spacing).
- renderAppDetail() gains an opt-in Version section so the version/badge reads
as a section in the panel; fleet rows omit it (the row head shows it already).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- HIGH: renderAppDetail gated the Roll back button on last_snapshot* fields no
generator emits, so it never rendered. Derive recoverability from update
history (updater_apply always snapshots first) so the affordance is reachable.
- MED: per-app Updates tab now repaints on update/rollback/check/hotfix task
completion (mirrors the backups card) instead of going stale until re-click.
- MED: in-page tab switches now sync spaClean.currentRoute, so the sidebar
Overview entry no longer no-ops after switching tabs.
- LOW: keyboard activation (Enter/Space) for the role=button expander heads,
backup tiles, and sidebar Overview entry.
- LOW: preserve ALL expanded Updates rows across a background repaint, not just
the single ?app= deep-link (split toggle into _openDetail/_closeDetail).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The fleet Overview area (Overview · Updates · Improvements · Backups) and the
backup center now live under App Center, so the standalone top-nav items are
redundant. Top nav is now Dashboard · App Center · Admin · Tasks.
- Remove the Backups and Updates anchors from topbar.html.
- Remove the nav{} blocks from updater/backup feature.json + manifest (so they
don't resurface when the nav kernel lands).
- Highlight App Center for /overview and /backup; drop the dead /updater branch.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a per-fleet Overview area inside the apps shell, reachable from a new
'Overview' entry pinned above the apps sidebar search. Selecting it renders a
top-tabbed view in the main pane — Overview · Updates · Improvements · Backups —
mirroring the per-app tabbed layout, with the apps sidebar persistent.
- TabController: generic root-scoped show/hide tab host (core/ui-state).
- OverviewManager: drives the 4 tabs. Reuses a headless UpdaterPage for all
update/CVE/improvement data + rendering (its renderX() are pure HTML
producers) and reads backup/dashboard.json directly for backup health.
- Overview tab: combined update + backup health cards.
- Updates tab: per-app expander table (CVEs/recovery/history inline via the new
UpdaterPage.renderAppDetail) + All/Updates/Security filter chips.
- Improvements tab: reuses the updater's signed-hotfix renderer.
- Backups tab: fleet backup-health tiles; actions deep-link per app.
- Additive only: /overview* routes on the apps feature; old /updater and
/backup pages untouched. Cleanup (redirects, nav, Admin config move) is next.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Surfaces the hotfix channel in the WebUI. Primary home is the Updates &
Improvements page (the updater component) — its own "Improvements" tab — with a
secondary chip on the App detail page (fork 3 locality = both).
Updater component (components/updater):
- New "Improvements" sidebar tab + panel; renderImprovements() reads the host-
generated artifacts_available.json (severity badge, scope chip, applied/auto/
not-applicable badges, plain-English why). Apply/Revert buttons dispatch
artifact_apply / artifact_revert through the TASK system (services.tasks.route)
— no mutating API. Apply is disabled when the index is UNSIGNED.
- Overview gains an "Improvements" stat card; task-refresh now also repaints on
artifact_* task completion; URL tab routing + dispose teardown extended.
Task plumbing (core/tasks): artifactApply/artifactRevert action methods (id is
charset-guarded before it enters the command string) + artifact_apply/
artifact_revert routeAction cases. Task list/format gain icons + friendly labels.
Apps component: an amber "⚡ N improvements" chip on an installed app's detail
header (populated async from artifacts_available.json filtered by app, applicable
& not-applied), linking to /updater/improvements. Best-effort, never throws.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
Comment-only tidy from the feng-shui audit — no code behavior changes. The
features/ directory was renamed to components/ during modularization, but
several header banners and inline comments still named the old path:
- 6 component module headers (admin/tasks/backup/dashboard/updater/index.js +
updater/js/updater-page.js) now name their real components/<id>/… path
- core/kernel/js/spa.js + core/tasks/js/task-router.js comments
- backend/routes/features.js doc-banner (drop a components/<id>/ folder …)
- core/update-notifier/css/update-notifier.css header (js/update-notifier.js)
Guarded the rewrite so the LIVE /api/features/list endpoint name (feature-
registry.js sources + backend route) is untouched — only stale 'features/<path>'
directory references were updated.
Signed-off-by: librelad <librelad@digitalangels.vip>
De-clutter each component into sub-system folders (apps: core/ port-manager/
services/ tools/ routing/; admin: config/ overview/ system/ ssh/ peers/) with
the standard js/ css/ html/ icons/ layout inside; single-page components
(backup/dashboard/tasks/updater) get js/ css/ html/. Single-feature icon sets
moved into their sub-system (vpn -> apps/core/icons, config/cpu/os ->
admin/{config,system}/icons); shared app + category icons stay in core/icons.
feature.json + index.js stay at each component root (the scanned descriptor +
entry). Every controller/CSS/fragment/icon path reference rewritten; verified
no stale refs, all JS valid.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
Restructure the updater page to mirror Backups exactly:
- updater-content.html: shared .sidebar/.category (with .category-icon SVGs)
outside the page card, .config-section + .page-header + a padded
.updater-page-body — fixes the missing content padding.
- updater.css: layout copied from .backup-* (flex, padding-bottom:48px,
body padding:22px); dropped the custom sidebar/header styles (now using the
shared chrome); kept the updater-specific content widgets.
- updater-page.js: delegate clicks on .updater-layout (sidebar is now a
sibling of the card) so clicking a sidebar entry opens that tab; fill the
shared page-header icon slot.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>