From baf2b09327a294fea672906f92e60c68d3172f9b Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Mon, 15 Jun 2026 17:30:39 +0200 Subject: [PATCH] refactor(beszel): consolidate hooks, extract helpers, deduplicate SSE envelope Consolidate 5 stat mapper useCallbacks and 6 series useMemos into single mappers/series objects. Extract statsWhenShown helper for repeated visibility guard pattern. Deduplicate SSE record envelope construction. Simplify prepareRecords with if/else. Remove unused gridColumns ternary with Number() indexing. --- .../src/beszel/beszel-integration.ts | 27 ++-- .../src/beszel-system-stats/component.tsx | 126 ++++++++---------- packages/widgets/src/beszel/_shared/chart.tsx | 15 +-- 3 files changed, 67 insertions(+), 101 deletions(-) diff --git a/packages/integrations/src/beszel/beszel-integration.ts b/packages/integrations/src/beszel/beszel-integration.ts index 425d4dad4..50f64668c 100644 --- a/packages/integrations/src/beszel/beszel-integration.ts +++ b/packages/integrations/src/beszel/beszel-integration.ts @@ -290,28 +290,17 @@ export class BeszelIntegration extends Integration { } if ("stats" in parsed) { - const stats: BeszelSystemStatsRecord = { - id: "", - system: systemId, - stats: parsed.stats as BeszelSystemStats, - type: "1m", - created: new Date().toISOString(), - updated: new Date().toISOString(), - }; + const now = new Date().toISOString(); + const envelope = { id: "", system: systemId, type: "1m" as const, created: now, updated: now }; + const stats: BeszelSystemStatsRecord = { ...envelope, stats: parsed.stats as BeszelSystemStats }; + let containerStats: BeszelContainerStatsRecord | null = null; - if ( + const hasContainers = parsed.container && Array.isArray(parsed.container) && - (parsed.container as BeszelContainerStats[]).length > 0 - ) { - containerStats = { - id: "", - system: systemId, - stats: parsed.container as BeszelContainerStats[], - type: "1m", - created: new Date().toISOString(), - updated: new Date().toISOString(), - }; + (parsed.container as BeszelContainerStats[]).length > 0; + if (hasContainers) { + containerStats = { ...envelope, stats: parsed.container as BeszelContainerStats[] }; } onMessage({ stats, containerStats }); } diff --git a/packages/widgets/src/beszel-system-stats/component.tsx b/packages/widgets/src/beszel-system-stats/component.tsx index 6e29370ac..720f9565c 100644 --- a/packages/widgets/src/beszel-system-stats/component.tsx +++ b/packages/widgets/src/beszel-system-stats/component.tsx @@ -36,6 +36,13 @@ const tooltipPercentTotal = makeTooltipProps(formatPercent, true); const tooltipBytesTotal = makeTooltipProps(formatStorageBytes, true); const CHART_HEIGHT = 180; +const MB = 1024 * 1024; +const gridColumns = [1, 2] as const; + +function statsWhenShown(show: boolean | undefined, data: T | undefined): T | undefined { + if (!show || !data) return undefined; + return data; +} export default function BeszelSystemStatsWidget({ options, @@ -88,89 +95,66 @@ export default function BeszelSystemStatsWidget({ activeStats = liveData; } - const cpuMap = useCallback((s: { cpu: number }) => ({ [t("chart.cpu.series")]: s.cpu }), [t]); - const memoryMap = useCallback( - (s: { mu: number; mb: number }) => ({ - [t("chart.memory.series")]: s.mu, - [t("chart.memory.cache")]: s.mb ?? 0, - }), - [t], - ); - const diskMap = useCallback((s: { du: number }) => ({ [t("chart.disk.series")]: s.du }), [t]); - const diskIOMap = useCallback( - (s: { dr?: number; dw?: number }) => ({ - [t("chart.diskIO.read")]: (s.dr ?? 0) * (1024 * 1024), - [t("chart.diskIO.write")]: (s.dw ?? 0) * (1024 * 1024), - }), - [t], - ); - const networkMap = useCallback( - (s: { ns: number; nr: number; b?: [number, number] }) => ({ - [t("chart.network.sent")]: s.b?.[0] ?? s.ns, - [t("chart.network.recv")]: s.b?.[1] ?? s.nr, + const mappers = useMemo( + () => ({ + cpu: (s: { cpu: number }) => ({ [t("chart.cpu.series")]: s.cpu }), + memory: (s: { mu: number; mb: number }) => ({ + [t("chart.memory.series")]: s.mu, + [t("chart.memory.cache")]: s.mb ?? 0, + }), + disk: (s: { du: number }) => ({ [t("chart.disk.series")]: s.du }), + diskIO: (s: { dr?: number; dw?: number }) => ({ + [t("chart.diskIO.read")]: (s.dr ?? 0) * MB, + [t("chart.diskIO.write")]: (s.dw ?? 0) * MB, + }), + network: (s: { ns: number; nr: number; b?: [number, number] }) => ({ + [t("chart.network.sent")]: s.b?.[0] ?? s.ns, + [t("chart.network.recv")]: s.b?.[1] ?? s.nr, + }), }), [t], ); - const cpuSeries = useMemo(() => [{ name: t("chart.cpu.series"), color: "teal.6" }], [t]); - const memorySeries = useMemo( - () => [ - { name: t("chart.memory.series"), color: "teal.5" }, - { name: t("chart.memory.cache"), color: "teal.8" }, - ], - [t], - ); - const diskSeries = useMemo(() => [{ name: t("chart.disk.series"), color: "grape.6" }], [t]); - const diskIOSeries = useMemo( - () => [ - { name: t("chart.diskIO.write"), color: "orange.6" }, - { name: t("chart.diskIO.read"), color: "blue.6" }, - ], - [t], - ); - const networkSeries = useMemo( - () => [ - { name: t("chart.network.sent"), color: "blue.6" }, - { name: t("chart.network.recv"), color: "teal.6" }, - ], + const series = useMemo( + () => ({ + cpu: [{ name: t("chart.cpu.series"), color: "teal.6" }], + memory: [ + { name: t("chart.memory.series"), color: "teal.5" }, + { name: t("chart.memory.cache"), color: "teal.8" }, + ], + disk: [{ name: t("chart.disk.series"), color: "grape.6" }], + diskIO: [ + { name: t("chart.diskIO.write"), color: "orange.6" }, + { name: t("chart.diskIO.read"), color: "blue.6" }, + ], + network: [ + { name: t("chart.network.sent"), color: "blue.6" }, + { name: t("chart.network.recv"), color: "teal.6" }, + ], + }), [t], ); const systemStats = activeStats?.systemStats; const containerStatsRaw = activeStats?.containerStats; - const cpuData = useSystemChartData((options.showCpu && systemStats) || undefined, cpuMap, isLive); - const memoryData = useSystemChartData((options.showMemory && systemStats) || undefined, memoryMap, isLive); - const diskData = useSystemChartData((options.showDisk && systemStats) || undefined, diskMap, isLive); - const diskIOData = useSystemChartData((options.showDiskIO && systemStats) || undefined, diskIOMap, isLive); - const networkData = useSystemChartData((options.showNetwork && systemStats) || undefined, networkMap, isLive); + const cpuData = useSystemChartData(statsWhenShown(options.showCpu, systemStats), mappers.cpu, isLive); + const memoryData = useSystemChartData(statsWhenShown(options.showMemory, systemStats), mappers.memory, isLive); + const diskData = useSystemChartData(statsWhenShown(options.showDisk, systemStats), mappers.disk, isLive); + const diskIOData = useSystemChartData(statsWhenShown(options.showDiskIO, systemStats), mappers.diskIO, isLive); + const networkData = useSystemChartData(statsWhenShown(options.showNetwork, systemStats), mappers.network, isLive); - const containerNames = useContainerNames((showDocker && containerStatsRaw) || undefined); - const dockerCpuData = useDockerChartData( - (options.showDockerCpu && containerStatsRaw) || undefined, - containerNames, - "cpu", - isLive, - ); - const dockerMemData = useDockerChartData( - (options.showDockerMemory && containerStatsRaw) || undefined, - containerNames, - "memory", - isLive, - ); - const dockerNetData = useDockerChartData( - (options.showDockerNetwork && containerStatsRaw) || undefined, - containerNames, - "network", - isLive, - ); + const containerNames = useContainerNames(statsWhenShown(showDocker, containerStatsRaw)); + const dockerCpuData = useDockerChartData(statsWhenShown(options.showDockerCpu, containerStatsRaw), containerNames, "cpu", isLive); + const dockerMemData = useDockerChartData(statsWhenShown(options.showDockerMemory, containerStatsRaw), containerNames, "memory", isLive); + const dockerNetData = useDockerChartData(statsWhenShown(options.showDockerNetwork, containerStatsRaw), containerNames, "network", isLive); const containerSeries = useMemo( () => containerNames.map((name, i) => ({ name, color: containerColors[i % containerColors.length] as string })), [containerNames], ); - const cols = width > 600 ? 2 : 1; + const cols = gridColumns[Number(width > 600)]; if (!systemsPending && !systemExists && systems.length > 0) { return ( @@ -260,7 +244,7 @@ export default function BeszelSystemStatsWidget({ chartProps={{ h: CHART_HEIGHT, data: cpuData, - series: cpuSeries, + series: series.cpu, yAxisFormatter: chartAxisFormatters.percent, yAxisDomain: CPU_Y_AXIS_DOMAIN, tooltipProps: tooltipPercent, @@ -276,7 +260,7 @@ export default function BeszelSystemStatsWidget({ h: CHART_HEIGHT, data: memoryData, type: "stacked", - series: memorySeries, + series: series.memory, yAxisFormatter: chartAxisFormatters.gb, tooltipProps: tooltipGB, }} @@ -290,7 +274,7 @@ export default function BeszelSystemStatsWidget({ chartProps={{ h: CHART_HEIGHT, data: diskData, - series: diskSeries, + series: series.disk, yAxisFormatter: chartAxisFormatters.gb, tooltipProps: tooltipGB, }} @@ -304,7 +288,7 @@ export default function BeszelSystemStatsWidget({ chartProps={{ h: CHART_HEIGHT, data: diskIOData, - series: diskIOSeries, + series: series.diskIO, yAxisFormatter: chartAxisFormatters.rate, tooltipProps: tooltipRate, }} @@ -318,7 +302,7 @@ export default function BeszelSystemStatsWidget({ chartProps={{ h: CHART_HEIGHT, data: networkData, - series: networkSeries, + series: series.network, yAxisFormatter: chartAxisFormatters.rate, tooltipProps: tooltipRate, }} diff --git a/packages/widgets/src/beszel/_shared/chart.tsx b/packages/widgets/src/beszel/_shared/chart.tsx index c5fc2b2f3..3938188f1 100644 --- a/packages/widgets/src/beszel/_shared/chart.tsx +++ b/packages/widgets/src/beszel/_shared/chart.tsx @@ -11,17 +11,11 @@ import type { BeszelContainerStatsRecord, BeszelSystemStatsRecord } from "@homar const formatTime = (timestamp: string) => dayjs(timestamp).format("HH:mm"); const formatTimeLive = (timestamp: string) => dayjs(timestamp).format("HH:mm:ss"); -const timeFormatters: Record string> = { - live: formatTimeLive, - historical: formatTime, -}; - function prepareRecords(records: T[], live: boolean) { - const mode = live ? "live" : "historical"; - return { - fmt: timeFormatters[mode] as (ts: string) => string, - ordered: live ? records : [...records].toReversed(), - }; + if (live) { + return { fmt: formatTimeLive, ordered: records }; + } + return { fmt: formatTime, ordered: [...records].toReversed() }; } const yAxisBase = { tickMargin: 0, tick: { fontSize: 10 } } as const; @@ -88,7 +82,6 @@ const BeszelAreaChart = memo( type={type} strokeWidth={1} fillOpacity={0.2} - areaChartProps={{}} withXAxis withYAxis w="100%"