MCPcopy Create free account
hub / github.com/ScriptedAlchemy/tracedecay / useGraphSearch

Function useGraphSearch

dashboard/graph/src/useGraphSearch.ts:6–90  ·  view source on GitHub ↗
({
  search,
  focusSymbol,
  onError,
  debounceMs = 180,
}: {
  search: (params: { q?: string; limit?: number; offset?: number }) => Promise<{ results: GraphNode[] }>;
  focusSymbol: (node: Pick<GraphNode, "id" | "name">) => void;
  onError: (message: string) => void;
  debounceMs?: number;
})

Source from the content-addressed store, hash-verified

4import type { GraphNode } from "./types";
5
6export function useGraphSearch({
7 search,
8 focusSymbol,
9 onError,
10 debounceMs = 180,
11}: {
12 search: (params: { q?: string; limit?: number; offset?: number }) => Promise<{ results: GraphNode[] }>;
13 focusSymbol: (node: Pick<GraphNode, "id" | "name">) => void;
14 onError: (message: string) => void;
15 debounceMs?: number;
16}) {
17 const [query, setQuery] = useState("");
18 const [results, setResults] = useState<GraphNode[]>([]);
19 const [searchOpen, setSearchOpen] = useState(false);
20 const searchTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
21 const searchSeq = useRef(makeSequence()).current;
22 const searchBoxRef = useRef<HTMLDivElement | null>(null);
23
24 const onQueryChange = useCallback((value: string) => {
25 setQuery(value);
26 if (searchTimer.current) clearTimeout(searchTimer.current);
27 if (!value.trim()) {
28 searchSeq.next();
29 setResults([]);
30 setSearchOpen(false);
31 return;
32 }
33 setSearchOpen(true);
34 searchTimer.current = setTimeout(() => {
35 const ticket = searchSeq.next();
36 search({ q: value, limit: 20 })
37 .then((payload) => {
38 if (searchSeq.isCurrent(ticket)) setResults(payload.results);
39 })
40 .catch((err) => {
41 if (searchSeq.isCurrent(ticket)) {
42 onError(err instanceof Error ? err.message : String(err));
43 }
44 });
45 }, debounceMs);
46 }, [debounceMs, onError, search, searchSeq]);
47
48 const onSearchKeyDown = useCallback(
49 (event: KeyboardEvent<HTMLElement>) => {
50 const box = searchBoxRef.current;
51 if (!box) return;
52 if (event.key === "Escape") {
53 event.preventDefault();
54 setSearchOpen(false);
55 box.querySelector<HTMLInputElement>("input")?.focus();
56 return;
57 }
58 if (!searchOpen || results.length === 0) return;
59 const buttons: HTMLButtonElement[] = Array.from(
60 box.querySelectorAll<HTMLButtonElement>(".tsg-search-pop button"),
61 );
62 const active = document.activeElement as HTMLElement | null;
63 const index = buttons.indexOf(active as HTMLButtonElement);

Callers 2

SearchHarnessFunction · 0.90
CodeGraphExplorerFunction · 0.90

Calls 4

makeSequenceFunction · 0.90
useStateFunction · 0.85
searchFunction · 0.50
fromMethod · 0.45

Tested by

no test coverage detected