diff --git a/web/src/components/filter/CameraGroupSelector.tsx b/web/src/components/filter/CameraGroupSelector.tsx index f975d290c..f737598c1 100644 --- a/web/src/components/filter/CameraGroupSelector.tsx +++ b/web/src/components/filter/CameraGroupSelector.tsx @@ -1,4 +1,4 @@ -import { FrigateConfig } from "@/types/frigateConfig"; +import { FrigateConfig, GROUP_ICONS } from "@/types/frigateConfig"; import { isDesktop } from "react-device-detect"; import useSWR from "swr"; import { MdHome } from "react-icons/md"; @@ -8,6 +8,17 @@ import { useNavigate } from "react-router-dom"; import { useCallback, useMemo, useState } from "react"; import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip"; import { getIconForGroup } from "@/utils/iconUtil"; +import { LuPlus } from "react-icons/lu"; +import { Dialog, DialogContent, DialogTitle } from "../ui/dialog"; +import { Input } from "../ui/input"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuTrigger, +} from "../ui/dropdown-menu"; +import FilterCheckBox from "./FilterCheckBox"; type CameraGroupSelectorProps = { className?: string; @@ -49,10 +60,16 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) { ); }, [config]); + // add group + + const [addGroup, setAddGroup] = useState(false); + return (
+ + + )}
); } + +type NewGroupDialogProps = { + open: boolean; + setOpen: (open: boolean) => void; +}; +function NewGroupDialog({ open, setOpen }: NewGroupDialogProps) { + const { data: config } = useSWR("config"); + const [newTitle, setNewTitle] = useState(""); + const [icon, setIcon] = useState(""); + const [cameras, setCameras] = useState([]); + + return ( + + + Create New Camera Group + setNewTitle(e.target.value)} + /> + + +
+ {icon.length == 0 ? "Select Icon" : "Icon: "} + {icon ? getIconForGroup(icon) :
} +
+ + + + {GROUP_ICONS.map((gIcon) => ( + + {getIconForGroup(gIcon)} + {gIcon} + + ))} + + + + + +
+ {cameras.length == 0 + ? "Select Cameras" + : `${cameras.length} Cameras`} +
+
+ + {Object.keys(config?.cameras ?? {}).map((camera) => ( + { + if (checked) { + setCameras([...cameras, camera]); + } else { + const index = cameras.indexOf(camera); + setCameras([ + ...cameras.slice(0, index), + ...cameras.slice(index + 1), + ]); + } + }} + /> + ))} + +
+ + +
+ ); +} diff --git a/web/src/components/filter/FilterCheckBox.tsx b/web/src/components/filter/FilterCheckBox.tsx new file mode 100644 index 000000000..b23a4e42c --- /dev/null +++ b/web/src/components/filter/FilterCheckBox.tsx @@ -0,0 +1,32 @@ +import { LuCheck } from "react-icons/lu"; +import { Button } from "../ui/button"; +import { IconType } from "react-icons"; + +type FilterCheckBoxProps = { + label: string; + CheckIcon?: IconType; + isChecked: boolean; + onCheckedChange: (isChecked: boolean) => void; +}; + +export default function FilterCheckBox({ + label, + CheckIcon = LuCheck, + isChecked, + onCheckedChange, +}: FilterCheckBoxProps) { + return ( + + ); +} diff --git a/web/src/components/filter/ReviewFilterGroup.tsx b/web/src/components/filter/ReviewFilterGroup.tsx index 489a997fb..1d862998c 100644 --- a/web/src/components/filter/ReviewFilterGroup.tsx +++ b/web/src/components/filter/ReviewFilterGroup.tsx @@ -1,4 +1,3 @@ -import { LuCheck } from "react-icons/lu"; import { Button } from "../ui/button"; import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; import useSWR from "swr"; @@ -16,11 +15,11 @@ import { ReviewFilter } from "@/types/review"; import { getEndOfDayTimestamp } from "@/utils/dateUtil"; import { useFormattedTimestamp } from "@/hooks/use-date-utils"; import { FaCalendarAlt, FaFilter, FaVideo } from "react-icons/fa"; -import { IconType } from "react-icons"; import { isMobile } from "react-device-detect"; import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer"; import { Switch } from "../ui/switch"; import { Label } from "../ui/label"; +import FilterCheckBox from "./FilterCheckBox"; const ATTRIBUTES = ["amazon", "face", "fedex", "license_plate", "ups"]; @@ -479,32 +478,3 @@ function GeneralFilterButton({ ); } - -type FilterCheckBoxProps = { - label: string; - CheckIcon?: IconType; - isChecked: boolean; - onCheckedChange: (isChecked: boolean) => void; -}; - -function FilterCheckBox({ - label, - CheckIcon = LuCheck, - isChecked, - onCheckedChange, -}: FilterCheckBoxProps) { - return ( - - ); -} diff --git a/web/src/types/frigateConfig.ts b/web/src/types/frigateConfig.ts index 7825e7f8f..a6c6b3864 100644 --- a/web/src/types/frigateConfig.ts +++ b/web/src/types/frigateConfig.ts @@ -204,9 +204,11 @@ export interface CameraConfig { }; } +export const GROUP_ICONS = ["car", "cat", "dog", "leaf"] as const; + export type CameraGroupConfig = { cameras: string[]; - icon: string; + icon: (typeof GROUP_ICONS)[number]; order: number; };