From 2f308af2ae6022aab3db17a77d22dc3d5cb3e411 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Thu, 30 Oct 2025 08:45:13 -0500 Subject: [PATCH] remove old review detail dialog --- .../overlay/detail/ReviewDetailDialog.tsx | 577 ------------------ 1 file changed, 577 deletions(-) delete mode 100644 web/src/components/overlay/detail/ReviewDetailDialog.tsx diff --git a/web/src/components/overlay/detail/ReviewDetailDialog.tsx b/web/src/components/overlay/detail/ReviewDetailDialog.tsx deleted file mode 100644 index 16050245c..000000000 --- a/web/src/components/overlay/detail/ReviewDetailDialog.tsx +++ /dev/null @@ -1,577 +0,0 @@ -import { isDesktop, isIOS, isMobile } from "react-device-detect"; -import { - Sheet, - SheetContent, - SheetDescription, - SheetHeader, - SheetTitle, -} from "../../ui/sheet"; -import useSWR from "swr"; -import { FrigateConfig } from "@/types/frigateConfig"; -import { useFormattedTimestamp } from "@/hooks/use-date-utils"; -import { getIconForLabel } from "@/utils/iconUtil"; -import { useApiHost } from "@/api"; -import { - ReviewDetailPaneType, - ReviewSegment, - ThreatLevel, -} from "@/types/review"; -import { Event } from "@/types/event"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { cn } from "@/lib/utils"; -import { FrigatePlusDialog } from "../dialog/FrigatePlusDialog"; -import TrackingDetails from "./TrackingDetails"; -import Chip from "@/components/indicators/Chip"; -import { FaDownload, FaImages, FaShareAlt } from "react-icons/fa"; -import FrigatePlusIcon from "@/components/icons/FrigatePlusIcon"; -import { FaArrowsRotate } from "react-icons/fa6"; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { useNavigate } from "react-router-dom"; -import { Button } from "@/components/ui/button"; -import { baseUrl } from "@/api/baseUrl"; -import { shareOrCopy } from "@/utils/browserUtil"; -import { - MobilePage, - MobilePageContent, - MobilePageDescription, - MobilePageHeader, - MobilePageTitle, -} from "@/components/mobile/MobilePage"; -import { DownloadVideoButton } from "@/components/button/DownloadVideoButton"; -import { TooltipPortal } from "@radix-ui/react-tooltip"; -import { LuSearch } from "react-icons/lu"; -import useKeyboardListener from "@/hooks/use-keyboard-listener"; -import { Trans, useTranslation } from "react-i18next"; -import { getTranslatedLabel } from "@/utils/i18n"; -import { CameraNameLabel } from "@/components/camera/CameraNameLabel"; - -type ReviewDetailDialogProps = { - review?: ReviewSegment; - setReview: (review: ReviewSegment | undefined) => void; -}; -export default function ReviewDetailDialog({ - review, - setReview, -}: ReviewDetailDialogProps) { - const { t } = useTranslation(["views/explore"]); - const { data: config } = useSWR("config", { - revalidateOnFocus: false, - }); - - const navigate = useNavigate(); - - // upload - - const [upload, setUpload] = useState(); - - // data - - const { data: events } = useSWR( - review ? ["event_ids", { ids: review.data.detections.join(",") }] : null, - ); - - const aiAnalysis = useMemo(() => review?.data?.metadata, [review]); - - const aiThreatLevel = useMemo(() => { - if ( - !aiAnalysis || - (!aiAnalysis.potential_threat_level && !aiAnalysis.other_concerns) - ) { - return "None"; - } - - let concerns = ""; - switch (aiAnalysis.potential_threat_level) { - case ThreatLevel.SUSPICIOUS: - concerns = `• ${t("suspiciousActivity", { ns: "views/events" })}\n`; - break; - case ThreatLevel.DANGER: - concerns = `• ${t("threateningActivity", { ns: "views/events" })}\n`; - break; - } - - (aiAnalysis.other_concerns ?? []).forEach((c) => { - concerns += `• ${c}\n`; - }); - - return concerns || "None"; - }, [aiAnalysis, t]); - - const hasMismatch = useMemo(() => { - if (!review || !events) { - return false; - } - - return events.length != review?.data.detections.length; - }, [review, events]); - - const missingObjects = useMemo(() => { - if (!review || !events) { - return []; - } - - const detectedIds = review.data.detections; - const missing = Array.from( - new Set( - events - .filter((event) => !detectedIds.includes(event.id)) - .map((event) => event.label), - ), - ); - - return missing; - }, [review, events]); - - const formattedDate = useFormattedTimestamp( - review?.start_time ?? 0, - config?.ui.time_format == "24hour" - ? t("time.formattedTimestampMonthDayYearHourMinute.24hour", { - ns: "common", - }) - : t("time.formattedTimestampMonthDayYearHourMinute.12hour", { - ns: "common", - }), - config?.ui.timezone, - ); - - // content - - const [selectedEvent, setSelectedEvent] = useState(); - const [pane, setPane] = useState("overview"); - - // dialog and mobile page - - const [isOpen, setIsOpen] = useState(review != undefined); - - const handleOpenChange = useCallback( - (open: boolean) => { - setIsOpen(open); - if (!open) { - // short timeout to allow the mobile page animation - // to complete before updating the state - setTimeout(() => { - setReview(undefined); - setSelectedEvent(undefined); - setPane("overview"); - }, 300); - } - }, - [setReview, setIsOpen], - ); - - useEffect(() => { - setIsOpen(review != undefined); - // we know that these deps are correct - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [review]); - - // keyboard listener - - useKeyboardListener(["Esc"], (key, modifiers) => { - if (key == "Esc" && modifiers.down && !modifiers.repeat) { - setIsOpen(false); - } - - return true; - }); - - const Overlay = isDesktop ? Sheet : MobilePage; - const Content = isDesktop ? SheetContent : MobilePageContent; - const Header = isDesktop ? SheetHeader : MobilePageHeader; - const Title = isDesktop ? SheetTitle : MobilePageTitle; - const Description = isDesktop ? SheetDescription : MobilePageDescription; - - if (!review) { - return; - } - - return ( - <> - - setUpload(undefined)} - onEventUploaded={() => { - if (upload) { - upload.plus_id = "new_upload"; - } - }} - /> - - - - {pane == "overview" && ( -
- {t("details.item.title")} - - {t("details.item.desc")} - -
- - - - - - - {t("details.item.button.share")} - - - - - - - - - - {t("button.download", { ns: "common" })} - - - -
-
- )} - {pane == "overview" && ( -
- {aiAnalysis != undefined && ( -
- {t("aiAnalysis.title")} -
- {t("details.description.label")} -
-
{aiAnalysis.scene}
-
- {t("details.score.label")} -
-
{aiAnalysis.confidence * 100}%
-
- {t("concerns.label")} -
-
{aiThreatLevel}
-
- )} -
-
-
-
- {t("details.camera")} -
-
- -
-
-
-
- {t("details.timestamp")} -
-
{formattedDate}
-
-
-
-
-
- {t("details.objects")} -
-
- {events?.map((event) => { - return ( -
- {getIconForLabel( - event.label, - "size-3 text-primary", - )} - {event.sub_label ?? - event.label.replaceAll("_", " ")}{" "} - ({Math.round(event.data.top_score * 100)}%) - - -
{ - navigate(`/explore?event_id=${event.id}`); - }} - > - -
-
- - - {t("details.item.button.viewInExplore")} - - -
-
- ); - })} -
-
- {review.data.zones.length > 0 && ( -
-
- {t("details.zones")} -
-
- {review.data.zones.map((zone) => { - return ( -
- {zone.replaceAll("_", " ")} -
- ); - })} -
-
- )} -
-
- {hasMismatch && ( -
- {(() => { - const detectedCount = Math.abs( - (events?.length ?? 0) - - (review?.data.detections.length ?? 0), - ); - - return t("details.item.tips.mismatch", { - count: detectedCount, - }); - })()} - {missingObjects.length > 0 && ( -
- getTranslatedLabel(x)) - .join(", "), - }} - > - details.item.tips.hasMissingObjects - -
- )} -
- )} -
- {events?.map((event) => ( - - ))} -
-
- )} - - {pane == "details" && selectedEvent && ( -
- -
- )} -
-
- - ); -} - -type EventItemProps = { - event: Event; - setPane: React.Dispatch>; - setSelectedEvent: React.Dispatch>; - setUpload?: React.Dispatch>; -}; - -function EventItem({ - event, - setPane, - setSelectedEvent, - setUpload, -}: EventItemProps) { - const { t } = useTranslation(["views/explore"]); - - const { data: config } = useSWR("config", { - revalidateOnFocus: false, - }); - - const apiHost = useApiHost(); - - const imgRef = useRef(null); - - const [hovered, setHovered] = useState(isMobile); - - const navigate = useNavigate(); - - return ( - <> -
setHovered(true) : undefined} - onMouseLeave={isDesktop ? () => setHovered(false) : undefined} - key={event.id} - > - {event.has_snapshot && ( - <> -
-
- - )} - - {hovered && ( -
-
- - - - - - - - - - {t("button.download", { ns: "common" })} - - - - {event.has_snapshot && - event.plus_id == undefined && - event.data.type == "object" && - config?.plus.enabled && ( - - - { - setUpload?.(event); - }} - > - - - - - {t("itemMenu.submitToPlus.label")} - - - )} - - {event.has_clip && ( - - - { - setPane("details"); - setSelectedEvent(event); - }} - > - - - - - {t("itemMenu.viewTrackingDetails.label")} - - - )} - - {event.has_snapshot && config?.semantic_search.enabled && ( - - - { - navigate( - `/explore?search_type=similarity&event_id=${event.id}`, - ); - }} - > - - - - - {t("itemMenu.findSimilar.label")} - - - )} -
-
- )} -
- - ); -}