A Hardware tab: what the machine is made of
Per machine, like every other page. Four tiles — processor, memory, storage, graphics — over a card for each. Memory is the part that had nowhere to live before: every slot, with the module's size, type, form factor, rated and running speed, maker, part number, serial, rank and voltage, and the empty slots marked empty. A module whose maker is only a JEDEC id gets a name when it is one we know and keeps the number when it is not, because a wrong name is worse than a code. Everything is read from what Debian already has: dmidecode for the parts only the firmware knows, lscpu, lspci, sysfs. None of it changes under a running kernel, so it is read once and kept for ten minutes; Re-read is for the one thing that does change, a drive plugged in. Every reader is allowed to come back empty. A machine with no dmidecode, no root to read it with, or no PCI bus at all still gets a page, with a note saying what was missing and why. Checked against the Mac mini, which is all three cases at once: no SMBIOS memory table, a GPU only the device tree knows about, and cores that are not all alike — lscpu counts one cluster as "cores per socket" there, so without SMT the thread count is the honest answer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
09dc846730
commit
776bcb236d
+6
-3
@@ -11,6 +11,7 @@ import Services from './Services'
|
||||
import Jobs from './Jobs'
|
||||
import Updates from './Updates'
|
||||
import Disks from './Disks'
|
||||
import Hardware from './Hardware'
|
||||
import ZFS from './ZFS'
|
||||
import KVM from './KVM'
|
||||
import Files from './Files'
|
||||
@@ -57,6 +58,7 @@ const GROUPS: Group[] = [
|
||||
{ id: 'services', label: 'Services', icon: '◈' },
|
||||
{ id: 'jobs', label: 'Jobs', icon: ClockIcon },
|
||||
{ id: 'disks', label: 'Disks', icon: '▤' },
|
||||
{ id: 'hardware', label: 'Hardware', icon: '⬡' },
|
||||
{ id: 'files', label: 'Files', icon: FolderIcon },
|
||||
{ id: 'usage', label: 'Usage', icon: '▧' },
|
||||
{ id: 'zfs', label: 'ZFS', icon: '⛁' },
|
||||
@@ -70,8 +72,8 @@ const GROUPS: Group[] = [
|
||||
{ id: 'settings', label: 'Settings', icon: '⚙' },
|
||||
]
|
||||
|
||||
type View = 'terminal' | 'widgets' | 'docker' | 'alerts' | 'services' | 'jobs' | 'updates' | 'disks' | 'zfs' | 'usage' | 'files' | 'procs' | 'machines' | 'kvm' | 'users' | 'settings'
|
||||
const VIEWS: View[] = ['terminal', 'widgets', 'docker', 'alerts', 'services', 'jobs', 'updates', 'disks', 'zfs', 'usage', 'files', 'procs', 'machines', 'kvm', 'users', 'settings']
|
||||
type View = 'terminal' | 'widgets' | 'docker' | 'alerts' | 'services' | 'jobs' | 'updates' | 'disks' | 'hardware' | 'zfs' | 'usage' | 'files' | 'procs' | 'machines' | 'kvm' | 'users' | 'settings'
|
||||
const VIEWS: View[] = ['terminal', 'widgets', 'docker', 'alerts', 'services', 'jobs', 'updates', 'disks', 'hardware', 'zfs', 'usage', 'files', 'procs', 'machines', 'kvm', 'users', 'settings']
|
||||
const HUB_ONLY: View[] = ['machines', 'users', 'settings', 'alerts']
|
||||
|
||||
// URL hash is the source of truth for where you are: #/<machine|hub>/<view>. Back and
|
||||
@@ -296,6 +298,7 @@ export default function Shell({ me: hubMe, onLoggedOut }: { me: Me; onLoggedOut:
|
||||
{view === 'jobs' && <Jobs />}
|
||||
{view === 'updates' && <Updates />}
|
||||
{view === 'disks' && <Disks />}
|
||||
{view === 'hardware' && <Hardware />}
|
||||
{view === 'zfs' && <ZFS />}
|
||||
{view === 'files' && <Files onOpenInTerminal={runInTerminal} />}
|
||||
{termView && <TermTabs terms={ordered} active={active} creating={creating}
|
||||
@@ -323,7 +326,7 @@ export default function Shell({ me: hubMe, onLoggedOut }: { me: Me; onLoggedOut:
|
||||
<span>{machine ? `${title} · ` : ''}{me.version.startsWith('v') ? me.version : 'v' + me.version}</span>
|
||||
<span>up {fmtUptime(me.uptime)}</span>
|
||||
<span className="spacer" />
|
||||
<span className="muted">{view === 'widgets' ? 'Widgets' : view === 'docker' ? 'Docker' : view === 'alerts' ? 'Alerts' : view === 'services' ? 'Services' : view === 'jobs' ? 'Jobs' : view === 'updates' ? 'Updates' : view === 'disks' ? 'Disks' : view === 'zfs' ? 'ZFS' : view === 'usage' ? 'Usage' : view === 'files' ? 'Files' : view === 'procs' ? 'Processes' : view === 'machines' ? 'Machines' : view === 'kvm' ? 'KVM' : view === 'users' ? 'Users' : view === 'settings' ? 'Settings' : activeTerm ? activeTerm.name : ''}</span>
|
||||
<span className="muted">{view === 'widgets' ? 'Widgets' : view === 'docker' ? 'Docker' : view === 'alerts' ? 'Alerts' : view === 'services' ? 'Services' : view === 'jobs' ? 'Jobs' : view === 'updates' ? 'Updates' : view === 'disks' ? 'Disks' : view === 'hardware' ? 'Hardware' : view === 'zfs' ? 'ZFS' : view === 'usage' ? 'Usage' : view === 'files' ? 'Files' : view === 'procs' ? 'Processes' : view === 'machines' ? 'Machines' : view === 'kvm' ? 'KVM' : view === 'users' ? 'Users' : view === 'settings' ? 'Settings' : activeTerm ? activeTerm.name : ''}</span>
|
||||
</footer>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user