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>
This commit is contained in:
Mitchell-Johnson
2026-09-18 17:46:16 -07:00
co-authored by Claude Fable 5.1
parent 27f9665606
commit f093b322ee
14 changed files with 126 additions and 36 deletions
+10 -2
View File
@@ -38,13 +38,21 @@ export default function Machines({ hub, onChanged, onOpen }: { hub: Me; onChange
}
async function update(m: MachineStatus) {
if (!window.confirm(`Update ${m.name} to ${norm(hub.version)}? Its Ham Lab restarts; open terminals there are lost.`)) return
try { const r = await api.updateMachine(m.name); toast(`${m.name} updated to ${r.version}, restarting`); setTimeout(load, 4000) } catch (e) { toast(`${m.name}: ${e instanceof Error ? e.message : 'failed'}`, 'err') }
try { const r = await api.updateMachine(m.name); toast(`${m.name} updated to ${r.version}, restarting`); setTimeout(load, 4000) }
catch (e) {
const msg = e instanceof Error ? e.message : 'failed'
if (msg.startsWith('busy:') && window.confirm(`${m.name} is ${msg.slice(6)}\n\nForce the update anyway?`)) {
try { const r = await api.updateMachine(m.name, true); toast(`${m.name} updated to ${r.version}, restarting`); setTimeout(load, 4000) } catch (e2) { toast(`${m.name}: ${e2 instanceof Error ? e2.message : 'failed'}`, 'err') }
} else toast(`${m.name}: ${msg}`, 'err')
}
}
async function updateAll() {
const n = list?.filter(outdated).length ?? 0
if (!window.confirm(`Update ${n} machine${n === 1 ? '' : 's'} to ${norm(hub.version)}?`)) return
try {
const res = await api.updateAllMachines()
let res = await api.updateAllMachines()
const busy = res.filter((r) => !r.ok && (r.error ?? '').startsWith('busy:'))
if (busy.length && window.confirm(`${busy.map((r) => r.name).join(', ')}: ${busy[0].error?.slice(6)}\n\nForce those too?`)) res = res.map((r) => r).concat(await api.updateAllMachines(true))
for (const r of res) toast(r.ok ? `${r.name} → ${r.version}` : `${r.name}: ${r.error}`, r.ok ? 'ok' : 'err')
setTimeout(load, 4000)
} catch (e) { toast(e instanceof Error ? e.message : 'failed', 'err') }