From 62710bb3464c1b54c1852c2e04de7f0c6b87b4ec Mon Sep 17 00:00:00 2001 From: Nick Mowen Date: Mon, 18 Dec 2023 15:43:17 -0700 Subject: [PATCH] Add filter popover --- frigate/http.py | 16 ++- .../filter/HistoryFilterPopover.tsx | 101 ++++++++++++++++++ web/src/pages/History.tsx | 15 ++- web/src/types/history.ts | 5 + web/vite.config.ts | 12 +-- 5 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 web/src/components/filter/HistoryFilterPopover.tsx diff --git a/frigate/http.py b/frigate/http.py index 6b7ff8c3a..427831b1e 100644 --- a/frigate/http.py +++ b/frigate/http.py @@ -614,20 +614,30 @@ def timeline(): @bp.route("/timeline/hourly") def hourly_timeline(): """Get hourly summary for timeline.""" - camera = request.args.get("camera", "all") + cameras = request.args.get("cameras", "all") + labels = request.args.get("labels", "all") before = request.args.get("before", type=float) + after = request.args.get("after", type=float) limit = request.args.get("limit", 200) tz_name = request.args.get("timezone", default="utc", type=str) _, minute_modifier, _ = get_tz_modifiers(tz_name) clauses = [] - if camera != "all": - clauses.append((Timeline.camera == camera)) + if cameras != "all": + camera_list = cameras.split(",") + clauses.append((Timeline.camera << camera_list)) + + if labels != "all": + label_list = labels.split(",") + clauses.append((Timeline.data["label"] << label_list)) if before: clauses.append((Timeline.timestamp < before)) + if after: + clauses.append((Timeline.timestamp > after)) + if len(clauses) == 0: clauses.append((True)) diff --git a/web/src/components/filter/HistoryFilterPopover.tsx b/web/src/components/filter/HistoryFilterPopover.tsx new file mode 100644 index 000000000..cdbd6efe8 --- /dev/null +++ b/web/src/components/filter/HistoryFilterPopover.tsx @@ -0,0 +1,101 @@ +import { LuFilter } from "react-icons/lu"; +import { Button } from "../ui/button"; +import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; +import useSWR from "swr"; +import { FrigateConfig } from "@/types/frigateConfig"; +import { useMemo } from "react"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "../ui/dropdown-menu"; + +type HistoryFilterPopoverProps = { + filter: HistoryFilter; + onUpdateFilter: (filter: HistoryFilter) => void; +}; + +export default function HistoryFilterPopover({ + filter, + onUpdateFilter +}: HistoryFilterPopoverProps) { + const { data: config } = useSWR("config"); + const { data: allLabels } = useSWR(["labels"], { + revalidateOnFocus: false, + }); + const { data: allSubLabels } = useSWR( + ["sub_labels", { split_joined: 1 }], + { + revalidateOnFocus: false, + } + ); + const filterValues = useMemo( + () => ({ + cameras: Object.keys(config?.cameras || {}), + labels: Object.values(allLabels || {}), + }), + [config, allLabels, allSubLabels] + ); + + return ( + + + + + +
+ + + + + + Filter Cameras + + {filterValues.cameras.map((item) => ( + + {item.replaceAll("_", " ")} + + ))} + + + + + + + + Filter Labels + + {filterValues.labels.map((item) => ( + + {item.replaceAll("_", " ")} + + ))} + + +
+
+
+ ); +} diff --git a/web/src/pages/History.tsx b/web/src/pages/History.tsx index e9e5a00a3..5641ecdbe 100644 --- a/web/src/pages/History.tsx +++ b/web/src/pages/History.tsx @@ -19,6 +19,7 @@ import { AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; +import HistoryFilterPopover from "@/components/filter/HistoryFilterPopover"; const API_LIMIT = 200; @@ -29,6 +30,12 @@ function History() { config?.ui?.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone, [config] ); + + const [searchFilter, setSearchFilter] = useState({ + cameras: [], + labels: [], + }); + const timelineFetcher = useCallback((key: any) => { const [path, params] = Array.isArray(key) ? key : [key, undefined]; return axios.get(path, { params }).then((res) => res.data); @@ -137,7 +144,13 @@ function History() { return ( <> - Review +
+ History + setSearchFilter(filter)} + /> +