From 3c591ad8a9c503f683b5e195c607a39de66f982e Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:16:43 -0500 Subject: [PATCH] Explore snapshot and clip filter (#14439) * backend * add ToggleButton component * boolean type * frontend * allow setting filter in input * better padding on dual slider * use shadcn toggle group instead of custom component --- frigate/api/defs/events_query_parameters.py | 2 + frigate/api/event.py | 8 + web/src/components/input/InputWithTags.tsx | 10 ++ .../overlay/dialog/SearchFilterDialog.tsx | 169 +++++++++++++++++- web/src/pages/Explore.tsx | 4 + web/src/types/search.ts | 2 + web/src/views/search/SearchView.tsx | 2 + 7 files changed, 194 insertions(+), 3 deletions(-) diff --git a/frigate/api/defs/events_query_parameters.py b/frigate/api/defs/events_query_parameters.py index f4c98809c..fe1d2b8b2 100644 --- a/frigate/api/defs/events_query_parameters.py +++ b/frigate/api/defs/events_query_parameters.py @@ -44,6 +44,8 @@ class EventsSearchQueryParams(BaseModel): after: Optional[float] = None before: Optional[float] = None time_range: Optional[str] = DEFAULT_TIME_RANGE + has_clip: Optional[bool] = None + has_snapshot: Optional[bool] = None timezone: Optional[str] = "utc" min_score: Optional[float] = None max_score: Optional[float] = None diff --git a/frigate/api/event.py b/frigate/api/event.py index 892624e53..d15fe326c 100644 --- a/frigate/api/event.py +++ b/frigate/api/event.py @@ -359,6 +359,8 @@ def events_search(request: Request, params: EventsSearchQueryParams = Depends()) min_score = params.min_score max_score = params.max_score time_range = params.time_range + has_clip = params.has_clip + has_snapshot = params.has_snapshot # for similarity search event_id = params.event_id @@ -433,6 +435,12 @@ def events_search(request: Request, params: EventsSearchQueryParams = Depends()) if before: event_filters.append((Event.start_time < before)) + if has_clip is not None: + event_filters.append((Event.has_clip == has_clip)) + + if has_snapshot is not None: + event_filters.append((Event.has_snapshot == has_snapshot)) + if min_score is not None and max_score is not None: event_filters.append((Event.data["score"].between(min_score, max_score))) else: diff --git a/web/src/components/input/InputWithTags.tsx b/web/src/components/input/InputWithTags.tsx index 45dfd6c32..29a6f8a31 100644 --- a/web/src/components/input/InputWithTags.tsx +++ b/web/src/components/input/InputWithTags.tsx @@ -296,6 +296,14 @@ export default function InputWithTags({ ); } break; + case "has_snapshot": + if (!newFilters.has_snapshot) newFilters.has_snapshot = undefined; + newFilters.has_snapshot = value == "yes" ? 1 : 0; + break; + case "has_clip": + if (!newFilters.has_clip) newFilters.has_clip = undefined; + newFilters.has_clip = value == "yes" ? 1 : 0; + break; case "event_id": newFilters.event_id = value; break; @@ -341,6 +349,8 @@ export default function InputWithTags({ }`; } else if (filterType === "min_score" || filterType === "max_score") { return Math.round(Number(filterValues) * 100).toString() + "%"; + } else if (filterType === "has_clip" || filterType === "has_snapshot") { + return filterValues ? "Yes" : "No"; } else { return filterValues as string; } diff --git a/web/src/components/overlay/dialog/SearchFilterDialog.tsx b/web/src/components/overlay/dialog/SearchFilterDialog.tsx index ed091b350..fdc80eefd 100644 --- a/web/src/components/overlay/dialog/SearchFilterDialog.tsx +++ b/web/src/components/overlay/dialog/SearchFilterDialog.tsx @@ -25,6 +25,8 @@ import { DropdownMenuSeparator } from "@/components/ui/dropdown-menu"; import { cn } from "@/lib/utils"; import { DualThumbSlider } from "@/components/ui/slider"; import { Input } from "@/components/ui/input"; +import { Checkbox } from "@/components/ui/checkbox"; +import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; type SearchFilterDialogProps = { config?: FrigateConfig; @@ -63,6 +65,8 @@ export default function SearchFilterDialog({ currentFilter && (currentFilter.time_range || (currentFilter.min_score ?? 0) > 0.5 || + (currentFilter.has_snapshot ?? 0) === 1 || + (currentFilter.has_clip ?? 0) === 1 || (currentFilter.max_score ?? 1) < 1 || (currentFilter.zones?.length ?? 0) > 0 || (currentFilter.sub_labels?.length ?? 0) > 0), @@ -113,6 +117,26 @@ export default function SearchFilterDialog({ setCurrentFilter({ ...currentFilter, min_score: min, max_score: max }) } /> + + setCurrentFilter({ + ...currentFilter, + has_snapshot: + snapshot !== undefined ? (snapshot ? 1 : 0) : undefined, + has_clip: clip !== undefined ? (clip ? 1 : 0) : undefined, + }) + } + /> {isDesktop && }