From 6805e3c995a55df96acbc4e194bed87b7c5f6861 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Tue, 2 Jun 2026 13:44:38 -0600 Subject: [PATCH] Add field to control if cameras show in review --- frigate/config/camera/ui.py | 5 ++++ .../components/filter/ReviewFilterGroup.tsx | 12 ++++++---- web/src/pages/Events.tsx | 24 ++++++++++++------- web/src/types/frigateConfig.ts | 1 + web/src/views/recording/RecordingView.tsx | 9 +++++-- 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/frigate/config/camera/ui.py b/frigate/config/camera/ui.py index 5e903b2543..7db1c537fa 100644 --- a/frigate/config/camera/ui.py +++ b/frigate/config/camera/ui.py @@ -16,3 +16,8 @@ class CameraUiConfig(FrigateBaseModel): title="Show in UI", description="Toggle whether this camera is visible everywhere in the Frigate UI. Disabling this will require manually editing the config to view this camera in the UI again.", ) + review: bool = Field( + default=True, + title="Show in review", + description="Toggle whether this camera is visible in review (the review page and its camera filter, motion review, and the history view).", + ) diff --git a/web/src/components/filter/ReviewFilterGroup.tsx b/web/src/components/filter/ReviewFilterGroup.tsx index 76274ec3f2..3c75dde630 100644 --- a/web/src/components/filter/ReviewFilterGroup.tsx +++ b/web/src/components/filter/ReviewFilterGroup.tsx @@ -144,11 +144,13 @@ export default function ReviewFilterGroup({ const filterValues = useMemo( () => ({ - cameras: allowedCameras.sort( - (a, b) => - (config?.cameras[a]?.ui?.order ?? 0) - - (config?.cameras[b]?.ui?.order ?? 0), - ), + cameras: allowedCameras + .filter((cam) => config?.cameras[cam]?.ui?.review !== false) + .sort( + (a, b) => + (config?.cameras[a]?.ui?.order ?? 0) - + (config?.cameras[b]?.ui?.order ?? 0), + ), labels: Object.values(allLabels || {}), zones: Object.values(allZones || {}), }), diff --git a/web/src/pages/Events.tsx b/web/src/pages/Events.tsx index 393f895b0e..a1aa4c79ef 100644 --- a/web/src/pages/Events.tsx +++ b/web/src/pages/Events.tsx @@ -70,13 +70,15 @@ export default function Events() { undefined, ); - const motionSearchCameras = useMemo(() => { + const reviewCameras = useMemo(() => { if (!config?.cameras) { return [] as string[]; } - return Object.keys(config.cameras).filter((cam) => - allowedCameras.includes(cam), + return Object.keys(config.cameras).filter( + (cam) => + allowedCameras.includes(cam) && + config.cameras[cam]?.ui?.review !== false, ); }, [allowedCameras, config?.cameras]); @@ -85,12 +87,12 @@ export default function Events() { return null; } - if (motionSearchCameras.includes(motionSearchCamera)) { + if (reviewCameras.includes(motionSearchCamera)) { return motionSearchCamera; } - return motionSearchCameras[0] ?? null; - }, [motionSearchCamera, motionSearchCameras]); + return reviewCameras[0] ?? null; + }, [motionSearchCamera, reviewCameras]); const motionSearchTimeRange = useMemo(() => { if (motionSearchDay) { @@ -357,6 +359,10 @@ export default function Events() { const motion: ReviewSegment[] = []; reviews?.forEach((segment) => { + if (config?.cameras[segment.camera]?.ui?.review === false) { + return; + } + all.push(segment); switch (segment.severity) { @@ -378,7 +384,7 @@ export default function Events() { detection: detections, significant_motion: motion, }; - }, [reviews]); + }, [reviews, config?.cameras]); // update review items in place when a review segment ends const reviewUpdate = useFrigateReviews(); @@ -635,7 +641,7 @@ export default function Events() { } setStartTime(recording.startTime); - const allCameras = reviewFilter?.cameras ?? allowedCameras; + const allCameras = reviewFilter?.cameras ?? reviewCameras; return { camera: recording.camera, @@ -680,7 +686,7 @@ export default function Events() { ) : ( allCameras.filter((camera) => allowedCameras.includes(camera)), - [allCameras, allowedCameras], + () => + allCameras.filter( + (camera) => + allowedCameras.includes(camera) && + config?.cameras[camera]?.ui?.review !== false, + ), + [allCameras, allowedCameras, config?.cameras], ); const [mainCamera, setMainCamera] = useState(startCamera);