diff --git a/web/src/components/overlay/dialog/LPRDetailDialog.tsx b/web/src/components/overlay/dialog/LPRDetailDialog.tsx index b2242f307..abbc4821b 100644 --- a/web/src/components/overlay/dialog/LPRDetailDialog.tsx +++ b/web/src/components/overlay/dialog/LPRDetailDialog.tsx @@ -32,7 +32,7 @@ import { MobilePageTitle, } from "@/components/mobile/MobilePage"; -const LPR_TABS = ["details", "snapshot", "video"] as const; +const LPR_TABS = ["details", "snapshot", "video", "raw"] as const; export type LPRTab = (typeof LPR_TABS)[number]; type LPRDetailDialogProps = { @@ -41,6 +41,7 @@ type LPRDetailDialogProps = { event?: Event; config: FrigateConfig; lprImage: string; + rawImage: string; }; export default function LPRDetailDialog({ @@ -49,6 +50,7 @@ export default function LPRDetailDialog({ event, config, lprImage, + rawImage, }: LPRDetailDialogProps) { const [page, setPage] = useState("details"); @@ -66,20 +68,21 @@ export default function LPRDetailDialog({ ); const lprTabs = useMemo(() => { - if (!config || !event) { - return []; - } - const views = [...LPR_TABS]; - if (!event.has_snapshot) { - const index = views.indexOf("snapshot"); - views.splice(index, 1); - } + if (event) { + if (!event.has_snapshot) { + const index = views.indexOf("snapshot"); + views.splice(index, 1); + } - if (!event.has_clip) { - const index = views.indexOf("video"); - views.splice(index, 1); + if (!event.has_clip) { + const index = views.indexOf("video"); + views.splice(index, 1); + } + } else { + // When no event, show only raw tab + return ['raw']; } return views; @@ -100,7 +103,7 @@ export default function LPRDetailDialog({ License Plate Image License plate image details - + ); @@ -110,60 +113,68 @@ export default function LPRDetailDialog({
- License Plate Event Details - License plate event details + {event ? "License Plate Event Details" : "License Plate Image"} + License plate details
- -
- { - if (value) { - setPage(value); - } - }} - > - {Object.values(lprTabs).map((item) => ( - - {item == "details" && } - {item == "snapshot" && } - {item == "video" && } -
{item}
-
- ))} -
- -
-
- {page === "details" && ( - + + {event && ( + +
+ { + if (value) { + setPage(value); + } + }} + > + {lprTabs.map((item) => ( + + {item === "details" && } + {item === "snapshot" && } + {item === "video" && } + {item === "raw" && } +
{item}
+
+ ))} +
+ +
+
)} - {page === "snapshot" && ( - - )} - {page === "video" && ( - - )} - {(page === "details" || !event) && ( - + + {event ? ( + <> + {page === "details" && } + {page === "snapshot" && } + {page === "video" && } + {page === "raw" && ( + + )} + + ) : ( + )}
@@ -333,9 +344,10 @@ function VideoTab({ event }: VideoTabProps) { type PlateTabProps = { lprImage: string; + config: FrigateConfig; }; -function PlateTab({ lprImage }: PlateTabProps) { +function PlateTab({ lprImage, config }: PlateTabProps) { const [imgRef, imgLoaded, onImgLoad] = useImageLoaded(); return ( @@ -346,33 +358,31 @@ function PlateTab({ lprImage }: PlateTabProps) { />
-
+
-
+
License plate { - onImgLoad(); - }} + onLoad={onImgLoad} /> -
+ -
+
{lprAttempts.map((attempt: string) => ( ))}
@@ -197,10 +161,9 @@ type LPRAttemptProps = { attempt: string; config: FrigateConfig; onRefresh: () => void; - viewMode: ViewMode; }; -function LPRAttempt({ attempt, config, onRefresh, viewMode }: LPRAttemptProps) { +function LPRAttempt({ attempt, config, onRefresh }: LPRAttemptProps) { const [showDialog, setShowDialog] = useState(false); const data = useMemo(() => { const parts = attempt.split("_"); @@ -245,6 +208,9 @@ function LPRAttempt({ attempt, config, onRefresh, viewMode }: LPRAttemptProps) { }); }, [attempt, onRefresh]); + // Extract event ID from processed image filename (format: PLATE_SCORE_EVENTID.jpg) + const eventId = useMemo(() => attempt.split("_").slice(2).join("_").replace(".jpg", ""), [attempt]); + return ( <>
@@ -263,7 +230,7 @@ function LPRAttempt({ attempt, config, onRefresh, viewMode }: LPRAttemptProps) {