"use client"; import dynamic from "next/dynamic"; import { Button, Center, Loader, Stack, Text } from "@mantine/core"; import { IconAlertTriangle } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { useScopedI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../definition"; const CustomJsxDisplay = dynamic(() => import("./custom-jsx-display"), { ssr: false }); export default function CustomApiWidget({ options, itemId, isEditMode, removeItem, }: WidgetComponentProps<"customApi">) { const t = useScopedI18n("widget.customApi"); const tCustomJsx = useScopedI18n("widget.customApi.customJsx"); const definitionId = options.definitionId; const safeInterval = Number.isFinite(options.refreshInterval) ? options.refreshInterval : 30; const intervalMs = Math.max(1_000, safeInterval * 1_000); const query = clientApi.widget.customApi.getData.useQuery( { itemId: itemId ?? "" }, { enabled: Boolean(itemId) && Boolean(definitionId), refetchInterval: (currentQuery) => (isTerminalDefinitionError(currentQuery.state.error) ? false : intervalMs), retry: (failureCount, error) => !isTerminalDefinitionError(error) && failureCount < 3, }, ); if (!definitionId) { return ; } if (isEditMode && !itemId) return ; if (query.isLoading) return (
); if (query.error) { const errorCode = query.error.data?.code; if (isEditMode && errorCode === "NOT_FOUND") { return ; } const isUnavailable = errorCode === "NOT_FOUND" || errorCode === "FORBIDDEN"; return ( ); } if (!query.data) return null; return ( ); } function isTerminalDefinitionError(error: unknown): boolean { if (!error || typeof error !== "object" || !("data" in error)) return false; const data = error.data; if (!data || typeof data !== "object" || !("code" in data)) return false; return data.code === "NOT_FOUND" || data.code === "FORBIDDEN" || data.code === "PRECONDITION_FAILED"; } function Unavailable({ message, danger = false, removeLabel, onRemove, }: { message: string; danger?: boolean; removeLabel?: string; onRemove?: () => void; }) { return (
{message} {removeLabel && onRemove && ( )}
); }