From f46458c5f5196a2cf7f757909b5a75443dad24b4 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Tue, 2 Jun 2026 14:46:45 -0600 Subject: [PATCH] Add config to UI --- web/public/locales/en/views/settings.json | 8 +- .../views/settings/CameraManagementView.tsx | 89 ++++++++++++++++++- 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/web/public/locales/en/views/settings.json b/web/public/locales/en/views/settings.json index 6d52ae154b..0c46aec581 100644 --- a/web/public/locales/en/views/settings.json +++ b/web/public/locales/en/views/settings.json @@ -492,12 +492,16 @@ "details": { "edit": "Edit camera details", "title": "Edit Camera Details", - "description": "Update the display name and external URL used for this camera throughout the Frigate UI.", + "description": "Update the display name, external URL, and visibility used for this camera throughout the Frigate UI.", "friendlyNameLabel": "Display Name", "friendlyNameHelp": "Friendly name shown for this camera throughout the Frigate UI. Leave blank to use the camera ID.", "webuiUrlLabel": "Camera Web UI URL", "webuiUrlHelp": "URL to visit the camera's web UI directly from the Debug view. Leave blank to disable the link.", - "webuiUrlInvalid": "Must be a valid URL (e.g., https://example.com)." + "webuiUrlInvalid": "Must be a valid URL (e.g., https://example.com).", + "dashboardLabel": "Show on Live dashboard", + "dashboardHelp": "Show this camera on the Live dashboard.", + "reviewLabel": "Show in Review", + "reviewHelp": "Show this camera in Review, including the camera filter, motion review, and the history view." } }, "cameraConfig": { diff --git a/web/src/views/settings/CameraManagementView.tsx b/web/src/views/settings/CameraManagementView.tsx index db8d5fc3b8..a51f3374ac 100644 --- a/web/src/views/settings/CameraManagementView.tsx +++ b/web/src/views/settings/CameraManagementView.tsx @@ -75,6 +75,7 @@ import { FormLabel, FormMessage, } from "@/components/ui/form"; +import { Switch } from "@/components/ui/switch"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; @@ -704,6 +705,8 @@ type CameraDetailsEditorProps = { type CameraDetailsFormValues = { friendlyName: string; webuiUrl: string; + dashboard: boolean; + review: boolean; }; function CameraDetailsEditor({ @@ -717,11 +720,15 @@ function CameraDetailsEditor({ const currentFriendlyName = config?.cameras?.[cameraName]?.friendly_name; const currentWebuiUrl = config?.cameras?.[cameraName]?.webui_url; + const currentDashboard = config?.cameras?.[cameraName]?.ui?.dashboard ?? true; + const currentReview = config?.cameras?.[cameraName]?.ui?.review ?? true; const formSchema = useMemo( () => z.object({ friendlyName: z.string(), + dashboard: z.boolean(), + review: z.boolean(), webuiUrl: z.string().refine( (val) => { const trimmed = val.trim(); @@ -748,6 +755,8 @@ function CameraDetailsEditor({ defaultValues: { friendlyName: currentFriendlyName ?? "", webuiUrl: currentWebuiUrl ?? "", + dashboard: currentDashboard, + review: currentReview, }, }); @@ -757,9 +766,18 @@ function CameraDetailsEditor({ form.reset({ friendlyName: currentFriendlyName ?? "", webuiUrl: currentWebuiUrl ?? "", + dashboard: currentDashboard, + review: currentReview, }); } - }, [open, currentFriendlyName, currentWebuiUrl, form]); + }, [ + open, + currentFriendlyName, + currentWebuiUrl, + currentDashboard, + currentReview, + form, + ]); const onSubmit = useCallback( async (values: CameraDetailsFormValues) => { @@ -768,7 +786,7 @@ function CameraDetailsEditor({ // only send fields the user actually changed const newFriendly = values.friendlyName.trim() || null; const newWebui = values.webuiUrl.trim() || null; - const cameraUpdate: Record = {}; + const cameraUpdate: Record = {}; if (newFriendly !== (currentFriendlyName ?? null)) { cameraUpdate.friendly_name = newFriendly; } @@ -776,6 +794,17 @@ function CameraDetailsEditor({ cameraUpdate.webui_url = newWebui; } + const uiUpdate: Record = {}; + if (values.dashboard !== currentDashboard) { + uiUpdate.dashboard = values.dashboard; + } + if (values.review !== currentReview) { + uiUpdate.review = values.review; + } + if (Object.keys(uiUpdate).length > 0) { + cameraUpdate.ui = uiUpdate; + } + if (Object.keys(cameraUpdate).length === 0) { setOpen(false); return; @@ -818,6 +847,8 @@ function CameraDetailsEditor({ cameraName, currentFriendlyName, currentWebuiUrl, + currentDashboard, + currentReview, isSaving, onConfigChanged, t, @@ -914,6 +945,60 @@ function CameraDetailsEditor({ )} /> + ( + +
+ + {t("cameraManagement.streams.details.dashboardLabel", { + ns: "views/settings", + })} + +

+ {t("cameraManagement.streams.details.dashboardHelp", { + ns: "views/settings", + })} +

+
+ + + +
+ )} + /> + ( + +
+ + {t("cameraManagement.streams.details.reviewLabel", { + ns: "views/settings", + })} + +

+ {t("cameraManagement.streams.details.reviewHelp", { + ns: "views/settings", + })} +

+
+ + + +
+ )} + />