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.
This commit is contained in:
3 files changed
+67
-101
No files matched your search
@@ -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 });
|
||||
}
|
||||
|
||||
@@ -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<T>(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,
|
||||
}}
|
||||
|
||||
@@ -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, (ts: string) => string> = {
|
||||
live: formatTimeLive,
|
||||
historical: formatTime,
|
||||
};
|
||||
|
||||
function prepareRecords<T>(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%"
|
||||
|
||||
Reference in new issue
Block a user