Commit Graph
64 Commits
Author SHA1 Message Date
Mitchell-JohnsonandClaude Opus 5 0587f50142 A Top tab: the whole machine on one screen, in btop's style
Boxes with their name in the border, dot curves that climb green to red, per-core meters and
temperatures, memory and filesystems, per-interface traffic and the process table. Drawn from
the sensor stream and /api/procs, so it works on every machine the console can see.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 23:52:29 -07:00
Mitchell-JohnsonandClaude Opus 5 b8eb4f5d40 Services, Docker and Cron fill the window when nothing is selected
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 20:08:09 -07:00
Mitchell-JohnsonandClaude Opus 5 04dd98e2cd Settings: one window for how far back every graph reaches, 1 minute to 24 hours
Each machine keeps 300 points per curve whatever the window, so memory doesn't follow it;
a wider window means wider points, each the average of its bucket rather than one instant
out of it. The hub passes the setting to every machine it manages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 19:07:55 -07:00
Mitchell-JohnsonandClaude Opus 5 885b050d02 The Monitors tab is called Dashboard again
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 18:29:09 -07:00
Mitchell-JohnsonandClaude Fable 5.1 1e992ca1eb Stacks: Duplicate, Labels and Network in the form, task verdict badges, a short Where; Cancel really cancels
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 13:12:54 -07:00
Mitchell-JohnsonandClaude Fable 5.1 a229f2b597 Dialogs scroll inside themselves on a phone: nothing squeezed, clear of the status bar, buttons pinned
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 12:43:23 -07:00
Mitchell-JohnsonandClaude Fable 5.1 a446a03b7d Bug bash 3: solid HUD dialogs, remote stacks deployed from the hub's shell, stopped-on-purpose is not down, the New stack dialog keeps what you typed
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 12:30:15 -07:00
Mitchell-JohnsonandClaude Fable 5.1 634e286796 Docker: delete volumes nothing uses, prune anonymous ones; images marked in use, remove unused
A named volume is deleted by typing its name, one at a time; the API wants it named
twice; nothing is forced. Prune touches anonymous volumes only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 08:01:57 -07:00
Mitchell-JohnsonandClaude Fable 5.1 c017b422d5 Docker: new stacks and containers, stack down/delete, container remove, image pull/remove/prune
A new stack is a folder in a home (where stacks are already kept: Dockhand's group here,
~/stacks elsewhere) with compose.yaml and an optional root-only .env, validated by compose
before it is kept and deployed the way its neighbours were — inside dockhand, or to a node
over tcp from the hub. New container is the same dialog on a form that writes the compose.
Homes are scanned, so undeployed stacks stay listed. Delete moves a stack's files to
.hamlab-trash; nothing is forced, and volumes and data are never touched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 07:50:43 -07:00
Mitchell-JohnsonandClaude Fable 5.1 df6c1dcebf Login: no title under the logo — the logo has the name (it is the image's alt text now)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 19:43:44 -07:00
Mitchell-JohnsonandClaude Fable 5.1 3a882e2d84 New app icon and login logo: the HamLab penguin
Every icon is rendered from web/scripts/logo-source.png by scripts/icons.mjs: trimmed to
the artwork's own edge, transparent corners for the browser icons, a dark ground from the
artwork's palette for iOS (which paints transparency black) and for Android's maskable
icon, where the whole artwork sits inside the 80% safe circle. The login screen no longer
crops the logo to a circle or repeats the wordmark. Service worker cache bumped so
installed apps fetch the new files.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 19:41:47 -07:00
Mitchell-JohnsonandClaude Fable 5.1 1d48267d90 Stacks: remote stacks editable from the hub, .env editing, deploy diff, image update checks; a gone container says so
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 16:42:54 -07:00
Mitchell-JohnsonandClaude Fable 5.1 eddba4250b Bug bash 2: 11 bugs in Stacks, Alerts, Docker, skins and the installer, fixed and verified (BUGS.md)
Stacks: deploy with every compose file (labels from inspect, not comma-joined ps);
refuse a stale overwrite; empty list without Docker. Alerts: firing state survives a
restart without re-announcing; vanished alerts are recorded as cleared with the reason;
rule values validated; 200 rules. Docker: 404 for a removed container's logs. Skins: four
palettes lifted to readable contrast. Phone: bigger toggles and swatches. Installer:
deploy republishes; an older published build is never installed silently.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 15:59:51 -07:00
Mitchell-JohnsonandClaude Fable 5.1 9c4f9dfa9f Docker: a Stacks section — edit a compose file, validate, deploy; fix the sideways scroll on phones
Stacks are found from container labels; the file is resolved on the host or through an
orchestrator's mounts, and compose runs where the file makes sense (inside Dockhand here),
so a redeploy is identical to how the stack was deployed. Save validates with compose and
keeps a .hamlab-bak; Deploy / Update / Restart / Stop run as followed tasks.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 15:23:50 -07:00
Mitchell-JohnsonandClaude Fable 5.1 cb1617c2b8 Alerts tab, Docker tab, nine new skins including HUD, a colour for every machine
Alerts: rules over sensors, watched fleet-wide from the hub; ntfy and webhook channels;
firing count on the rail. Docker: containers by stack with live use, start/stop/restart,
following logs, inspect, images/volumes/networks. Skins: HUD, Nord, Gruvbox, Catppuccin
(+Latte), Dracula, Tokyo Night, Solarized (+Light). Accents: per-machine colour.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 15:07:15 -07:00
Mitchell-JohnsonandClaude Fable 5.1 63fcba6077 Rail: an outline clock for Cron instead of the ⏱ emoji
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 12:06:15 -07:00
Mitchell-JohnsonandClaude Fable 5.1 a838adcb27 Machine menu shows each machine's address instead of its load
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 10:45:24 -07:00
Mitchell-JohnsonandClaude Fable 5.1 d3f2a83249 Terminal: Ctrl+C copies a selection (else ^C), Ctrl+V pastes, over http too; drop Log out everywhere
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 10:44:17 -07:00
Mitchell-JohnsonandClaude Fable 5.1 d7ed4d8549 Quality of life: in-app dialogs, selections in the URL, editable widgets, token dialog, gallery search, status history, stream errors that say why, tab reordering and shortcuts, log out everywhere
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 10:34:59 -07:00
Mitchell-JohnsonandClaude Fable 5.1 8ee2a2d293 Bug bash 2026-09-19: 17 bugs fixed and verified (BUGS.md)
Widgets: a bad pattern no longer silences every widget; malformed layouts load.
Shell: lost session returns to login at once; tab titles; Escape closes menus and dialogs.
Files: names are one path segment; unsaved edits ask before page/machine/tab changes;
only folders that opened are remembered. Terminals: unique default names; 64-char names.
API: queries capped at 10 000 values; 32 streams per client, 512 in all; only
/embed/widget is frameable. ZFS sensors: one unprivileged zpool list, no sudo journal spam.
Phone: 36 px inputs; dataset rows as wide as their cells. Machines: valid name pattern.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 10:18:23 -07:00
Mitchell-JohnsonandClaude Fable 5.1 62605d57eb Widgets tab links the external demo when config.json names one (demo_url)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 08:58:36 -07:00
Mitchell-JohnsonandClaude Fable 5.1 0b0b2897cb Rail: Widgets sits under Machines
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 08:37:52 -07:00
Mitchell-JohnsonandClaude Fable 5.1 b1c1404181 Widgets tab: every widget type and every sensor, live, one of each
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 08:29:15 -07:00
Mitchell-JohnsonandClaude Fable 5.1 4c2eb57ea6 Sensors: per-service and container sensors, pattern-limited tokens, fleet query, steady sampler
- service.<unit>.active|state for services that are enabled, up or failed
- containers.* and container.<name>.running|state|health|mem|cpu (cgroup reads, no docker stats)
- sensors:read tokens can be limited to ID patterns, enforced on every endpoint and,
  through the hub's filter header, on managed machines; the header can only narrow
- /api/fleet/sensors/query: one shaped query, every machine, one request
- the sampler waits what's left of the interval, so 250 ms means 4 a second
- Monitors asks for the families it draws instead of *
- unpowered hwmon sentinels (-93 °C) are not temperatures

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 08:08:44 -07:00
Mitchell-JohnsonandClaude Fable 5.1 4ddf10be51 The full switch: Monitors and Disks read only the sensor API; /api/metrics retired
- stock Monitors modules fed by one sensor stream, the catalog and one batch of
  histories (GET /api/sensors/history?ids=…), through sampleAdapter.ts
- the stream closes while the page is hidden and refills its curves on return
- Disks tab live rates from the stream
- new sensors: hamlab.sample_interval, ups.last_event
- stream: asking for about the sampling rate means every sample
- NUT runtime rounded at the source

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 07:52:14 -07:00
Mitchell-JohnsonandClaude Fable 5.1 f01175ceca Embed: bare=1 is really transparent
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 07:40:36 -07:00
Mitchell-JohnsonandClaude Fable 5.1 b05a053920 Sensors: read-only tokens, live stream, Prometheus, status sensors, widgets, embeds
- sensors:read tokens open the sensor endpoints (here and on managed machines
  through the hub) and nothing else; full tokens are never accepted from a URL
- /api/sensors/stream: a shaped query that keeps answering, over SSE
- /metrics: Prometheus text format
- services, updates, ZFS and SMART as background status sensors
- widget library over the sensor API; custom widgets on the dashboard
- /embed/widget: one live widget in its own bundle, the only frameable path
- Dashboard tab is now Monitors

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 07:37:10 -07:00
Mitchell-JohnsonandClaude Fable 5.1 232163ff4c Disks: eMMC is one device, not three, and reports wear from its own registers
mmcblkNboot0/boot1/rpmb are hardware areas of the chip; hide them on Disks and
Dashboard. Badge eMMC/SD instead of SSD. smartctl cannot talk to MMC, so read
life_time and pre_eol_info from /sys instead of showing its error.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 04:48:52 -07:00
Mitchell-JohnsonandClaude Fable 5.1 488d929733 Portable install: the binary installs itself; static builds on five architectures; root via sudo, doas or uid 0; every package manager; older systemd; no lsblk
- hamlab install / uninstall (internal/setup): systemd or OpenRC, elevates through
  sudo or doas, runs as the invoking user, sets or generates the password, names only
  journal groups that exist, waits for /healthz, reports an active firewalld/ufw.
  --purge and the data chown never touch a directory that isn't Ham Lab's alone.
- install.sh: curl-able bootstrap (arch detection, SHA256SUMS, offline beside the
  binaries, noexec /tmp fallback). make release builds dist/ for amd64, arm64, arm
  (ARMv6), 386, riscv64. Every build is CGO_ENABLED=0; the native one used to link glibc.
- internal/priv replaces every literal `sudo -n`: uid 0, sudo or doas.
- Updates acts on dnf, zypper, pacman and apk as well as apt; dnf shows installed versions.
- Services falls back to the plain systemctl table before systemd 246 and says so on
  hosts without systemd. Disks falls back to /sys/block without lsblk.
- Listener binds with IP_FREEBIND, so a LAN address that isn't up at boot is no failure.
- Self-update: the new build must pass `check` against the live config, is put in
  place by atomic rename, and the daemon re-execs itself (same under any supervisor).
- State and config writes are fsynced; a corrupt state.json is set aside, not fatal.
- Terminal shutdown no longer empties the saved list, so names come back after a
  restart by design rather than by winning a race.
- Config default is ~/.config/hamlab; an existing ~/apps/hamlab is still found.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 23:00:20 -07:00
Mitchell-JohnsonandClaude Fable 5.1 91b7f4f009 Terminal sessions move from the rail into a tab strip on the terminal page
The rail is now a flat list of pages; Terminal is one of them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 22:10:22 -07:00
Mitchell-JohnsonandClaude Fable 5.1 f093b322ee Bug bash fixes: hash routing + back button, hub-only pages reset on machine switch, exited terminals reap after 10 min, self-update refuses while busy unless forced, touch-sized controls, power confirm by machine name, down interfaces collapsed and empty modules hidden, load label, offline backoff, cron log newest first, procs empty message, timer timestamp parsing
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 17:46:16 -07:00
Mitchell-JohnsonandClaude Fable 5.1 27f9665606 Bug bash fixes: special-file reads, per-client lockout, prefs validation, security headers, kernel-thread guard, login feedback, error text; plus journal-quiet sudoers + journal groups, upload overwrite guard, machines pattern, dnf freshness, cron/services speed, clean version
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 17:41:52 -07:00
Mitchell-JohnsonandClaude Fable 5.1 0af24f41c3 Disks: one card per physical drive (NVMe namespaces folded under their controller), partitions summarised on one line instead of listed
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 14:18:20 -07:00
Mitchell-JohnsonandClaude Fable 5.1 b6502ba362 Disks: one toggle opens SMART for every drive, remembered per device
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 13:41:38 -07:00
Mitchell-JohnsonandClaude Fable 5.1 4b8a2b15ed Refresh rate is honoured exactly everywhere: no list floor, sampler up to 10 s, server caches reduced to coalescing only
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 13:32:36 -07:00
Mitchell-JohnsonandClaude Fable 5.1 bbf0f2580f Global refresh rate in Settings drives every live view and each machine's sampler; per-page pickers removed
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 13:27:13 -07:00
Mitchell-JohnsonandClaude Fable 5.1 a4f39859b6 Settings page: themes (Dark, Light, Cyberpunk, Retro) with xterm palettes and hub-synced choice, change password, access tokens, about
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 13:14:01 -07:00
Mitchell-JohnsonandClaude Fable 5.1 254e0cdd58 Update from hub: node self-update endpoint, hub push per machine / all, push-nodes CLI run by make deploy, outdated badges + Update buttons on Machines
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 12:04:31 -07:00
Mitchell-JohnsonandClaude Fable 5.1 e9be94e32b SMART: detect drives whose firmware rejects the self-test log (WD SN580) and hide the test buttons with an explanation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 11:37:49 -07:00
Mitchell-JohnsonandClaude Fable 5.1 340232b724 Header dot: don't go red on machine switch; reflect remote reachability
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 11:36:04 -07:00
Mitchell-JohnsonandClaude Fable 5.1 7dcdb5dc98 Multi-host phase 1: API tokens, auto TLS with pinned fingerprints, hub-side node manager + reverse proxy (WebSockets included), machine switcher in the rail, Machines page
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 11:35:29 -07:00
Mitchell-JohnsonandClaude Fable 5.1 fc42675e9f Processes: show current / max clock so idle scaling isn't mistaken for the rated speed
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 06:13:24 -07:00
Mitchell-JohnsonandClaude Fable 5.1 bd475eaafd Processes tab: whole page scrolls, tools + column header pinned together, detail sheet sticks to the bottom, metrics boxes collapsible
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 06:12:29 -07:00
Mitchell-JohnsonandClaude Fable 5.1 b802dcf313 Processes tab: btop-style cpu/mem/net boxes with labels, gradient bars, block graph, CPU model/GHz/temp, memory breakdown, per-interface rates, and a refresh interval control
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 06:05:09 -07:00
Mitchell-JohnsonandClaude Fable 5.1 e4df878ac0 Processes tab (btop-style): every process with CPU%, memory, cpu time, start, sortable + filter, per-core and memory bars, detail pane with terminate/kill; module removed from the dashboard; sampling only while the tab is open
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 06:01:12 -07:00
Mitchell-JohnsonandClaude Fable 5.1 ff922bda74 Dashboard: Processes module (top by CPU/memory, PID, user, threads, SIGTERM), sampled at most every 2 s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 05:58:11 -07:00
Mitchell-JohnsonandClaude Fable 5.1 4986af5ac9 Drop the top activity bar
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 05:55:11 -07:00
Mitchell-JohnsonandClaude Fable 5.1 116f4c72f6 Rail: proper folder icon for Files (inline SVG, matches the monochrome glyphs)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 05:54:20 -07:00
Mitchell-JohnsonandClaude Fable 5.1 2d23ba8582 Files rail icon: use a glyph iOS renders
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 05:48:33 -07:00
Mitchell-JohnsonandClaude Fable 5.1 63b020d556 Files tab: browser with breadcrumbs/sort/filter, text editor, image preview, streamed upload with progress, download, mkdir/touch/rename/move/chmod/delete, open-in-terminal; root toggle via sudo-reexecuted 'hamlab fs' helper
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 05:39:57 -07:00