import { DropdownMenu, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer"; import MotionTuner from "@/components/settings/MotionTuner"; import MasksAndZones from "@/components/settings/MasksAndZones"; import { Button } from "@/components/ui/button"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import useOptimisticState from "@/hooks/use-optimistic-state"; import { isMobile } from "react-device-detect"; import { FaVideo } from "react-icons/fa"; import { CameraConfig, FrigateConfig } from "@/types/frigateConfig"; import useSWR from "swr"; import General from "@/components/settings/General"; import FilterSwitch from "@/components/filter/FilterSwitch"; import { ZoneMaskFilterButton } from "@/components/filter/ZoneMaskFilter"; import { PolygonType } from "@/types/canvas"; import ObjectSettings from "@/components/settings/ObjectSettings"; import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; import scrollIntoView from "scroll-into-view-if-needed"; export default function Settings() { const settingsViews = [ "general", "masks / zones", "motion tuner", "debug", ] as const; type SettingsType = (typeof settingsViews)[number]; const [page, setPage] = useState("general"); const [pageToggle, setPageToggle] = useOptimisticState(page, setPage, 100); const tabsRef = useRef(null); const { data: config } = useSWR("config"); // TODO: confirm leave page const [unsavedChanges, setUnsavedChanges] = useState(false); const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false); const cameras = useMemo(() => { if (!config) { return []; } return Object.values(config.cameras) .filter((conf) => conf.ui.dashboard && conf.enabled) .sort((aConf, bConf) => aConf.ui.order - bConf.ui.order); }, [config]); const [selectedCamera, setSelectedCamera] = useState(""); const [filterZoneMask, setFilterZoneMask] = useState(); const handleDialog = useCallback( (save: boolean) => { if (unsavedChanges && save) { // TODO } setConfirmationDialogOpen(false); setUnsavedChanges(false); }, [unsavedChanges], ); useEffect(() => { if (cameras.length) { setSelectedCamera(cameras[0].name); } // only run once // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { if (tabsRef.current) { const element = tabsRef.current.querySelector( `[data-nav-item="${pageToggle}"]`, ); if (element instanceof HTMLElement) { scrollIntoView(element, { behavior: "smooth", inline: "start", }); } } }, [tabsRef, pageToggle]); useEffect(() => { document.title = "Settings - Frigate"; }, []); return (
{ if (value) { setPageToggle(value); } }} > {Object.values(settingsViews).map((item) => (
{item}
))}
{(page == "debug" || page == "masks / zones" || page == "motion tuner") && (
{page == "masks / zones" && ( )}
)}
{page == "general" && } {page == "debug" && } {page == "masks / zones" && ( )} {page == "motion tuner" && ( )}
{confirmationDialogOpen && ( setConfirmationDialogOpen(false)} > You have unsaved changes. Do you want to save your changes before continuing? handleDialog(false)}> Cancel handleDialog(true)}> Save )}
); } type CameraSelectButtonProps = { allCameras: CameraConfig[]; selectedCamera: string; setSelectedCamera: React.Dispatch>; }; function CameraSelectButton({ allCameras, selectedCamera, setSelectedCamera, }: CameraSelectButtonProps) { const [open, setOpen] = useState(false); if (!allCameras.length) { return; } const trigger = ( ); const content = ( <> {isMobile && ( <> Camera )}
{allCameras.map((item) => ( { if (isChecked) { setSelectedCamera(item.name); setOpen(false); } }} /> ))}
); if (isMobile) { return ( { if (!open) { setSelectedCamera(selectedCamera); } setOpen(open); }} > {trigger} {content} ); } return ( { if (!open) { setSelectedCamera(selectedCamera); } setOpen(open); }} > {trigger} {content} ); }