Commit Graph
120 Commits
Author SHA1 Message Date
Mitchell-JohnsonandClaude Opus 5 e0625be684 The disks box is drives; the net box lets you pick the interface
Disks: one row per physical drive with its model, size, temperature and IO, and a usage
bar built from the filesystems the sampler can attribute to it. Attribution is new — a
mount's source device is resolved through sysfs to the drive behind it, following one
layer of device-mapper or md and folding NVMe namespaces the way the sampler does. A pool
member gets no usage bar, because one drive's share of a raidz pool is not a real number.

Net: every interface that is up is listed and tappable, defaulting to the one that has
actually carried traffic rather than whichever the kernel listed first.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 12:09:39 -07:00
Mitchell-JohnsonandClaude Opus 5 bf0bdd54af The disks box is this machine's own storage, not a network share
core mounts grid's tank over CIFS, and it was listed beside root and efi as though it
were a disk in the box. Filesystems whose storage is on another machine are now marked
remote — a label on the fs sensors, so the sensor stays for anyone who wants it — and the
Processes tab's disks box leaves them out.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
v0.1.0-116-gbf0bdd5
2026-09-23 23:16:17 -07:00
Mitchell-JohnsonandClaude Opus 5 9bf60deffc Retire the Dashboard tab; Processes is the front page
The app repeated itself. The module list, /api/prefs/dashboard, applyPrefs and the
per-user dashboard blob are gone. Widgets stays and now says plainly that it is for
dashboards outside Ham Lab.

This also closes a bug: applyPrefs set the sampling rate from intervalMs inside the
dashboard layout, and reset it to the default when that field was absent — so with
per-user layouts, one account saving a dashboard could reset the sampling rate for the
whole machine. The sampler now has one source.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
v0.1.0-115-g9bf60de
2026-09-23 23:03:49 -07:00
Mitchell-JohnsonandClaude Opus 5 1eb59fd08c One tab called Processes, showing what Top showed
The two read the same data and answered the same question. Procs.tsx is gone; a rail
order saved before this keeps the merged page in Top's slot. The mouse back-button item
is dropped from the plan.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
v0.1.0-114-g1eb59fd
2026-09-23 22:58:06 -07:00
Mitchell-JohnsonandClaude Opus 5 e184b4a149 PLAN: seven more to do — tab overlap, two renames, ZFS scheduling, virtualization, Files polish
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 21:38:19 -07:00
Mitchell-JohnsonandClaude Opus 5 363ff02bda Drop the external demo: the Widgets tab is the demo
The hamlab-demo site, its Widgets-tab button, the demo_url config key and the make publish
target that fed it are all gone, along with the public read-only token it needed. The
example stays in examples/external-demo as something to read. The installer one-liner
already comes from Gitea releases.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
v0.1.0-112-g363ff02
2026-09-23 20:17:22 -07:00
Mitchell-JohnsonandClaude Opus 5 b5454c1022 Public downloads: the installer and the updater come from Gitea releases, no token
REQUIRE_SIGNIN_VIEW is off and mitchell/hamlab is public, so anyone can clone it or pull
a release. The other five repos are individually private and 404 to anonymous. Gitea
resolves releases/download/latest/<asset>, so the install one-liner and HAMLAB_URL point
at the newest release and never need changing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
v0.1.0-111-gb5454c1
2026-09-23 18:59:42 -07:00
Mitchell-JohnsonandClaude Opus 5 1599ac65ef PLAN: the updater shipped; what is left is where a public download lives
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
v0.1.0-110-g1599ac6
2026-09-23 14:33:20 -07:00
Mitchell-JohnsonandClaude Opus 5 68bf3bb218 An updater: what is published on Gitea, and installing it from Settings
A new selfupdate package asks one URL what the newest build is — a Gitea/Forgejo repo
API base, or any directory holding VERSION, SHA256SUMS and hamlab-linux-<arch>, which is
what make release already writes and what install.sh already downloads. The binary is
checked against SHA256SUMS before it goes near the running one, and a token is sent when
the source is behind a login, so a private Gitea serves its own fleet without opening the
instance to everyone. Version ordering is install.sh's vnum rule, so the daemon and the
installer never disagree about which build is newer.

