'use client'; import Image from "next/image"; import logo from "../../public/sb_logo_large_3.png" import { Input } from "@/components/ui/input" import { useEffect, useRef, useState } from "react"; import { useDebouncedCallback } from 'use-debounce'; import { Separator } from "@/components/ui/separator" import { useRouter } from "next/navigation"; import { useNonEmptyQueryParam } from "@/hooks/useNonEmptyQueryParam"; interface ZoekMatch { URL: string, FileName: string, LineNum: number, Fragments: { Pre: string, Match: string, Post: string }[] } interface ZoekFileMatch { FileName: string, Repo: string, Language: string, Matches: ZoekMatch[], URL: string, } interface ZoekResult { QueryStr: string, FileMatches: ZoekFileMatch[] | null, } interface ZoekSearchResponse { result: ZoekResult; } export default function Home() { const router = useRouter(); const defaultQuery = useNonEmptyQueryParam("query") ?? ""; const defaultNumResults = useNonEmptyQueryParam("numResults"); const [query, setQuery] = useState(defaultQuery); const [numResults, _setNumResults] = useState(defaultNumResults && !isNaN(Number(defaultNumResults)) ? Number(defaultNumResults) : 100); const [fileMatches, setFileMatches] = useState([]); /** * @note : when the user navigates backwards/forwards, the defaultQuery * will update, but the query state will not. This effect keeps things in * sync for that scenario. */ useEffect(() => { setQuery(defaultQuery); }, [defaultQuery]); return (
{"Sourcebot setQuery(query)} onSearchResult={(result) => { setFileMatches(result?.FileMatches ?? []); router.push(`?query=${query}&numResults=${numResults}`); }} />

Results for: {fileMatches.length} files

{fileMatches.map((match, index) => ( ))}
); } interface SearchBarProps { query: string; numResults: number; onQueryChange: (query: string) => void; onSearchResult: (result?: ZoekResult) => void, } const SearchBar = ({ query, numResults, onQueryChange, onSearchResult, }: SearchBarProps) => { const SEARCH_DEBOUNCE_MS = 200; const search = useDebouncedCallback((query: string) => { if (query === "") { onSearchResult(undefined); return; } console.log('making query...'); fetch(`http://localhost:3000/zoekt/search?query=${query}&numResults=${numResults}`) .then(response => response.json()) .then(({ data }: { data: ZoekSearchResponse }) => { onSearchResult(data.result); }) // @todo : error handling .catch(error => { console.error('Error:', error); }).finally(() => { console.log('done making query'); }) }, SEARCH_DEBOUNCE_MS); useEffect(() => { search(query); }, [query]); return ( { const query = e.target.value; onQueryChange(query); }} /> ) } interface FileMatchProps { match: ZoekFileMatch; } const FileMatch = ({ match, }: FileMatchProps) => { return (

{match.Repo} | {match.FileName}

); }