diff --git a/packages/widgets/src/beszel-system-stats/component.tsx b/packages/widgets/src/beszel-system-stats/component.tsx
index 012abaff3..cb17fcc3f 100644
--- a/packages/widgets/src/beszel-system-stats/component.tsx
+++ b/packages/widgets/src/beszel-system-stats/component.tsx
@@ -105,6 +105,30 @@ export default function BeszelSystemStatsWidget({
[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" },
+ ],
+ [t],
+ );
+
const cpuData = useSystemChartData(activeStats?.systemStats, cpuMap, isLive);
const memoryData = useSystemChartData(activeStats?.systemStats, memoryMap, isLive);
const diskData = useSystemChartData(activeStats?.systemStats, diskMap, isLive);
@@ -116,10 +140,10 @@ export default function BeszelSystemStatsWidget({
const dockerMemData = useDockerChartData(activeStats?.containerStats, containerNames, "memory", isLive);
const dockerNetData = useDockerChartData(activeStats?.containerStats, containerNames, "network", isLive);
- const containerSeries = containerNames.map((name, i) => ({
- name,
- color: containerColors[i % containerColors.length] as string,
- }));
+ const containerSeries = useMemo(
+ () => containerNames.map((name, i) => ({ name, color: containerColors[i % containerColors.length] as string })),
+ [containerNames],
+ );
const cols = width > 600 ? 2 : 1;
@@ -209,7 +233,7 @@ export default function BeszelSystemStatsWidget({
@@ -238,7 +259,7 @@ export default function BeszelSystemStatsWidget({
@@ -250,10 +271,7 @@ export default function BeszelSystemStatsWidget({
@@ -265,10 +283,7 @@ export default function BeszelSystemStatsWidget({
diff --git a/packages/widgets/src/beszel/_shared/chart.tsx b/packages/widgets/src/beszel/_shared/chart.tsx
index 67b8957da..6db2b30f5 100644
--- a/packages/widgets/src/beszel/_shared/chart.tsx
+++ b/packages/widgets/src/beszel/_shared/chart.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useMemo } from "react";
+import { memo, useMemo, useRef } from "react";
import { Group, Stack, Text } from "@mantine/core";
import type { AreaChartProps } from "@mantine/charts";
import { AreaChart } from "@mantine/charts";
@@ -19,6 +19,8 @@ function prepareRecords(records: T[], live: boolean) {
}
const yAxisBase = { tickMargin: 0, tick: { fontSize: 10 } } as const;
+const activeDot = { r: 1, strokeWidth: 3 } as const;
+const hiddenDot = { r: 0, strokeWidth: 0 } as const;
interface ChartPanelProps {
title: string;
@@ -26,7 +28,7 @@ interface ChartPanelProps {
children: React.ReactNode;
}
-export const ChartPanel = ({ title, subtitle, children }: ChartPanelProps) => (
+export const ChartPanel = memo(({ title, subtitle, children }: ChartPanelProps) => (
@@ -40,14 +42,14 @@ export const ChartPanel = ({ title, subtitle, children }: ChartPanelProps) => (
{children}
-);
+));
type BeszelAreaChartProps = Omit & {
yAxisFormatter: (value: number) => string;
yAxisDomain?: [number, string];
};
-export const BeszelAreaChart = ({
+export const BeszelAreaChart = memo(({
yAxisFormatter,
yAxisDomain,
yAxisProps,
@@ -64,8 +66,8 @@ export const BeszelAreaChart = ({
type={type}
strokeWidth={1}
fillOpacity={0.2}
- activeDotProps={{ r: 1, strokeWidth: 3 }}
- dotProps={{ r: 0, strokeWidth: 0 }}
+ activeDotProps={activeDot}
+ dotProps={hiddenDot}
withXAxis
withYAxis
w="100%"
@@ -80,7 +82,7 @@ export const BeszelAreaChart = ({
}}
{...props}
/>
-);
+));
export const useSystemChartData = (
systemStats: BeszelSystemStatsRecord[] | undefined,
@@ -96,17 +98,23 @@ export const useSystemChartData = (
}));
}, [systemStats, mapFn, live]);
-export const useContainerNames = (containerStats: BeszelContainerStatsRecord[] | undefined, max = 15) =>
- useMemo(() => {
- if (!containerStats?.length) return [];
+export const useContainerNames = (containerStats: BeszelContainerStatsRecord[] | undefined, max = 15) => {
+ const prevRef = useRef([]);
+ return useMemo(() => {
+ if (!containerStats?.length) return prevRef.current.length === 0 ? prevRef.current : (prevRef.current = []);
const names = new Set();
for (const record of containerStats) {
for (const c of record.stats) {
names.add(c.n);
}
}
- return [...names].slice(0, max);
+ const next = [...names].slice(0, max);
+ const prev = prevRef.current;
+ if (prev.length === next.length && prev.every((n, i) => n === next[i])) return prev;
+ prevRef.current = next;
+ return next;
}, [containerStats, max]);
+};
type ContainerExtractor = (container: BeszelContainerStatsRecord["stats"][number] | undefined) => number;