Split Proxmox node card into system info (left) / storage (right)

Was a single stacked column (uptime/CPU/memory/swap, then the storage
table below); now a two-column layout within the card body — system
stats on the left, storage table (or the missing-permission hint) on
the right — so the card reads more like a dashboard tile at a glance.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
bobbanandClaude Sonnet 5 committed 2026-09-17 20:50:16 +02:00
1 parent 846953194c
commit 7b39b7be4d
1 file changed
+13 -11
+13 -11
View File
@@ -186,11 +186,12 @@ export default function Proxmox({ user }: { user: CurrentUser }) {
<div className="card-body"> <div className="card-body">
{n.error && <div className="alert alert-danger">{n.error}</div>} {n.error && <div className="alert alert-danger">{n.error}</div>}
<div className="row g-3"> <div className="row g-3">
<div className="col-sm-6"> <div className="col-md-6">
<div className="mb-3">
<div className="text-secondary small">Uptime</div> <div className="text-secondary small">Uptime</div>
<div>{formatUptime(n.uptime)}</div> <div>{formatUptime(n.uptime)}</div>
</div> </div>
<div className="col-sm-6"> <div className="mb-3">
<div className="text-secondary small">CPU</div> <div className="text-secondary small">CPU</div>
<div> <div>
{n.cpuUsagePercent !== null ? `${n.cpuUsagePercent.toFixed(1)}%` : "—"} {n.cpuUsagePercent !== null ? `${n.cpuUsagePercent.toFixed(1)}%` : "—"}
@@ -200,7 +201,7 @@ export default function Proxmox({ user }: { user: CurrentUser }) {
<div className="text-secondary small">Load: {n.loadAverage.map((l) => l.toFixed(2)).join(", ")}</div> <div className="text-secondary small">Load: {n.loadAverage.map((l) => l.toFixed(2)).join(", ")}</div>
)} )}
</div> </div>
<div className="col-sm-6"> <div className={n.swapTotalBytes ? "mb-3" : ""}>
<div className="text-secondary small">Memory</div> <div className="text-secondary small">Memory</div>
<div> <div>
{formatBytes(n.memUsedBytes)} / {formatBytes(n.memTotalBytes)} {formatBytes(n.memUsedBytes)} / {formatBytes(n.memTotalBytes)}
@@ -208,7 +209,7 @@ export default function Proxmox({ user }: { user: CurrentUser }) {
{usageBar(n.memUsedBytes, n.memTotalBytes)} {usageBar(n.memUsedBytes, n.memTotalBytes)}
</div> </div>
{!!n.swapTotalBytes && ( {!!n.swapTotalBytes && (
<div className="col-sm-6"> <div>
<div className="text-secondary small">Swap</div> <div className="text-secondary small">Swap</div>
<div> <div>
{formatBytes(n.swapUsedBytes)} / {formatBytes(n.swapTotalBytes)} {formatBytes(n.swapUsedBytes)} / {formatBytes(n.swapTotalBytes)}
@@ -218,9 +219,9 @@ export default function Proxmox({ user }: { user: CurrentUser }) {
)} )}
</div> </div>
{n.storages.length > 0 ? ( <div className="col-md-6">
<div className="mt-3">
<div className="text-secondary small mb-1">Storage</div> <div className="text-secondary small mb-1">Storage</div>
{n.storages.length > 0 ? (
<table className="table table-sm table-vcenter mb-0"> <table className="table table-sm table-vcenter mb-0">
<tbody> <tbody>
{n.storages.map((s) => ( {n.storages.map((s) => (
@@ -238,19 +239,20 @@ export default function Proxmox({ user }: { user: CurrentUser }) {
))} ))}
</tbody> </tbody>
</table> </table>
</div>
) : ( ) : (
!n.error && ( !n.error && (
<div className="text-secondary small mt-3"> <div className="text-secondary small">
No storage visible to this API token. Proxmox filters the storage list per-token — No storage visible to this API token. Proxmox filters the storage list
grant it <code>Datastore.Audit</code> (e.g. on <code>/storage</code>) to see disk per-token — grant it <code>Datastore.Audit</code> (e.g. on{" "}
usage here. <code>/storage</code>) to see disk usage here.
</div> </div>
) )
)} )}
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
))} ))}
{nodeStats?.length === 0 && ( {nodeStats?.length === 0 && (
<div className="col-12"> <div className="col-12">