fix(beszel): address final review findings
- Gate stats/live queries on systems loading state to prevent stale ID requests during initial load - Simplify useLiveStats: functional setState, stable integrationKey dep, remove unused includeDocker param - Extract prepareRecords helper to deduplicate chart ordering logic - Remove stale timePeriod type cast
This commit is contained in:
3 files changed
+28
-22
No files matched your search
@@ -44,7 +44,7 @@ export default function BeszelSystemStatsWidget({
|
||||
setOptions,
|
||||
}: WidgetComponentProps<"beszelSystemStats">) {
|
||||
const t = useScopedI18n("widget.beszelSystemStats");
|
||||
const { data: systemsResult = [] } = clientApi.widget.beszel.getSystems.useQuery(
|
||||
const { data: systemsResult = [], isPending: systemsPending } = clientApi.widget.beszel.getSystems.useQuery(
|
||||
{ integrationIds },
|
||||
{ staleTime: 30 * 1000 },
|
||||
);
|
||||
@@ -56,7 +56,8 @@ export default function BeszelSystemStatsWidget({
|
||||
|
||||
const selectedSystem = options.systemId || systems[0]?.value || "";
|
||||
const selectedLabel = systems.find((s) => s.value === selectedSystem)?.label;
|
||||
const systemExists = systems.length === 0 || systems.some((s) => s.value === selectedSystem);
|
||||
const systemExists = systems.some((s) => s.value === selectedSystem);
|
||||
const systemReady = !systemsPending && (selectedSystem === "" || systemExists);
|
||||
|
||||
const handleSelectSystem = useCallback(
|
||||
(value: string) => setOptions({ newOptions: { systemId: value } }),
|
||||
@@ -70,13 +71,13 @@ export default function BeszelSystemStatsWidget({
|
||||
{
|
||||
integrationIds,
|
||||
systemId: selectedSystem,
|
||||
timePeriod: options.timePeriod as "1h" | "12h" | "24h" | "1w" | "30d",
|
||||
timePeriod: options.timePeriod,
|
||||
includeDocker: showDocker,
|
||||
},
|
||||
{ staleTime: 30 * 1000, enabled: !isLive && systemExists && selectedSystem !== "" },
|
||||
{ staleTime: 30 * 1000, enabled: !isLive && systemReady && selectedSystem !== "" },
|
||||
);
|
||||
|
||||
const liveData = useLiveStats(integrationIds, selectedSystem, showDocker, isLive && systemExists);
|
||||
const liveData = useLiveStats(integrationIds, selectedSystem, isLive && systemReady);
|
||||
|
||||
const activeStats = isLive ? liveData : statsResult;
|
||||
|
||||
@@ -122,7 +123,7 @@ export default function BeszelSystemStatsWidget({
|
||||
|
||||
const cols = width > 600 ? 2 : 1;
|
||||
|
||||
if (!systemExists && systems.length > 0) {
|
||||
if (!systemsPending && !systemExists && systems.length > 0) {
|
||||
return (
|
||||
<Center h="100%">
|
||||
<Stack align="center" gap="sm" p="md">
|
||||
|
||||
@@ -11,6 +11,13 @@ 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");
|
||||
|
||||
function prepareRecords<T>(records: T[], live: boolean) {
|
||||
return {
|
||||
fmt: live ? formatTimeLive : formatTime,
|
||||
ordered: live ? records : [...records].toReversed(),
|
||||
};
|
||||
}
|
||||
|
||||
const yAxisBase = { tickMargin: 0, tick: { fontSize: 10 } } as const;
|
||||
|
||||
interface ChartPanelProps {
|
||||
@@ -82,8 +89,7 @@ export const useSystemChartData = (
|
||||
) =>
|
||||
useMemo(() => {
|
||||
if (!systemStats) return [];
|
||||
const fmt = live ? formatTimeLive : formatTime;
|
||||
const ordered = live ? systemStats : [...systemStats].toReversed();
|
||||
const { fmt, ordered } = prepareRecords(systemStats, live);
|
||||
return ordered.map((r) => ({
|
||||
time: fmt(r.created),
|
||||
...mapFn(r.stats),
|
||||
@@ -123,8 +129,7 @@ export const useDockerChartData = (
|
||||
if (!containerStats?.length) return [];
|
||||
const extract = defaultContainerExtractors[metric];
|
||||
if (!extract) return [];
|
||||
const fmt = live ? formatTimeLive : formatTime;
|
||||
const ordered = live ? containerStats : [...containerStats].toReversed();
|
||||
const { fmt, ordered } = prepareRecords(containerStats, live);
|
||||
return ordered.map((record) => {
|
||||
const point: Record<string, unknown> = { time: fmt(record.created) };
|
||||
for (const name of containerNames) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import type { BeszelContainerStatsRecord, BeszelSystemStatsRecord } from "@homarr/integrations/types";
|
||||
@@ -12,29 +12,29 @@ interface LiveStatsData {
|
||||
containerStats: BeszelContainerStatsRecord[];
|
||||
}
|
||||
|
||||
export const useLiveStats = (integrationIds: string[], systemId: string, includeDocker: boolean, enabled: boolean) => {
|
||||
const bufferRef = useRef<LiveStatsData>({ systemStats: [], containerStats: [] });
|
||||
export const useLiveStats = (integrationIds: string[], systemId: string, enabled: boolean) => {
|
||||
const [data, setData] = useState<LiveStatsData | null>(null);
|
||||
|
||||
const integrationKey = integrationIds.join(",");
|
||||
useEffect(() => {
|
||||
bufferRef.current = { systemStats: [], containerStats: [] };
|
||||
setData(null);
|
||||
}, [systemId, enabled, ...integrationIds]);
|
||||
}, [systemId, enabled, integrationKey]);
|
||||
|
||||
const onData = useCallback(
|
||||
(incoming: { stats: BeszelSystemStatsRecord; containerStats: BeszelContainerStatsRecord | null }) => {
|
||||
const buf = bufferRef.current;
|
||||
buf.systemStats = [...buf.systemStats, incoming.stats].slice(-MAX_BUFFER);
|
||||
if (incoming.containerStats) {
|
||||
buf.containerStats = [...buf.containerStats, incoming.containerStats].slice(-MAX_BUFFER);
|
||||
}
|
||||
setData({ ...buf });
|
||||
setData((prev) => {
|
||||
const systemStats = [...(prev?.systemStats ?? []), incoming.stats].slice(-MAX_BUFFER);
|
||||
const containerStats = incoming.containerStats
|
||||
? [...(prev?.containerStats ?? []), incoming.containerStats].slice(-MAX_BUFFER)
|
||||
: prev?.containerStats ?? [];
|
||||
return { systemStats, containerStats };
|
||||
});
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
clientApi.widget.beszel.subscribeSystemStats.useSubscription(
|
||||
{ integrationIds, systemId, includeDocker },
|
||||
{ integrationIds, systemId },
|
||||
{ enabled: enabled && systemId !== "", onData },
|
||||
);
|
||||
|
||||
|
||||
Reference in new issue
Block a user