The config-category icons sat at admin/config/icons/CONFIG/ — the inner config/
duplicates the subsystem name; they belong in the icons root. Moved all 6
(backup, features, general, network, security, webui) up to
components/admin/config/icons/ and updated the two consumers (config-manager.js
header icon, config-sidebar.js category icons).
Also fixed the backup-engine logos: scripts/backup/engines/{restic,kopia,borg}
.json pointed 'logo' at /icons/config/backup.svg — a path that 404'd on two
counts (missing the components/admin/config prefix AND the now-removed config/
nesting), so the engine-details modal logo silently hid. Repointed to the real
served path /components/admin/config/icons/backup.svg.
(Left the meaningful icon groupings alone — admin/system/icons/{cpu,os} and
apps/core/icons/vpn are vendor/OS/provider logo sets, not redundant nesting.
The backup engines borrowing an admin-config icon is a minor smell; a dedicated
backup-engine icon could replace it later if wanted.)
Signed-off-by: librelad <librelad@digitalangels.vip>
Brings core/ in line with components/ — each subsystem now sorts its files into
js/ css/ html/ subfolders (and the nested auth/ + controls/ groups keep theirs):
core/topbar/{js/{topbar,mobile-menu}.js, css/{topbar,sidebar}.css, html/topbar.html}
core/theme/{js/theme-registry.js, css/{tokens,themes,base,aurora-background}.css}
core/forms/{css/{forms,config}.css, controls/js/{custom-number,custom-select}.js}
core/boot/{js/{system-loader,system-orchestrator}.js, auth/{js/auth-manager.js,css/login.css}}
core/{config,tasks,kernel}/js/… core/overlays/{js,css}/… core/setup/{js,css}/…
core/{app-meta,backup-card,data-loader,dom,live,notifications,ui-mode,ui-state}/js/…
core/{loading,update-notifier}/{js,css}/…
50 files relocated (pure git mv). All path literals rewritten from a generated
old→new map across index.html, system-loader.js bundles, topbar.js's internal
fetch (/core/topbar/html/topbar.html), and the three backup-app-card loaders. No
OLD path contained a js/css/html segment, so no double-prefixing was possible.
core/icons/ left as-is (shared asset tree). All 50 /core asset refs verified to
resolve; full node --check sweep clean.
Signed-off-by: librelad <librelad@digitalangels.vip>
The frontend modularization moved icons to frontend/core/icons/ and updated the
frontend JS, but the host-side generators were never updated — they wrote the
apps.json/categories 'icon' field as /icons/apps/<app>.svg and /icons/categories/
<cat>.svg, and webui_app_icons.sh / webui_config.sh synced icon files into the
non-existent frontend/icons/apps. Those served paths 404 (text/html catch-all),
so every app card fell back to default.svg (the generic box) instead of its real
logo.
Repointed to /core/icons/... (where the SVGs actually live and serve as
image/svg+xml):
- webui_config.sh: icon dir + emitted apps.json icon path
- webui_app_icons.sh: icon sync dir + comment
- webui_container_setup.sh: comment
- webui_create_app_categories.sh: 11 category icon paths
Source fix only — the live apps.json refreshes on the next host-side regen
(lpRegen). NOT touched: scripts/backup/engines/*.json '/icons/config/backup.svg'
(that SVG lives at the oddly-nested components/admin/config/icons/config/ and
serves at neither path — needs a placement decision, flagged separately).
Signed-off-by: librelad <librelad@digitalangels.vip>
The generic core/css/{base,components,screens} buckets are gone; every shared
stylesheet now lives beside the subsystem that owns it:
base/tokens.css, base/themes.css, components/aurora-background.css -> core/theme/
base/style.css -> core/theme/base.css (carve deferred)
components/modal.css -> core/overlays/
components/topbar.css, components/sidebar.css -> core/topbar/
components/forms.css, components/config.css -> core/forms/ (config.css under forms)
components/update-notifier.css -> core/update-notifier/
screens/login.css -> core/boot/auth/
screens/loading-screen.css -> core/loading/
screens/setup-wizard.css -> core/setup/
href-only rewrites in index.html; the <link> line ORDER is unchanged, so the
cascade is preserved (no @import anywhere). All 13 /core css hrefs verified to
resolve. (The JS for overlays/topbar/forms/update-notifier/loading/setup/auth
co-locates in the next phase.)
Signed-off-by: librelad <librelad@digitalangels.vip>
The Phase-2 rename put DataLoader in core/data/, but update.sh's deploy rsync
uses --exclude 'data/' (to protect the runtime frontend/data/ dir the backend
serves auth-gated under /data). rsync's pattern matches a 'data' dir ANYWHERE in
the tree, so core/data/ was silently excluded from the served copy — the file
404'd and the dashboard showed 0 apps / Loading… while every sibling subsystem
deployed fine. Renamed the folder to core/data-loader/ (segment 'data-loader' ≠
'data') so it ships. No code/class change.
Signed-off-by: librelad <librelad@digitalangels.vip>
The generic core/lib/ wrapper (and its task/config/util sub-buckets) is gone.
Each child is now a named core subsystem describing what it IS:
core/lib/task/ -> core/tasks/ (task kernel: bus, refresh,
manager, router, actions,
commands, parameter-preserve)
core/lib/config/ -> core/config/ (config-shared.js→field-factory.js,
config-options.js→options.js;
options-before-factory order kept)
core/lib/util/system-live -> core/live/live-system.js
core/lib/util/lp-ui -> core/ui-mode/lp-ui.js (stays FIRST eager — no FOUC)
core/lib/util/data-loader -> core/data/data-loader.js
core/lib/util/dom-helpers -> core/dom/dom-helpers.js
core/lib/util/ui-helpers -> core/app-meta/app-helpers.js (getAppIcon survivor)
core/lib/util/dismissible -> core/ui-state/dismissible.js (generic+eager, stays
core — NOT a backup widget)
core/boot/theme-registry -> core/theme/theme-registry.js (theming, not bootstrap)
Path-only moves (git mv) + literal rewrites in index.html, system-loader.js
(config/task/apps bundles) and apps-manager ensureTaskScripts. Class/global
names unchanged (ConfigShared/ConfigOptions/LiveSystem/getAppIcon) so consumers
are untouched. All 16 referenced paths verified to resolve; full node --check
sweep clean.
Signed-off-by: librelad <librelad@digitalangels.vip>
Verified-dead removals (zero consumers, confirmed by adversarial dependency
audit):
- core/lib/util/router.js — legacy class Router superseded by kernel/spa.js;
self-instantiated, never exposed, and added a SECOND competing popstate
listener. Dropped the file + its eager index.html tag.
- core/lib/task/task-global-functions.js — wired window.installApp/uninstallApp/
etc. that nothing calls (real calls go through class methods / the task
router). Dropped the file + its task-system scripts[] entry + the
setupTaskGlobalFunctions() block in system-loader.js.
- TopbarComponent.createNavigationHighlighting + clearAllNavigationHighlighting —
dead statics; window.topbarNavigationHighlighting was never set.
- ui-helpers.js: getAppStatus/formatAppName/getAppShortName (dead), the stale
setupMobileMenu/closeMobileMenu (superseded by core/ui/mobile-menu.js's
#mobile-drawer impl), setupActiveNavigation + the safe* helpers (verbatim dups
of dom-helpers). Only getAppIcon remains. dom-helpers loses dead
setupActiveNavigation + waitForElement; it is now the sole safe* source.
Bug fixes surfaced during the audit:
- system-orchestrator.js called this._wireLogout() which is defined nowhere —
threw on the 'Continue Anyway' boot path. Removed the dangling call (logout is
wired in topbar.setupLogout()).
- active-nav highlighting never updated on SPA navigation (it depended on the
never-set global). spa.js now calls the live window.topbar?.setActiveNav?.()
after each route handler.
No structural moves yet; full node --check sweep clean.
Signed-off-by: librelad <librelad@digitalangels.vip>
core/css held 13 flat stylesheets. Grouped by role, matching the JS sub-system
split:
core/css/base/ foundation (3): tokens, style, themes
core/css/components/ chrome + widgets (7): topbar, sidebar, modal, forms,
config, update-notifier, aurora-background
core/css/screens/ full-page screens (3): login, loading-screen,
setup-wizard
Path-only move (git mv) + href rewrite in index.html. No @import anywhere and
the <link> line order is unchanged, so the cascade is preserved; all 13 paths
verified to resolve.
Signed-off-by: librelad <librelad@digitalangels.vip>
backup/ held 15 loose .js plus css/html at the component root. Split into
per-tab sub-systems mirroring the admin/apps layout:
backup/core/{js,css,html}/ schema, base BackupPage, fetch-client,
cron-schedule, backup.css, backup-content.html
backup/dashboard/js/ backup-dashboard
backup/snapshots/js/ backup-snapshots, backup-snapshot-actions
backup/locations/js/ backup-locations, backup-location-fields,
backup-location-modal, backup-ssh-key
backup/migrate/js/ backup-migrate
backup/configuration/js/ backup-configuration, backup-retention-presets,
backup-engine-details
Updated the scripts[] array + loadFragment in index.js, the backup.css href in
index.html, and the handleBackup() fallback paths in spa.js. No behaviour
change — files moved verbatim (prototype-augment clusters), all 17 referenced
paths verified to resolve, node --check clean.
Signed-off-by: librelad <librelad@digitalangels.vip>
admin had sub-system folders (config/overview/system/ssh/peers) AND a bare
root css/ (admin.css) — inconsistent. A component's shared base belongs in a
core/ sub-folder once it has sub-systems (matching apps/core/), so admin.css
moves to admin/core/css/admin.css. Audit confirms all components are now
consistent: sub-system components (apps, admin) use core/ + sub-systems;
single-page components (backup/dashboard/tasks/updater) stay flat js/css/html
(no sub-systems, so no core/ needed).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
config-redirect/, peers/, ssh/ were redirect-only shim components (just a
feature.json each) whose handlers re-entered navigate() and were silently
no-op'd by the isLoading guard — i.e. the legacy /config /peers /ssh URLs were
broken, and nothing in the UI links to them. Replace all three with a single
_legacyRedirect() at the top of navigate() (before the guard, so it actually
works) that rewrites them to the canonical /admin/* path. Removed the 3
folders, their manifest entries, the 3 dead spa.js handlers, and their
setupRoutes() lines. components/ is now exactly the 6 real pages; the real
SSH/Peers pages live (as before) under admin/ssh and admin/peers.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
app-detail was a separate sibling component but is really the apps feature's
detail view (shares the apps controllers + apps-unified-layout). Merge it in:
the apps feature now owns /apps*, /app, /app* and its mount() dispatches grid
vs detail by path (checks /apps first for wildcard precedence). Removed the
components/app-detail/ folder + its manifest entry. (The 1-level feature scan
means a feature must be a direct components/<id>/ child — folding the routes
into apps is the correct way to express the relationship.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
Brace-aware split of apps-manager.js (4154->2015 base) into apps-grid,
config-form, port-manager-integration, gluetun-vpn, config-dirty-guard,
install-console, service-buttons-sidebar — augmenting AppsManager.prototype.
Removed the dead duplicate initializeSimpleTabs (kept the live later def).
Used a self-checking extractor (node --check per cluster, auto-revert on
failure): install-dispatch contains a regex literal (/^\d{16}$/) that trips
brace-bounding, so its methods were safely LEFT in the base rather than risk a
bad split. ServiceButtons class + expandServiceLinks + bootstrap also remain
inline. Verified: all 117 methods preserved (none lost), all files
node --check clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
Faithful brace-aware split of tasks-manager.js (2664->491 line base) into
list-render, data-load, log-stream, row-expand, actions, modals, logs-modal,
format — augmenting TasksManager.prototype. First removed 4 provably-dead
duplicate defs (the earlier init/setupAutoRefresh/startLogStreaming/loadTaskLogs
that the later defs already overrode — behavior-preserving). Methods relocated
verbatim via a brace-aware Node extractor (handles strings/templates/comments/
regex, fixing the line-heuristic over-capture). Verified: all 60 (deduped)
methods present exactly once, no dups, all 9 files node --check clean. Wired
after the base in the task-system loader (async=false-ordered).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
Faithful prototype-augment split of backup-page.js (2353->753 line base) into
fetch-client, dashboard, snapshots, locations, location-fields, ssh-key,
retention-presets, configuration, engine-details, location-modal,
snapshot-actions, migrate (+ the earlier cron-schedule). Methods relocated
verbatim (mechanical sed/awk extraction, no logic change); all augment
BackupPage.prototype and load after the base via the ordered kernel loader.
Verified: all 99 original methods present exactly once across base+clusters,
no duplicates, all 14 files node --check clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
First god-file decomposition slice: lift the standalone cron-next utility
(nextCronFireTime/_cronFieldSet/formatRelativeFuture/formatScheduleClock) out
of backup-page.js into backup-cron-schedule.js, augmenting BackupPage.prototype.
Extracted verbatim via sed (no logic change); loaded after backup-page.js in
the feature's ordered scripts array. backup-page.js 2470 -> ~2353 lines.
Proves the faithful prototype-split pattern on the verify-confirmed-safe loader.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
system-loader's loadScript appended scripts without async=false, so a
component's scripts[] executed in download-finish order, not array order.
That's a latent nondeterminism today (duplicate-method 'last wins' depended
on it) and a hard blocker for splitting a class across files (a base file
must run before prototype-augment files). Forcing async=false makes the
boot loader honour array order, matching the kernel's ctx.loadScripts.
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>
- scripts/webui/data/generators/updater/webui_updater_scan.sh (webuiUpdaterScan):
writes frontend/data/updater/generated/{updates,cves,history}.json from the
installed-apps DB (current image per app from compose). Available-version +
CVE-scanner are clearly-marked pluggable hooks; always emits valid JSON.
- scripts/cli/commands/updater/{cli_updater_commands.sh,cli_updater_header.sh}:
auto-dispatched as 'libreportal updater <sub>' (check/apply/apply-all/rollback).
apply does disaster-recovery FIRST — snapshots the app via the backup engine,
then pulls + recreates (real dockerComposeUp/compose-pull helpers), records
history, and auto-rolls-back on failure. Standard LIBREPORTAL_TASK_EXEC
enqueue/exec split so WebUI + CLI share locking + audit trail.
New .sh files: the array/function-manifest regen self-heals on deploy; the
check path also sources its generator on demand to cover the gap.
NOTE: host-side bash — written to the repo's conventions but not runnable in
this env; this is the surface to test (the WebUI feature is lp-shot-verified).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
Add updater_check/apply/apply_all/rollback cases to task-router routeAction
and the matching task-actions methods, each running the locked-down
'libreportal updater …' CLI as a task (apply/rollback snapshot-before-update
host-side for disaster recovery). Verified: /updater + all tabs render, the
new Updates nav button shows globally, and the feature auto-discovers via
/api/features/list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>