From fdf704fffd5d2fbb5bbac27c89655b43e65581dc Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Thu, 5 Mar 2026 10:16:17 -0600 Subject: [PATCH] frontend --- web/src/pages/Settings.tsx | 18 +-- ...ingsView.tsx => MediaSyncSettingsView.tsx} | 4 +- .../views/settings/RegionGridSettingsView.tsx | 124 ++++++++++++++++++ 3 files changed, 136 insertions(+), 10 deletions(-) rename web/src/views/settings/{MaintenanceSettingsView.tsx => MediaSyncSettingsView.tsx} (99%) create mode 100644 web/src/views/settings/RegionGridSettingsView.tsx diff --git a/web/src/pages/Settings.tsx b/web/src/pages/Settings.tsx index e686ea241..c5c55ef5e 100644 --- a/web/src/pages/Settings.tsx +++ b/web/src/pages/Settings.tsx @@ -40,7 +40,8 @@ import UsersView from "@/views/settings/UsersView"; import RolesView from "@/views/settings/RolesView"; import UiSettingsView from "@/views/settings/UiSettingsView"; import FrigatePlusSettingsView from "@/views/settings/FrigatePlusSettingsView"; -import MaintenanceSettingsView from "@/views/settings/MaintenanceSettingsView"; +import MediaSyncSettingsView from "@/views/settings/MediaSyncSettingsView"; +import RegionGridSettingsView from "@/views/settings/RegionGridSettingsView"; import SystemDetectionModelSettingsView from "@/views/settings/SystemDetectionModelSettingsView"; import { SingleSectionPage, @@ -154,7 +155,8 @@ const allSettingsViews = [ "roles", "notifications", "frigateplus", - "maintenance", + "mediaSync", + "regionGrid", ] as const; type SettingsType = (typeof allSettingsViews)[number]; @@ -444,7 +446,10 @@ const settingsGroups = [ }, { label: "maintenance", - items: [{ key: "maintenance", component: MaintenanceSettingsView }], + items: [ + { key: "mediaSync", component: MediaSyncSettingsView }, + { key: "regionGrid", component: RegionGridSettingsView }, + ], }, ]; @@ -471,15 +476,12 @@ const CAMERA_SELECT_BUTTON_PAGES = [ "masksAndZones", "motionTuner", "triggers", + "regionGrid", ]; const ALLOWED_VIEWS_FOR_VIEWER = ["ui", "debug", "notifications"]; -const LARGE_BOTTOM_MARGIN_PAGES = [ - "masksAndZones", - "motionTuner", - "maintenance", -]; +const LARGE_BOTTOM_MARGIN_PAGES = ["masksAndZones", "motionTuner", "mediaSync"]; // keys for camera sections const CAMERA_SECTION_MAPPING: Record = { diff --git a/web/src/views/settings/MaintenanceSettingsView.tsx b/web/src/views/settings/MediaSyncSettingsView.tsx similarity index 99% rename from web/src/views/settings/MaintenanceSettingsView.tsx rename to web/src/views/settings/MediaSyncSettingsView.tsx index df1dd7b90..afbfe3ea1 100644 --- a/web/src/views/settings/MaintenanceSettingsView.tsx +++ b/web/src/views/settings/MediaSyncSettingsView.tsx @@ -15,7 +15,7 @@ import { cn } from "@/lib/utils"; import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; import { MediaSyncStats } from "@/types/ws"; -export default function MaintenanceSettingsView() { +export default function MediaSyncSettingsView() { const { t } = useTranslation("views/settings"); const [selectedMediaTypes, setSelectedMediaTypes] = useState([ "all", @@ -103,7 +103,7 @@ export default function MaintenanceSettingsView() {
- + {t("maintenance.sync.title")} diff --git a/web/src/views/settings/RegionGridSettingsView.tsx b/web/src/views/settings/RegionGridSettingsView.tsx new file mode 100644 index 000000000..c802d4cbf --- /dev/null +++ b/web/src/views/settings/RegionGridSettingsView.tsx @@ -0,0 +1,124 @@ +import Heading from "@/components/ui/heading"; +import { Button, buttonVariants } from "@/components/ui/button"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog"; +import { Toaster } from "@/components/ui/sonner"; +import { useCallback, useContext, useState } from "react"; +import { useTranslation } from "react-i18next"; +import axios from "axios"; +import { toast } from "sonner"; +import { StatusBarMessagesContext } from "@/context/statusbar-provider"; +import { cn } from "@/lib/utils"; + +type RegionGridSettingsViewProps = { + selectedCamera: string; +}; + +export default function RegionGridSettingsView({ + selectedCamera, +}: RegionGridSettingsViewProps) { + const { t } = useTranslation("views/settings"); + const { addMessage } = useContext(StatusBarMessagesContext)!; + const [isConfirmOpen, setIsConfirmOpen] = useState(false); + const [isClearing, setIsClearing] = useState(false); + const [imageKey, setImageKey] = useState(0); + + const handleClear = useCallback(async () => { + setIsClearing(true); + + try { + await axios.delete(`${selectedCamera}/region_grid`); + toast.success(t("maintenance.regionGrid.clearSuccess"), { + position: "top-center", + }); + setImageKey((prev) => prev + 1); + addMessage( + "region_grid_restart", + t("maintenance.regionGrid.restartRequired"), + undefined, + "region_grid_settings", + ); + } catch { + toast.error(t("maintenance.regionGrid.clearError"), { + position: "top-center", + }); + } finally { + setIsClearing(false); + setIsConfirmOpen(false); + } + }, [selectedCamera, t, addMessage]); + + return ( + <> +
+ +
+ + {t("maintenance.regionGrid.title")} + + +
+
+

{t("maintenance.regionGrid.desc")}

+
+
+ +
+ {t("maintenance.regionGrid.title")} +
+ +
+ +
+
+
+ + + + + + {t("maintenance.regionGrid.clearConfirmTitle")} + + + {t("maintenance.regionGrid.clearConfirmDesc")} + + + + + {t("button.cancel", { ns: "common" })} + + + {t("maintenance.regionGrid.clear")} + + + + + + ); +}