From 3300b8afb9f42f65c3c39752e0a628a32c7973e6 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Wed, 11 Sep 2024 12:25:18 -0600 Subject: [PATCH] Remove frigate plus view --- web/src/hooks/use-navigation.ts | 20 +- web/src/pages/SubmitPlus.tsx | 636 -------------------------------- 2 files changed, 2 insertions(+), 654 deletions(-) delete mode 100644 web/src/pages/SubmitPlus.tsx diff --git a/web/src/hooks/use-navigation.ts b/web/src/hooks/use-navigation.ts index 6a43483f8..06ebd6c1d 100644 --- a/web/src/hooks/use-navigation.ts +++ b/web/src/hooks/use-navigation.ts @@ -1,28 +1,20 @@ -import Logo from "@/components/Logo"; import { ENV } from "@/env"; -import { FrigateConfig } from "@/types/frigateConfig"; import { NavData } from "@/types/navigation"; import { useMemo } from "react"; import { FaCompactDisc, FaVideo } from "react-icons/fa"; import { IoSearch } from "react-icons/io5"; import { LuConstruction } from "react-icons/lu"; import { MdVideoLibrary } from "react-icons/md"; -import useSWR from "swr"; export const ID_LIVE = 1; export const ID_REVIEW = 2; export const ID_EXPLORE = 3; export const ID_EXPORT = 4; -export const ID_PLUS = 5; -export const ID_PLAYGROUND = 6; +export const ID_PLAYGROUND = 5; export default function useNavigation( variant: "primary" | "secondary" = "primary", ) { - const { data: config } = useSWR("config", { - revalidateOnFocus: false, - }); - return useMemo( () => [ @@ -54,14 +46,6 @@ export default function useNavigation( title: "Export", url: "/export", }, - { - id: ID_PLUS, - variant, - icon: Logo, - title: "Frigate+", - url: "/plus", - enabled: config?.plus?.enabled == true, - }, { id: ID_PLAYGROUND, variant, @@ -71,6 +55,6 @@ export default function useNavigation( enabled: ENV !== "production", }, ] as NavData[], - [config?.plus.enabled, variant], + [variant], ); } diff --git a/web/src/pages/SubmitPlus.tsx b/web/src/pages/SubmitPlus.tsx deleted file mode 100644 index 96fc21787..000000000 --- a/web/src/pages/SubmitPlus.tsx +++ /dev/null @@ -1,636 +0,0 @@ -import { baseUrl } from "@/api/baseUrl"; -import { CamerasFilterButton } from "@/components/filter/CamerasFilterButton"; -import { GeneralFilterContent } from "@/components/filter/ReviewFilterGroup"; -import Chip from "@/components/indicators/Chip"; -import ActivityIndicator from "@/components/indicators/activity-indicator"; -import { FrigatePlusDialog } from "@/components/overlay/dialog/FrigatePlusDialog"; -import { Button } from "@/components/ui/button"; -import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; -import { DualThumbSlider } from "@/components/ui/slider"; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { Event } from "@/types/event"; -import { ATTRIBUTE_LABELS, FrigateConfig } from "@/types/frigateConfig"; -import { getIconForLabel } from "@/utils/iconUtil"; -import { capitalizeFirstLetter } from "@/utils/stringUtil"; -import axios from "axios"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { isMobile } from "react-device-detect"; -import { - FaList, - FaSort, - FaSortAmountDown, - FaSortAmountUp, -} from "react-icons/fa"; -import { LuFolderX } from "react-icons/lu"; -import { PiSlidersHorizontalFill } from "react-icons/pi"; -import useSWR from "swr"; -import useSWRInfinite from "swr/infinite"; - -const API_LIMIT = 100; - -export default function SubmitPlus() { - // title - - useEffect(() => { - document.title = "Plus - Frigate"; - }, []); - - // filters - - const [selectedCameras, setSelectedCameras] = useState(); - const [selectedLabels, setSelectedLabels] = useState(); - const [scoreRange, setScoreRange] = useState(); - - // sort - - const [sort, setSort] = useState(); - - // data - - const eventFetcher = useCallback((key: string) => { - const [path, params] = Array.isArray(key) ? key : [key, undefined]; - return axios.get(path, { params }).then((res) => res.data); - }, []); - - const getKey = useCallback( - (index: number, prevData: Event[]) => { - if (index > 0) { - const lastDate = prevData[prevData.length - 1].start_time; - return [ - "events", - { - limit: API_LIMIT, - in_progress: 0, - is_submitted: 0, - has_snapshot: 1, - cameras: selectedCameras ? selectedCameras.join(",") : null, - labels: selectedLabels ? selectedLabels.join(",") : null, - min_score: scoreRange ? scoreRange[0] : null, - max_score: scoreRange ? scoreRange[1] : null, - sort: sort ? sort : null, - before: lastDate, - }, - ]; - } - - return [ - "events", - { - limit: 100, - in_progress: 0, - is_submitted: 0, - has_snapshot: 1, - cameras: selectedCameras ? selectedCameras.join(",") : null, - labels: selectedLabels ? selectedLabels.join(",") : null, - min_score: scoreRange ? scoreRange[0] : null, - max_score: scoreRange ? scoreRange[1] : null, - sort: sort ? sort : null, - }, - ]; - }, - [scoreRange, selectedCameras, selectedLabels, sort], - ); - - const { - data: eventPages, - mutate: refresh, - size, - setSize, - isValidating, - } = useSWRInfinite(getKey, eventFetcher, { - revalidateOnFocus: false, - }); - - const events = useMemo( - () => (eventPages ? eventPages.flat() : []), - [eventPages], - ); - - const [upload, setUpload] = useState(); - - // paging - - const isDone = useMemo( - () => (eventPages?.at(-1)?.length ?? 0) < API_LIMIT, - [eventPages], - ); - - const pagingObserver = useRef(); - const lastEventRef = useCallback( - (node: HTMLElement | null) => { - if (isValidating) return; - if (pagingObserver.current) pagingObserver.current.disconnect(); - try { - pagingObserver.current = new IntersectionObserver((entries) => { - if (entries[0].isIntersecting && !isDone) { - setSize(size + 1); - } - }); - if (node) pagingObserver.current.observe(node); - } catch (e) { - // no op - } - }, - [isValidating, isDone, size, setSize], - ); - - return ( -
-
- - -
-
- {!events?.length ? ( - <> - {isValidating ? ( - - ) : ( -
- - No snapshots found -
- )} - - ) : ( - <> -
- setUpload(undefined)} - onEventUploaded={() => { - refresh( - (data: Event[][] | undefined) => { - if (!data || !upload) { - return data; - } - - let pageIndex = -1; - let index = -1; - - data.forEach((page, pIdx) => { - const search = page.findIndex((e) => e.id == upload.id); - - if (search != -1) { - pageIndex = pIdx; - index = search; - } - }); - - if (index == -1) { - return data; - } - - return [ - ...data.slice(0, pageIndex), - [ - ...data[pageIndex].slice(0, index), - { ...data[pageIndex][index], plus_id: "new_upload" }, - ...data[pageIndex].slice(index + 1), - ], - ...data.slice(pageIndex + 1), - ]; - }, - { revalidate: false, populateCache: true }, - ); - }} - /> - - {events?.map((event) => { - if (event.data.type != "object" || event.plus_id) { - return; - } - - return ( -
setUpload(event)} - > -
- -
- -
- - {[event.label].map((object) => { - return getIconForLabel( - object, - "size-3 text-white", - ); - })} -
- {Math.round(event.data.score * 100)}% -
-
-
-
-
- - {[event.label] - .map((text) => capitalizeFirstLetter(text)) - .sort() - .join(", ") - .replaceAll("-verified", "")} - -
-
- -
- ); - })} -
- {!isDone && isValidating ? ( -
- -
- ) : ( -
- )} - - )} -
-
- ); -} - -type PlusFilterGroupProps = { - selectedCameras: string[] | undefined; - selectedLabels: string[] | undefined; - selectedScoreRange: number[] | undefined; - setSelectedCameras: (cameras: string[] | undefined) => void; - setSelectedLabels: (cameras: string[] | undefined) => void; - setSelectedScoreRange: (range: number[] | undefined) => void; -}; -function PlusFilterGroup({ - selectedCameras, - selectedLabels, - selectedScoreRange, - setSelectedCameras, - setSelectedLabels, - setSelectedScoreRange, -}: PlusFilterGroupProps) { - const { data: config } = useSWR("config"); - - const allCameras = useMemo(() => { - if (!config) { - return []; - } - - return Object.keys(config.cameras); - }, [config]); - const allLabels = useMemo(() => { - if (!config) { - return []; - } - - const labels = new Set(); - const cameras = selectedCameras || Object.keys(config.cameras); - - cameras.forEach((camera) => { - const cameraConfig = config.cameras[camera]; - cameraConfig.objects.track.forEach((label) => { - if (!ATTRIBUTE_LABELS.includes(label)) { - labels.add(label); - } - }); - }); - - return [...labels].sort(); - }, [config, selectedCameras]); - - const [open, setOpen] = useState<"none" | "camera" | "label" | "score">( - "none", - ); - const [currentLabels, setCurrentLabels] = useState( - undefined, - ); - const [currentScoreRange, setCurrentScoreRange] = useState< - number[] | undefined - >(undefined); - - const Menu = isMobile ? Drawer : DropdownMenu; - const Trigger = isMobile ? DrawerTrigger : DropdownMenuTrigger; - const Content = isMobile ? DrawerContent : DropdownMenuContent; - - return ( -
- - { - if (!open) { - setCurrentLabels(selectedLabels); - } - setOpen(open ? "label" : "none"); - }} - > - - - - - setOpen("none")} - /> - - - { - setOpen(open ? "score" : "none"); - }} - > - - - - -
- { - const value = e.target.value; - - if (value) { - setCurrentScoreRange([ - parseInt(value) / 100.0, - currentScoreRange?.at(1) ?? 1.0, - ]); - } - }} - /> - - { - const value = e.target.value; - - if (value) { - setCurrentScoreRange([ - currentScoreRange?.at(0) ?? 0.5, - parseInt(value) / 100.0, - ]); - } - }} - /> -
- -
- - -
-
-
-
- ); -} - -type PlusSortSelectorProps = { - selectedSort?: string; - setSelectedSort: (sort: string | undefined) => void; -}; -function PlusSortSelector({ - selectedSort, - setSelectedSort, -}: PlusSortSelectorProps) { - // menu state - - const [open, setOpen] = useState(false); - - // sort - - const [currentSort, setCurrentSort] = useState(); - const [currentDir, setCurrentDir] = useState("desc"); - - // components - - const Sort = selectedSort - ? selectedSort.split("_")[1] == "desc" - ? FaSortAmountDown - : FaSortAmountUp - : FaSort; - const Menu = isMobile ? Drawer : DropdownMenu; - const Trigger = isMobile ? DrawerTrigger : DropdownMenuTrigger; - const Content = isMobile ? DrawerContent : DropdownMenuContent; - - return ( -
- { - setOpen(open); - - if (!open) { - const parts = selectedSort?.split("_"); - - if (parts?.length == 2) { - setCurrentSort(parts[0]); - setCurrentDir(parts[1]); - } - } - }} - > - - - - - setCurrentSort(value)} - > -
- - - {currentSort == "date" ? ( - currentDir == "desc" ? ( - setCurrentDir("asc")} - /> - ) : ( - setCurrentDir("desc")} - /> - ) - ) : ( -
- )} -
-
- - - {currentSort == "score" ? ( - currentDir == "desc" ? ( - setCurrentDir("asc")} - /> - ) : ( - setCurrentDir("desc")} - /> - ) - ) : ( -
- )} -
- - -
- - -
- -
-
- ); -}