Use query arg for search and remove unused recording opening

This commit is contained in:
Nicolas Mowen 2024-09-19 09:36:54 -06:00
parent de0019fe90
commit e6059a4982
4 changed files with 52 additions and 140 deletions

View File

@ -584,7 +584,9 @@ export default function InputWithTags({
)} )}
{Object.entries(filters).map(([filterType, filterValues]) => {Object.entries(filters).map(([filterType, filterValues]) =>
Array.isArray(filterValues) ? ( Array.isArray(filterValues) ? (
filterValues.map((value, index) => ( filterValues
.filter(() => filterType !== "query")
.map((value, index) => (
<span <span
key={`${filterType}-${index}`} key={`${filterType}-${index}`}
className="inline-flex items-center whitespace-nowrap rounded-full bg-green-100 px-2 py-0.5 text-sm capitalize text-green-800" className="inline-flex items-center whitespace-nowrap rounded-full bg-green-100 px-2 py-0.5 text-sm capitalize text-green-800"

View File

@ -1,30 +1,24 @@
import { useApiFilterArgs } from "@/hooks/use-api-filter"; import { useApiFilterArgs } from "@/hooks/use-api-filter";
import { useCameraPreviews } from "@/hooks/use-camera-previews"; import { useSearchEffect } from "@/hooks/use-overlay-state";
import { useOverlayState, useSearchEffect } from "@/hooks/use-overlay-state";
import { FrigateConfig } from "@/types/frigateConfig";
import { RecordingStartingPoint } from "@/types/record";
import { SearchFilter, SearchQuery, SearchResult } from "@/types/search"; import { SearchFilter, SearchQuery, SearchResult } from "@/types/search";
import { TimeRange } from "@/types/timeline";
import { RecordingView } from "@/views/recording/RecordingView";
import SearchView from "@/views/search/SearchView"; import SearchView from "@/views/search/SearchView";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import useSWR from "swr";
import useSWRInfinite from "swr/infinite"; import useSWRInfinite from "swr/infinite";
const API_LIMIT = 25; const API_LIMIT = 25;
export default function Explore() { export default function Explore() {
const { data: config } = useSWR<FrigateConfig>("config", {
revalidateOnFocus: false,
});
// search field handler // search field handler
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const [searchTerm, setSearchTerm] = useState("");
const [recording, setRecording] = const [searchFilter, setSearchFilter, searchSearchParams] =
useOverlayState<RecordingStartingPoint>("recording"); useApiFilterArgs<SearchFilter>();
const searchTerm = useMemo(
() => searchSearchParams?.["query"] || "",
[searchSearchParams],
);
// search filter // search filter
@ -36,9 +30,6 @@ export default function Explore() {
return searchTerm.split(":")[1]; return searchTerm.split(":")[1];
}, [searchTerm]); }, [searchTerm]);
const [searchFilter, setSearchFilter, searchSearchParams] =
useApiFilterArgs<SearchFilter>();
// search api // search api
useSearchEffect("similarity_search_id", (similarityId) => { useSearchEffect("similarity_search_id", (similarityId) => {
@ -49,7 +40,16 @@ export default function Explore() {
}); });
useEffect(() => { useEffect(() => {
setSearchTerm(search); if (!searchTerm && !search) {
return;
}
setSearchFilter({
...searchFilter,
query: search.length > 0 ? search : undefined,
});
// only update when search is updated
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [search]); }, [search]);
const searchQuery: SearchQuery = useMemo(() => { const searchQuery: SearchQuery = useMemo(() => {
@ -168,94 +168,6 @@ export default function Explore() {
} }
}, [isReachingEnd, isLoadingMore, setSize, size, searchResults, searchQuery]); }, [isReachingEnd, isLoadingMore, setSize, size, searchResults, searchQuery]);
// previews
const previewTimeRange = useMemo<TimeRange>(() => {
if (!searchResults) {
return { after: 0, before: 0 };
}
return {
after: Math.min(...searchResults.map((res) => res.start_time)),
before: Math.max(
...searchResults.map((res) => res.end_time ?? Date.now() / 1000),
),
};
}, [searchResults]);
const allPreviews = useCameraPreviews(previewTimeRange, {
autoRefresh: false,
fetchPreviews: searchResults != undefined,
});
// selection
const onOpenSearch = useCallback(
(item: SearchResult) => {
setRecording({
camera: item.camera,
startTime: item.start_time,
severity: "alert",
});
},
[setRecording],
);
const selectedReviewData = useMemo(() => {
if (!recording) {
return undefined;
}
if (!config) {
return undefined;
}
if (!searchResults) {
return undefined;
}
const allCameras = searchFilter?.cameras ?? Object.keys(config.cameras);
return {
camera: recording.camera,
start_time: recording.startTime,
allCameras: allCameras,
};
// previews will not update after item is selected
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [recording, searchResults]);
const selectedTimeRange = useMemo(() => {
if (!recording) {
return undefined;
}
const time = new Date(recording.startTime * 1000);
time.setUTCMinutes(0, 0, 0);
const start = time.getTime() / 1000;
time.setHours(time.getHours() + 2);
const end = time.getTime() / 1000;
return {
after: start,
before: end,
};
}, [recording]);
if (recording) {
if (selectedReviewData && selectedTimeRange) {
return (
<RecordingView
startCamera={selectedReviewData.camera}
startTime={selectedReviewData.start_time}
allCameras={selectedReviewData.allCameras}
allPreviews={allPreviews}
timeRange={selectedTimeRange}
updateFilter={setSearchFilter}
/>
);
}
} else {
return ( return (
<SearchView <SearchView
search={search} search={search}
@ -267,10 +179,8 @@ export default function Explore() {
setSimilaritySearch={(search) => setSearch(`similarity:${search.id}`)} setSimilaritySearch={(search) => setSearch(`similarity:${search.id}`)}
setSearchFilter={setSearchFilter} setSearchFilter={setSearchFilter}
onUpdateFilter={setSearchFilter} onUpdateFilter={setSearchFilter}
onOpenSearch={onOpenSearch}
loadMore={loadMore} loadMore={loadMore}
hasMore={!isReachingEnd} hasMore={!isReachingEnd}
/> />
); );
}
} }

View File

@ -29,6 +29,7 @@ export type SearchResult = {
}; };
export type SearchFilter = { export type SearchFilter = {
query?: string;
cameras?: string[]; cameras?: string[];
labels?: string[]; labels?: string[];
subLabels?: string[]; subLabels?: string[];

View File

@ -33,7 +33,6 @@ type SearchViewProps = {
setSimilaritySearch: (search: SearchResult) => void; setSimilaritySearch: (search: SearchResult) => void;
setSearchFilter: (filter: SearchFilter) => void; setSearchFilter: (filter: SearchFilter) => void;
onUpdateFilter: (filter: SearchFilter) => void; onUpdateFilter: (filter: SearchFilter) => void;
onOpenSearch: (item: SearchResult) => void;
loadMore: () => void; loadMore: () => void;
hasMore: boolean; hasMore: boolean;
}; };