diff --git a/web/src/components/overlay/SearchDetailDialog.tsx b/web/src/components/overlay/SearchDetailDialog.tsx index 61b295f57..ef722a29a 100644 --- a/web/src/components/overlay/SearchDetailDialog.tsx +++ b/web/src/components/overlay/SearchDetailDialog.tsx @@ -16,10 +16,12 @@ import { toast } from "sonner"; type SearchDetailDialogProps = { search?: SearchResult; setSearch: (search: SearchResult | undefined) => void; + setSimilarity?: () => void; }; export default function SearchDetailDialog({ search, setSearch, + setSimilarity, }: SearchDetailDialogProps) { const { data: config } = useSWR("config", { revalidateOnFocus: false, @@ -31,6 +33,7 @@ export default function SearchDetailDialog({ const [desc, setDesc] = useState(search?.description); + // we have to make sure the current selected search item stays in sync useEffect(() => setDesc(search?.description), [search]); const formattedDate = useFormattedTimestamp( @@ -129,7 +132,17 @@ export default function SearchDetailDialog({ : `${apiHost}api/events/${search.id}/thumbnail.jpg` } /> - +
diff --git a/web/src/pages/Search.tsx b/web/src/pages/Search.tsx index 59e43b70c..0bad38453 100644 --- a/web/src/pages/Search.tsx +++ b/web/src/pages/Search.tsx @@ -38,7 +38,13 @@ export default function Search() { // search api + const [similaritySearch, setSimilaritySearch] = useState(); + useEffect(() => { + if (similaritySearch) { + setSimilaritySearch(undefined); + } + if (searchTimeout) { clearTimeout(searchTimeout); } @@ -53,22 +59,43 @@ export default function Search() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [search]); - const { data: searchResults, isLoading } = useSWR( - searchTerm.length > 0 - ? [ - "events/search", - { - query: searchTerm, - cameras: searchSearchParams["cameras"], - labels: searchSearchParams["labels"], - zones: searchSearchParams["zones"], - before: searchSearchParams["before"], - after: searchSearchParams["after"], - include_thumbnails: 0, - }, - ] - : null, - ); + const searchQuery = useMemo(() => { + if (searchTerm.length == 0) { + return null; + } + + if (similaritySearch) { + return [ + "events/search", + { + query: similaritySearch.id, + cameras: searchSearchParams["cameras"], + labels: searchSearchParams["labels"], + zones: searchSearchParams["zones"], + before: searchSearchParams["before"], + after: searchSearchParams["after"], + include_thumbnails: 0, + search_type: "thumbnail", + }, + ]; + } + + return [ + "events/search", + { + query: searchTerm, + cameras: searchSearchParams["cameras"], + labels: searchSearchParams["labels"], + zones: searchSearchParams["zones"], + before: searchSearchParams["before"], + after: searchSearchParams["after"], + include_thumbnails: 0, + }, + ]; + }, [searchTerm, searchSearchParams, similaritySearch]); + + const { data: searchResults, isLoading } = + useSWR(searchQuery); const previewTimeRange = useMemo(() => { if (!searchResults) { @@ -164,6 +191,7 @@ export default function Search() { allPreviews={allPreviews} isLoading={isLoading} setSearch={setSearch} + setSimilaritySearch={setSimilaritySearch} onUpdateFilter={onUpdateFilter} onOpenSearch={onOpenSearch} /> diff --git a/web/src/views/search/SearchView.tsx b/web/src/views/search/SearchView.tsx index 5e6c82e16..b3d31ebf0 100644 --- a/web/src/views/search/SearchView.tsx +++ b/web/src/views/search/SearchView.tsx @@ -18,6 +18,7 @@ type SearchViewProps = { allPreviews?: Preview[]; isLoading: boolean; setSearch: (search: string) => void; + setSimilaritySearch: (search: SearchResult) => void; onUpdateFilter: (filter: SearchFilter) => void; onOpenSearch: (item: SearchResult) => void; }; @@ -29,6 +30,7 @@ export default function SearchView({ allPreviews, isLoading, setSearch, + setSimilaritySearch, onUpdateFilter, onOpenSearch, }: SearchViewProps) { @@ -52,7 +54,13 @@ export default function SearchView({ return (
- + setSimilaritySearch(searchDetail)) + } + />