Settings gains an Updates card: installed, published, when it last looked, the source,
release notes, Check for updates, and Install. The rail badges Settings when a newer
build is out. Nothing installs unasked — it restarts the daemon and drops terminals.

scripts/gitea-release.sh (make gitea-release) publishes dist/ as a Gitea release.
Deliberate, and not part of deploy: deploy pushes to the machines this hub owns,
publishing offers the build to every install anywhere.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 14:31:32 -07:00
Mitchell-JohnsonandClaude Opus 5 98a8de8091 PLAN: to do — deprecate copyparty, deprecate Dockhand
The Dockhand entry is the app half only; migrating the stacks stays in hamlet's
docs/pending.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 11:32:52 -07:00
Mitchell-JohnsonandClaude Fable 5.1 ad88a48c01 space: the diff's clock runs inside sudo, so zfs is killed too
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 01:19:19 -07:00
Mitchell-JohnsonandClaude Fable 5.1 314a021a3e space: zfs diffs run side by side, give up after four minutes, and die properly
The timeout killed sudo and left zfs holding the pipe, so the refresh of tank sat on
immich's diff indefinitely. The process group is killed now, and a slow dataset is walked
by mtime instead.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 01:13:05 -07:00
Mitchell-JohnsonandClaude Fable 5.1 53d1da08a5 Space keeps its scans and refreshes them: zfs diff, folder mtimes, resume after cancel
A scan is saved beside the config and read back after a restart. The next scan starts
from it: on a pool with snapshots zfs diff names what changed and only those folders are
read; elsewhere a folder whose mtime is unchanged keeps its list and only its kept files
are stat'ed again. A cancelled scan keeps what it walked and Resume reads the rest.
Forget drops the saved result. The treemap is every file a tile, grouped by folder, with
no nested boxes: the folder chains of a Linux system made a staircase of empty headers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 00:43:30 -07:00
Mitchell-JohnsonandClaude Fable 5.1 c96d6facad PLAN: Space scans a disk or a pool, from a dropdown
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 20:28:00 -07:00
Mitchell-JohnsonandClaude Fable 5.1 8f77cc23e1 Space: the picker itself — pools with layout and members, then disks on their own
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 20:27:20 -07:00
Mitchell-JohnsonandClaude Fable 5.1 e9fa21768e Space: the unit is a disk on its own or a ZFS pool as a whole, picked from a dropdown
A pool's member disks are listed under it, not offered apart; the picker shows the
layout, members, size and scan state.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 20:26:03 -07:00
Mitchell-JohnsonandClaude Fable 5.1 4280b2226a Top: a hyper-thread wears its core's temperature, and the columns line up
The process table carries each logical CPU's core id from sysfs topology; a row with
no reading still has the temperature cells, so the % column is one column.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 20:22:54 -07:00
Mitchell-JohnsonandClaude Fable 5.1 41e63f74e9 space: 32-bit builds — stat fields are int32 there
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 20:19:19 -07:00
Mitchell-JohnsonandClaude Fable 5.1 fc5236471e Space: what is using a disk, WizTree-style
Pick a disk, not a partition; the scan walks every filesystem it backs, as root when
the host allows, in a helper process that streams the tree back. A tree of folders
largest-first over a treemap of the selected folder, nested to the file and coloured by
kind, plus the thousand largest files. The rail no longer offers the hub-only pages
while a remote machine is being looked at.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 20:18:36 -07:00
Mitchell-JohnsonandClaude Fable 5.1 7e3e916f25 Arrange the rail: drag pages into your own order, kept with the account
The close cross on a detail pane is drawn, not a glyph, and sits in no box.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 19:59:25 -07:00
Mitchell-JohnsonandClaude Fable 5.1 b8ea7abcc7 A × closes a detail pane on a wide screen: Docker, Services, Cron
On a phone the list gives way to the pane and Back returns; on a desktop the list stays
beside it and there was no way to put the pane away.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 19:52:35 -07:00
Mitchell-JohnsonandClaude Fable 5.1 027a2a575c A Users tab: own password, sessions and accounts in one place
Settings keeps appearance, rates, tokens and About.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 19:45:01 -07:00
Mitchell-JohnsonandClaude Fable 5.1 2b54a06821 Users, with their own settings, and a list of where each is signed in
The login is a user name and a password. The old single password becomes the account
named after the OS user on first boot, along with its sessions and the machine-wide look.
Settings gains Users (add, remove, reset a password — your own password confirms) and
Sessions (device, IP, last seen; revoke one or sign out everywhere else). Theme, accents
and the dashboard layout follow the account; the refresh rate, graph history and alerts
stay the machine's. Pairing a machine takes a user on it. Log lines name the actor.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 18:20:30 -07:00
Mitchell-JohnsonandClaude Opus 5 db214ebc2b PLAN: to do — users, with their own settings
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 17:36:53 -07:00
Mitchell-JohnsonandClaude Opus 5 e558ca7ace PLAN: to do — a public download page and an updater that uses it
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 16:47:34 -07:00
Mitchell-JohnsonandClaude Opus 5 4b255fe63f A drive is a drive: NVMe namespaces fold into their controller
An Apple SSD presents three namespaces and the kernel lists each as a whole disk, so the
dashboard was showing one drive as three. The Disks page has always folded them; now the
dashboard, the Top tab and the disk.* sensors do too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 09:11:03 -07:00
Mitchell-JohnsonandClaude Opus 5 5761ee09db BUGS: note the one Firefox console line that is navigation, not a fault
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 00:11:37 -07:00
Mitchell-JohnsonandClaude Opus 5 5412e316de A live socket stays with the machine it was opened for
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 23:53:18 -07:00
Mitchell-JohnsonandClaude Opus 5 3c7e46104c Bug bash 5: the URL, the fleet loop, and an empty card
A link to a hub page no longer reloads onto the last machine; a link from a hub-only page to
a machine's page arrives at that page; a page being left no longer asks about the next page's
selection; the hub holds its machines to the rate it is itself running.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 23:26:36 -07:00
Mitchell-JohnsonandClaude Opus 5 a7b8319974 Disks: the SMART table stays inside its card
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 21:09:43 -07:00
Mitchell-JohnsonandClaude Opus 5 dbfe163a75 A machine is titled by its own hostname, and follows a rename
The name a machine was added under stays its identity — the URL, its accent, what the hub's
API calls it — and is what the Machines page shows as 'Added as'. The hostname is read live
rather than at start-up, so renaming a machine reaches the console without a restart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 17:04:17 -07:00
Mitchell-JohnsonandClaude Fable 5.1 ec94cb8bff Top: a graph's past holds still — columns draw the peak of their own fixed slice of history
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 10:54:30 -07:00
Mitchell-JohnsonandClaude Fable 5.1 be0f2a5aaf The hub keeps every machine's sampling rate and history window in step
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 10:14:23 -07:00
Mitchell-JohnsonandClaude Fable 5.1 668e716601 Top wears the skin; the refresh rate reaches every machine; bug bash 4
The process table's columns fit the box they are in, the rate control saves, curves are
timed on the viewer's clock and keep to the stride, the power icon is drawn, and a young
history draws in from the right instead of being stretched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 10:12:45 -07:00
Mitchell-JohnsonandClaude Opus 5 ef3dbdf543 Top: a long CPU model keeps to its line
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 23:54:33 -07:00
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 08fb9d6e38 container.<name>.down: should be up and isn't — not merely stopped; the default alert watches that
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 15:10:17 -07:00