import { useRouter } from "next/router"; import { type RefObject, useCallback, useEffect, useRef, useState } from "react"; import { api } from "~/utils/api"; import { NumberParam, useQueryParams } from "use-query-params"; import { useAppStore } from "~/state/store"; export const useExperiments = () => { const selectedProjectId = useAppStore((state) => state.selectedProjectId); return api.experiments.list.useQuery( { projectId: selectedProjectId ?? "" }, { enabled: !!selectedProjectId }, ); }; export const useExperiment = () => { const router = useRouter(); const experiment = api.experiments.get.useQuery( { id: router.query.id as string }, { enabled: !!router.query.id }, ); return experiment; }; export const useExperimentAccess = () => { return useExperiment().data?.access ?? { canView: false, canModify: false }; }; export const useDatasets = () => { const selectedProjectId = useAppStore((state) => state.selectedProjectId); return api.datasets.list.useQuery( { projectId: selectedProjectId ?? "" }, { enabled: !!selectedProjectId }, ); }; export const useDataset = () => { const router = useRouter(); const dataset = api.datasets.get.useQuery( { id: router.query.id as string }, { enabled: !!router.query.id }, ); return dataset; }; export const useDatasetEntries = () => { const dataset = useDataset(); const { page, pageSize } = usePageParams(); return api.datasetEntries.list.useQuery( { datasetId: dataset.data?.id ?? "", page, pageSize }, { enabled: dataset.data?.id != null }, ); }; type AsyncFunction = (...args: T) => Promise; export function useHandledAsyncCallback( callback: AsyncFunction, deps: React.DependencyList, ) { const [loading, setLoading] = useState(0); const [error, setError] = useState(null); const wrappedCallback = useCallback((...args: T) => { setLoading((loading) => loading + 1); setError(null); callback(...args) .catch((error) => { setError(error as Error); console.error(error); }) .finally(() => { setLoading((loading) => loading - 1); }); // eslint-disable-next-line react-hooks/exhaustive-deps }, deps); return [wrappedCallback, loading > 0, error] as const; } // Have to do this ugly thing to convince Next not to try to access `navigator` // on the server side at build time, when it isn't defined. export const useModifierKeyLabel = () => { const [label, setLabel] = useState(""); useEffect(() => { setLabel(navigator?.platform?.startsWith("Mac") ? "⌘" : "Ctrl"); }, []); return label; }; interface Dimensions { left: number; top: number; right: number; bottom: number; width: number; height: number; x: number; y: number; } // get dimensions of an element export const useElementDimensions = (): [RefObject, Dimensions | undefined] => { const ref = useRef(null); const [dimensions, setDimensions] = useState(); useEffect(() => { if (ref.current) { const observer = new ResizeObserver((entries) => { entries.forEach((entry) => { setDimensions(entry.contentRect); }); }); const observedRef = ref.current; observer.observe(observedRef); // Cleanup the observer on component unmount return () => { if (observedRef) { observer.unobserve(observedRef); } }; } }, []); return [ref, dimensions]; }; export const usePageParams = () => { const [pageParams, setPageParams] = useQueryParams({ page: NumberParam, pageSize: NumberParam, }); const { page, pageSize } = pageParams; return { page: page || 1, pageSize: pageSize || 10, setPageParams }; }; export const useScenarios = () => { const experiment = useExperiment(); const { page, pageSize } = usePageParams(); return api.scenarios.list.useQuery( { experimentId: experiment.data?.id ?? "", page, pageSize }, { enabled: experiment.data?.id != null }, ); }; export const useScenario = (scenarioId: string) => { return api.scenarios.get.useQuery({ id: scenarioId }); }; export const useVisibleScenarioIds = () => useScenarios().data?.scenarios.map((s) => s.id) ?? []; export const useSelectedProject = () => { const selectedProjectId = useAppStore((state) => state.selectedProjectId); return api.projects.get.useQuery( { id: selectedProjectId ?? "" }, { enabled: !!selectedProjectId }, ); }; export const useScenarioVars = () => { const experiment = useExperiment(); return api.scenarioVars.list.useQuery( { experimentId: experiment.data?.id ?? "" }, { enabled: experiment.data?.id != null }, ); }; export const useLoggedCalls = () => { const selectedProjectId = useAppStore((state) => state.selectedProjectId); const { page, pageSize } = usePageParams(); return api.loggedCalls.list.useQuery( { projectId: selectedProjectId ?? "", page, pageSize }, { enabled: !!selectedProjectId }, ); };