({
loadNode,
loadNeighbors,
onError,
}: {
loadNode: (id: string) => Promise<GraphNodeResponse>;
loadNeighbors: (id: string) => Promise<GraphNeighborsResponse>;
onError: (message: string) => void;
})
| 3 | import type { GraphNeighborsResponse, GraphNode, GraphNodeResponse } from "./types"; |
| 4 | |
| 5 | export function useGraphInspection({ |
| 6 | loadNode, |
| 7 | loadNeighbors, |
| 8 | onError, |
| 9 | }: { |
| 10 | loadNode: (id: string) => Promise<GraphNodeResponse>; |
| 11 | loadNeighbors: (id: string) => Promise<GraphNeighborsResponse>; |
| 12 | onError: (message: string) => void; |
| 13 | }) { |
| 14 | const [selected, setSelected] = useState<GraphNode | null>(null); |
| 15 | const [neighbors, setNeighbors] = useState<GraphNeighborsResponse | null>(null); |
| 16 | const inspectSeq = useRef(makeSequence()).current; |
| 17 | |
| 18 | const inspect = useCallback(async (id: string) => { |
| 19 | const ticket = inspectSeq.next(); |
| 20 | try { |
| 21 | const [detail, nextNeighbors] = await Promise.all([ |
| 22 | loadNode(id), |
| 23 | loadNeighbors(id), |
| 24 | ]); |
| 25 | if (!inspectSeq.isCurrent(ticket)) return; |
| 26 | setSelected(detail.node); |
| 27 | setNeighbors(nextNeighbors); |
| 28 | } catch (err) { |
| 29 | if (inspectSeq.isCurrent(ticket)) { |
| 30 | onError(err instanceof Error ? err.message : String(err)); |
| 31 | } |
| 32 | } |
| 33 | }, [inspectSeq, loadNeighbors, loadNode, onError]); |
| 34 | |
| 35 | return { |
| 36 | selected, |
| 37 | neighbors, |
| 38 | setSelected, |
| 39 | setNeighbors, |
| 40 | inspect, |
| 41 | }; |
| 42 | } |
no test coverage detected