diff --git a/web/src/components/filter/ReviewFilterGroup.tsx b/web/src/components/filter/ReviewFilterGroup.tsx index 5de010a3d..c518ce7ca 100644 --- a/web/src/components/filter/ReviewFilterGroup.tsx +++ b/web/src/components/filter/ReviewFilterGroup.tsx @@ -30,6 +30,7 @@ import MobileReviewSettingsDrawer, { } from "../overlay/MobileReviewSettingsDrawer"; import useOptimisticState from "@/hooks/use-optimistic-state"; import FilterSwitch from "./FilterSwitch"; +import { FilterList } from "@/types/filter"; const REVIEW_FILTERS = [ "cameras", @@ -53,7 +54,7 @@ type ReviewFilterGroupProps = { reviewSummary?: ReviewSummary; filter?: ReviewFilter; motionOnly: boolean; - filterLabels?: string[]; + filterList?: FilterList; onUpdateFilter: (filter: ReviewFilter) => void; setMotionOnly: React.Dispatch>; }; @@ -64,15 +65,15 @@ export default function ReviewFilterGroup({ reviewSummary, filter, motionOnly, - filterLabels, + filterList, onUpdateFilter, setMotionOnly, }: ReviewFilterGroupProps) { const { data: config } = useSWR("config"); const allLabels = useMemo(() => { - if (filterLabels) { - return filterLabels; + if (filterList?.labels) { + return filterList.labels; } if (!config) { @@ -99,14 +100,43 @@ export default function ReviewFilterGroup({ }); return [...labels].sort(); - }, [config, filterLabels, filter]); + }, [config, filterList, filter]); + + const allZones = useMemo(() => { + if (filterList?.zones) { + return filterList.zones; + } + + if (!config) { + return []; + } + + const zones = new Set(); + const cameras = filter?.cameras || Object.keys(config.cameras); + + cameras.forEach((camera) => { + if (camera == "birdseye") { + return; + } + const cameraConfig = config.cameras[camera]; + cameraConfig.review.alerts.required_zones.forEach((zone) => { + zones.add(zone); + }); + cameraConfig.review.detections.required_zones.forEach((zone) => { + zones.add(zone); + }); + }); + + return [...zones].sort(); + }, [config, filterList, filter]); const filterValues = useMemo( () => ({ cameras: Object.keys(config?.cameras || {}), labels: Object.values(allLabels || {}), + zones: Object.values(allZones || {}), }), - [config, allLabels], + [config, allLabels, allZones], ); const groups = useMemo(() => { @@ -189,12 +219,17 @@ export default function ReviewFilterGroup({ selectedLabels={filter?.labels} currentSeverity={currentSeverity} showAll={filter?.showAll == true} + allZones={filterValues.zones} + selectedZones={filter?.zones} setShowAll={(showAll) => { onUpdateFilter({ ...filter, showAll }); }} updateLabelFilter={(newLabels) => { onUpdateFilter({ ...filter, labels: newLabels }); }} + updateZoneFilter={(newZones) => + onUpdateFilter({ ...filter, zones: newZones }) + } /> )} {isMobile && mobileSettingsFeatures.length > 0 && ( @@ -495,21 +530,30 @@ type GeneralFilterButtonProps = { selectedLabels: string[] | undefined; currentSeverity?: ReviewSeverity; showAll: boolean; + allZones: string[]; + selectedZones?: string[]; setShowAll: (showAll: boolean) => void; updateLabelFilter: (labels: string[] | undefined) => void; + updateZoneFilter: (zones: string[] | undefined) => void; }; function GeneralFilterButton({ allLabels, selectedLabels, currentSeverity, showAll, + allZones, + selectedZones, setShowAll, updateLabelFilter, + updateZoneFilter, }: GeneralFilterButtonProps) { const [open, setOpen] = useState(false); const [currentLabels, setCurrentLabels] = useState( selectedLabels, ); + const [currentZones, setCurrentZones] = useState( + selectedZones, + ); const trigger = (