6 Commits

Author SHA1 Message Date
librelad
facf764c4b feat(webui): bulk selection on app tasks, updates overview, and app backups
The /tasks page's right-side tick + dynamic Select all / Clear All ⇄
Delete Selected layout now covers the other three management surfaces:

- App detail → Tasks tab: filter bar gains the Clear All button and
  master tick; Clear All there scopes to that app's tasks only. The
  selection set is resolved through window.tasksManager everywhere —
  TasksManager is constructed in several places, and ticks previously
  landed on one instance while Delete Selected read another's empty set.
- Apps overview → Updates: the header's Update all button now morphs to
  Update Selected (N) + Clear in place as rows are ticked, replacing the
  separate selection bar between toolbar and list.
- App detail → Backups: each snapshot row gains Delete + a right-side
  tick; a toolbar atop the list morphs Delete All ⇄ Delete Selected (N).
  The whole selection rides in ONE task (delete <app> 1:a,2:b,…) since
  the backup surfaces hold one task per subject at a time.
- CLI: backup app delete accepts comma-separated <idx>:<snap> pairs, and
  both delete and delete_all now regenerate the WebUI backup JSON so
  deleted snapshots leave the screen instead of lingering until the next
  backup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 00:59:19 +01:00
librelad
3f582120ba feat(cli): route all long-running app + update commands through tasks
Extends the install-routing spike (e5273a4) to every long-running CLI
command, so CLI and WebUI now share one execution path everywhere:

  app install      ← already done
  app uninstall
  app start / stop / restart / up / down / reload
  app backup
  app restore
  update apply
  backup app create   (matches `app backup` — same end target)

Each handler now has the same shape:
  if [[ "$LIBREPORTAL_TASK_EXEC" == "1" ]]; then
      <inline call>            # processor's recursive invocation
  else
      cliTaskRun "<cmd>" <type> <app>   # user invocation: enqueue + follow
  fi

Processor change — crontab_task_processor.sh:
  Adds `export LIBREPORTAL_TASK_EXEC=1` next to LIBREPORTAL_NONINTERACTIVE.
  Universal bypass: every task command the processor runs (CLI-queued OR
  pre-existing WebUI-queued like `libreportal app install adguard`)
  inherits the env var, so the inline branch fires and we never
  re-enqueue. This also lets us drop the env-var prefix the install spike
  was baking into the command string (e5273a4) — cleaner task files +
  one place to think about the bypass.

`backup app schedule` (the cron-driven path that already enqueues via
createTaskFile in backup_app_schedule.sh) is left alone — different
entry point, different runtime context, already correctly task-routed.

Why route the fast ones too (start/stop/restart/up/down):
  Consistency beats the ~1s task-roundtrip latency for a CLI button.
  Locking now serialises a CLI `app stop foo` against a WebUI restart of
  the same app; the audit trail covers every state change. Cheap to
  revert any individually if the latency turns out to bother someone.

Validated live earlier with `libreportal app install dashy` — task file
written, processor dispatched, follower streamed install live, exit 0
propagated. Same machinery now powers the other 9 handlers.

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-27 14:38:14 +01:00
librelad
839cf3561a feat(cli): backup system / restore system subcommands
Expose the system-config backup on demand (not just within 'backup all'):

- `libreportal backup system`      -> backupSystemConfig (snapshot the system
  config — settings, WebUI creds, backup-location creds — to all enabled locations)
- `libreportal restore system [loc_idx]` -> backupRestoreSystemConfig (restore the
  latest system snapshot into a staging dir; never overwrites live config)

Distinct from the existing 'restore migrate system' (which restores all *apps*
from another host). Help text updated for both. Routing verified with stubs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-26 00:27:25 +01:00
librelad
19c76f0a3f feat(backup): CLI + data plumbing for per-location SSH keys
Expose the existing location_ssh.sh key store through the backup CLI:
'backup location ssh-key-set|ssh-key-generate|ssh-key-public|ssh-key-delete <idx>'
(the WebUI runs these as tasks). The locations generator now emits
ssh_key_exists + ssh_public_key (public key only — the private key never
leaves the per-location ssh.key file), so the editor can show the key state.
Also fix the stale SSH_AUTH label (~/.ssh/id_rsa -> managed per-location key).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-23 16:11:31 +01:00
librelad
4ce0340ef8 refactor(backup): replace per-app cron stagger with task-queue scheduler
Application backups were driven by one crontab entry per app, each offset by
id * CFG_BACKUP_CRONTAB_APP_INTERVAL minutes. That minute offset is written
straight into cron's 0-59 minute field, so past ~20 apps it overflowed into
an invalid entry that silently never fired, and the fixed spacing could not
serialize backups that ran longer than the gap.

Replace it with a single daily entry (`libreportal backup scheduled`) that
enqueues a backup task per enabled app. The existing systemd task processor
drains them serially — no minute overflow, real serialization, and backups
are now visible/cancellable in the Tasks UI. Per-app enable is read from
CFG_<APP>_BACKUP at schedule time instead of being mirrored into crontab.

Removes the stagger machinery (timing/setup/check/remove scripts), the
now-unused cron_jobs table + insert, and the CFG_BACKUP_CRONTAB_APP_INTERVAL
config knob and its WebUI field.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-22 14:34:35 +01:00
librelad
875a60f90f LibrePortal v0.1.0 — initial release
A free, open, self-hosted app platform (GNU AGPLv3): one-click app deploys,
Traefik reverse proxy with automatic SSL, rootless Docker support, gluetun
VPN routing, and a web dashboard to manage it all.

Free & open forever to self-host; optional paid hosted services fund it.
See PROMISE.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-21 20:37:54 +01:00