This commit is contained in:
henrygd
2026-04-21 15:44:08 -04:00
parent 48fe407292
commit e931165566
2 changed files with 20 additions and 20 deletions

View File

@@ -13,7 +13,7 @@ import { TemperatureChart, BatteryChart } from "./system/charts/sensor-charts"
import { GpuPowerChart, GpuDetailCharts } from "./system/charts/gpu-charts" import { GpuPowerChart, GpuDetailCharts } from "./system/charts/gpu-charts"
import { LazyContainersTable, LazySmartTable, LazySystemdTable, LazyNetworkProbesTable } from "./system/lazy-tables" import { LazyContainersTable, LazySmartTable, LazySystemdTable, LazyNetworkProbesTable } from "./system/lazy-tables"
import { LoadAverageChart } from "./system/charts/load-average-chart" import { LoadAverageChart } from "./system/charts/load-average-chart"
import { ContainerIcon, CpuIcon, HardDriveIcon, TerminalSquareIcon } from "lucide-react" import { ContainerIcon, CpuIcon, HardDriveIcon, NetworkIcon, TerminalSquareIcon } from "lucide-react"
import { GpuIcon } from "../ui/icons" import { GpuIcon } from "../ui/icons"
import SystemdTable from "../systemd-table/systemd-table" import SystemdTable from "../systemd-table/systemd-table"
import ContainersTable from "../containers-table/containers-table" import ContainersTable from "../containers-table/containers-table"
@@ -65,7 +65,7 @@ export default memo(function SystemDetail({ id }: { id: string }) {
const hasGpu = hasGpuData || hasGpuPowerData const hasGpu = hasGpuData || hasGpuPowerData
// keep tabsRef in sync for keyboard navigation // keep tabsRef in sync for keyboard navigation
const tabs = ["core", "disk"] const tabs = ["core", "network", "disk"]
if (hasGpu) tabs.push("gpu") if (hasGpu) tabs.push("gpu")
if (hasContainers) tabs.push("containers") if (hasContainers) tabs.push("containers")
if (hasSystemd) tabs.push("services") if (hasSystemd) tabs.push("services")
@@ -159,6 +159,10 @@ export default memo(function SystemDetail({ id }: { id: string }) {
<CpuIcon className="size-3.5" /> <CpuIcon className="size-3.5" />
<Trans context="Core system metrics">Core</Trans> <Trans context="Core system metrics">Core</Trans>
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="network" className="w-full flex items-center gap-1.5">
<NetworkIcon className="size-3.5" />
<Trans>Network</Trans>
</TabsTrigger>
<TabsTrigger value="disk" className="w-full flex items-center gap-1.5"> <TabsTrigger value="disk" className="w-full flex items-center gap-1.5">
<HardDriveIcon className="size-3.5" /> <HardDriveIcon className="size-3.5" />
<Trans>Disk</Trans> <Trans>Disk</Trans>
@@ -186,15 +190,24 @@ export default memo(function SystemDetail({ id }: { id: string }) {
<TabsContent value="core" forceMount className={activeTab === "core" ? "contents" : "hidden"}> <TabsContent value="core" forceMount className={activeTab === "core" ? "contents" : "hidden"}>
<div className="grid xl:grid-cols-2 gap-4"> <div className="grid xl:grid-cols-2 gap-4">
<CpuChart {...coreProps} /> <CpuChart {...coreProps} />
<MemoryChart {...coreProps} />
<LoadAverageChart chartData={chartData} grid={grid} dataEmpty={dataEmpty} /> <LoadAverageChart chartData={chartData} grid={grid} dataEmpty={dataEmpty} />
<BandwidthChart {...coreProps} systemStats={systemStats} /> <MemoryChart {...coreProps} />
<SwapChart chartData={chartData} grid={grid} dataEmpty={dataEmpty} systemStats={systemStats} />
<TemperatureChart {...coreProps} setPageBottomExtraMargin={setPageBottomExtraMargin} /> <TemperatureChart {...coreProps} setPageBottomExtraMargin={setPageBottomExtraMargin} />
<BatteryChart {...coreProps} /> <BatteryChart {...coreProps} />
<SwapChart chartData={chartData} grid={grid} dataEmpty={dataEmpty} systemStats={systemStats} />
{pageBottomExtraMargin > 0 && <div style={{ marginBottom: pageBottomExtraMargin }}></div>} {pageBottomExtraMargin > 0 && <div style={{ marginBottom: pageBottomExtraMargin }}></div>}
</div> </div>
<LazyNetworkProbesTable systemId={system.id} systemData={systemData} /> </TabsContent>
<TabsContent value="network" forceMount className={activeTab === "network" ? "contents" : "hidden"}>
{mountedTabs.has("network") && (
<>
<div className="grid xl:grid-cols-2 gap-4">
<BandwidthChart {...coreProps} systemStats={systemStats} />
</div>
<LazyNetworkProbesTable systemId={system.id} systemData={systemData} />
</>
)}
</TabsContent> </TabsContent>
<TabsContent value="disk" forceMount className={activeTab === "disk" ? "contents" : "hidden"}> <TabsContent value="disk" forceMount className={activeTab === "disk" ? "contents" : "hidden"}>

View File

@@ -19,7 +19,6 @@ import { chartTimeData, listen, parseSemVer, useBrowserStorage } from "@/lib/uti
import type { import type {
ChartData, ChartData,
ContainerStatsRecord, ContainerStatsRecord,
NetworkProbeStatsRecord,
SystemDetailsRecord, SystemDetailsRecord,
SystemInfo, SystemInfo,
SystemRecord, SystemRecord,
@@ -49,7 +48,6 @@ export function useSystemData(id: string) {
const [system, setSystem] = useState({} as SystemRecord) const [system, setSystem] = useState({} as SystemRecord)
const [systemStats, setSystemStats] = useState([] as SystemStatsRecord[]) const [systemStats, setSystemStats] = useState([] as SystemStatsRecord[])
const [containerData, setContainerData] = useState([] as ChartData["containerData"]) const [containerData, setContainerData] = useState([] as ChartData["containerData"])
const [probeStats, setProbeStats] = useState([] as NetworkProbeStatsRecord[])
const persistChartTime = useRef(false) const persistChartTime = useRef(false)
const statsRequestId = useRef(0) const statsRequestId = useRef(0)
const [chartLoading, setChartLoading] = useState(true) const [chartLoading, setChartLoading] = useState(true)
@@ -121,34 +119,24 @@ export function useSystemData(id: string) {
pb.realtime pb.realtime
.subscribe( .subscribe(
`rt_metrics`, `rt_metrics`,
(data: { (data: { container: ContainerStatsRecord[]; info: SystemInfo; stats: SystemStats }) => {
container: ContainerStatsRecord[]
info: SystemInfo
stats: SystemStats
probes?: NetworkProbeStatsRecord["stats"]
}) => {
const now = Date.now() const now = Date.now()
const statsPoint = { created: now, stats: data.stats } as SystemStatsRecord const statsPoint = { created: now, stats: data.stats } as SystemStatsRecord
const containerPoint = const containerPoint =
data.container?.length > 0 data.container?.length > 0
? makeContainerPoint(now, data.container as unknown as ContainerStatsRecord["stats"]) ? makeContainerPoint(now, data.container as unknown as ContainerStatsRecord["stats"])
: null : null
const probePoint: NetworkProbeStatsRecord | null = data.probes ? { stats: data.probes, created: now } : null
// on first message, make sure we clear out data from other time periods // on first message, make sure we clear out data from other time periods
if (isFirst) { if (isFirst) {
isFirst = false isFirst = false
setSystemStats([statsPoint]) setSystemStats([statsPoint])
setContainerData(containerPoint ? [containerPoint] : []) setContainerData(containerPoint ? [containerPoint] : [])
setProbeStats(probePoint ? [probePoint] : [])
return return
} }
setSystemStats((prev) => appendData(prev, [statsPoint], 1000, 60)) setSystemStats((prev) => appendData(prev, [statsPoint], 1000, 60))
if (containerPoint) { if (containerPoint) {
setContainerData((prev) => appendData(prev, [containerPoint], 1000, 60)) setContainerData((prev) => appendData(prev, [containerPoint], 1000, 60))
} }
if (probePoint) {
setProbeStats((prev) => appendData(prev, [probePoint], 1000, 60))
}
}, },
{ query: { system: system.id } } { query: { system: system.id } }
) )
@@ -334,7 +322,6 @@ export function useSystemData(id: string) {
system, system,
systemStats, systemStats,
containerData, containerData,
probeStats,
chartData, chartData,
containerChartConfigs, containerChartConfigs,
details, details,