// Hardware: what this machine is made of — the board, the processor, the memory modules in // their slots, the drives and the graphics. None of it moves, so the page is a read rather // than a monitor: what is live (temperature, usage, SMART) belongs to Dashboard and Disks. import { useCallback, useEffect, useState } from 'react' import { api, Hardware as HW, HWBoard, HWDrive, HWGPU, HWModule } from './api' import { fmtBytes } from './fmt' import { Btn, Loading } from './ui' const KIND: Record = { nvme: 'NVMe', ssd: 'SSD', hdd: 'HDD', usb: 'USB', emmc: 'eMMC', sd: 'SD', other: 'disk' } const ghz = (mhz?: number) => (mhz ? `${(mhz / 1000).toFixed(mhz >= 1000 ? 2 : 1)} GHz` : '') // A row of the "key: value" kind, dropped entirely when there is no value — a machine that // doesn't report its serial should show one fewer line, not an empty one. function P({ k, v, mono }: { k: string; v?: string | number | null | false; mono?: boolean }) { if (v === undefined || v === null || v === false || v === '' || v === 0) return null return
{k}{v}
} function Module({ m }: { m: HWModule }) { if (m.empty) { return (
{m.locator}empty
) } const speed = m.running_mts && m.speed_mts && m.running_mts !== m.speed_mts ? `${m.running_mts} MT/s (rated ${m.speed_mts})` // the board is running it slower than it could : m.running_mts || m.speed_mts ? `${m.running_mts || m.speed_mts} MT/s` : '' return (
{fmtBytes(m.size ?? 0)} {m.type} {m.locator}

) } function Drive({ d }: { d: HWDrive }) { return (
{d.model || d.name} {KIND[d.kind] ?? d.kind}

) } function Gpu({ g }: { g: HWGPU }) { return (
{g.model} {g.class && {g.class}}

) } // The board and the firmware on it. Everything here is SMBIOS, so a machine without one // — a Mac, a Pi — gets a card that says as much instead of a column of blanks. function Motherboard({ b }: { b: HWBoard }) { const named = b.maker || b.product || b.bios // A board that reports every slot "Available" is not telling us anything — mini PCs // copy the slot table out of a reference design and list slots the case has no room // for. Only worth showing when the firmware actually tracks what is plugged in. const slots = (b.slots ?? []).some((s) => s.usage === 'In Use') ? (b.slots ?? []) : [] return (

Motherboard

{!named &&
This machine has no SMBIOS table, so its firmware doesn't say what board it is.
} {named && (

)} {(b.bios || b.bios_date) && (

)} {slots.length > 0 && (
Expansion slotsas the firmware lists them
{slots.map((s, i) => ( ))}
SlotTypeWhat is in it
{s.designation} {[s.type, s.length && s.length !== 'Other' ? s.length.toLowerCase() : ''].filter(Boolean).join(' · ')} {s.usage === 'In Use' ? (s.device ?? s.bus ?? 'in use') : {(s.usage ?? '').toLowerCase() || '—'}}
)}
) } export default function Hardware() { const [hw, setHw] = useState(null) const [err, setErr] = useState('') const [busy, setBusy] = useState(false) const load = useCallback(async (refresh = false) => { if (refresh) setBusy(true) try { setHw(await api.hardware(refresh)); setErr('') } catch (e) { setErr(e instanceof Error ? e.message : 'failed') } finally { setBusy(false) } }, []) useEffect(() => { load() }, [load]) if (err) return
{err === 'not found' ? "This machine's Ham Lab is older than the Hardware tab. Update it from Machines." : err}
if (!hw) return
const { system: sys, board, cpu, memory: mem } = hw const drives = hw.drives ?? [] const gpus = hw.gpus ?? [] const capacity = drives.reduce((n, d) => n + d.size, 0) const threads = cpu.threads ?? 0 const cores = cpu.cores ?? 0 return (
{sys.model || 'this machine'} {sys.virt && {sys.virt}} load(true)}>Re-read
Processor
20 ? { fontSize: 16 } : undefined}>{cpu.model}
{[cores ? `${cores} core${cores === 1 ? '' : 's'}` : '', threads && threads !== cores ? `${threads} threads` : '', cpu.max_mhz ? `up to ${ghz(cpu.max_mhz)}` : ''].filter(Boolean).join(' · ')}
Memory
{fmtBytes(mem.installed || mem.total)}
{mem.slots ? `${mem.filled ?? 0} of ${mem.slots} slot${mem.slots === 1 ? '' : 's'} filled` : 'slots unknown'}{mem.ecc ? ` · ${mem.ecc}` : ''}
Storage
{fmtBytes(capacity)}
{drives.length} drive{drives.length === 1 ? '' : 's'}
Graphics
20 ? { fontSize: 16 } : undefined}>{gpus[0]?.model ?? 'none found'}
{gpus.length > 1 ? `${gpus.length} adapters` : gpus[0]?.driver ? `${gpus[0].driver} driver` : ''}
{(hw.notes ?? []).map((n, i) =>
{n}
)}

Processor

1 ? ` · ${cpu.threads_per_core} threads each` : ''}` : ''} />

{(cpu.caches ?? []).length > 0 && (
{(cpu.caches ?? []).map((c) =>

)}

)} {(cpu.flags ?? []).length > 0 && (
{(cpu.flags ?? []).map((f) => {f})}
)}

Memory

{(mem.modules ?? []).map((m, i) => )} {(mem.modules ?? []).length === 0 &&
The firmware doesn't say what is in the slots.
}

Drives

{drives.map((d) => )} {drives.length === 0 &&
No drives found.
}

Graphics

{gpus.map((g, i) => )} {gpus.length === 0 &&
No display adapter found.
}

System

) }