"use client"; import { useCallback, useMemo, useRef } from "react"; import { Box, Button, Center, Group, Loader, Menu, ScrollArea, Select, Stack, Text } from "@mantine/core"; import { IconQuestionMark, IconServer, IconServerOff } from "@tabler/icons-react"; import { getQueryKey } from "@trpc/react-query"; import { clientApi } from "@homarr/api/client"; import { useSession } from "@homarr/auth/client"; import { constructBoardPermissions } from "@homarr/auth/shared"; import { useOptionalBoard } from "@homarr/boards/context"; import { showErrorNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; import { iconSizes, zoomCompensatedSize } from "@homarr/ui"; import classes from "./component.module.css"; import type { WidgetComponentProps } from "../definition"; import { useWidgetRuntimeQueries } from "../runtime-hooks"; import type { BeszelTimePeriod } from "../beszel/_shared/chart"; import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; import { getUsableWidgetQueryData } from "../common/query-state"; import { BeszelStatsView } from "../beszel/_shared/stats-view"; import { createBeszelSystemChoices, resolveBeszelSystemChoice } from "./selection"; export default function BeszelSystemStatsWidget({ options, integrationIds, isEditMode, width, boardId, itemId, setOptions, widgetRuntimeRef, }: WidgetComponentProps<"beszelSystemStats">) { const t = useI18n("widget.beszelSystemStats"); const tBeszel = useI18n("widget.beszel"); const board = useOptionalBoard(); const { data: session } = useSession(); const hasChangeAccess = board ? constructBoardPermissions(board, session).hasChangeAccess : false; const selectionSavePendingRef = useRef(false); const { mutate: saveItemOptions, isPending: isSelectionSavePending } = clientApi.widget.options.saveItemOptions.useMutation({ onError: () => showErrorNotification({ title: t("error.selectionSaveTitle"), message: t("error.selectionSaveMessage"), }), }); const systemsQuery = clientApi.widget.beszel.getSystems.useQuery({ integrationIds }); const systemsData = getUsableWidgetQueryData(systemsQuery); const systemsResult = useMemo(() => systemsData ?? [], [systemsData]); const { isPending: systemsPending } = systemsQuery; const systems = useMemo(() => createBeszelSystemChoices(systemsResult), [systemsResult]); const selectedSystem = resolveBeszelSystemChoice(systems, options.systemId); const selectedValue = selectedSystem?.value ?? ""; const selectedLabel = selectedSystem?.label; const systemExists = selectedSystem !== undefined; const includeDocker = options.showDockerCpu || options.showDockerMemory || options.showDockerNetwork; const periodOptions = [ { value: "1m", label: t("period.live") }, { value: "1h", label: t("period.oneHour") }, { value: "12h", label: t("period.twelveHours") }, { value: "24h", label: t("period.oneDay") }, { value: "1w", label: t("period.oneWeek") }, { value: "30d", label: t("period.thirtyDays") }, ]; useWidgetRuntimeQueries( widgetRuntimeRef, selectedSystem && options.timePeriod !== "1m" ? [ getQueryKey( clientApi.widget.beszel.getSystemStats, { integrationIds: [selectedSystem.integrationId], systemId: selectedSystem.systemId, timePeriod: options.timePeriod as BeszelTimePeriod, includeDocker, }, "query", ), ] : [], ); const handleSelectSystem = useCallback( (value: string) => { if (selectionSavePendingRef.current) return; const previousValue = options.systemId; setOptions({ newOptions: { systemId: value } }); if (hasChangeAccess && boardId && itemId) { selectionSavePendingRef.current = true; saveItemOptions( { boardId, itemId, newOptions: { systemId: value } }, { onError: () => { setOptions({ newOptions: { systemId: previousValue } }); }, onSettled: () => { selectionSavePendingRef.current = false; }, }, ); } }, [boardId, hasChangeAccess, itemId, options.systemId, saveItemOptions, setOptions], ); const handleTimePeriod = useCallback( (value: string) => { if (selectionSavePendingRef.current) return; const timePeriod = value as BeszelTimePeriod; const previousValue = options.timePeriod; setOptions({ newOptions: { timePeriod } }); if (hasChangeAccess && boardId && itemId) { selectionSavePendingRef.current = true; saveItemOptions( { boardId, itemId, newOptions: { timePeriod } }, { onError: () => { setOptions({ newOptions: { timePeriod: previousValue } }); }, onSettled: () => { selectionSavePendingRef.current = false; }, }, ); } }, [boardId, hasChangeAccess, itemId, options.timePeriod, saveItemOptions, setOptions], ); if (systemsPending) return (