From 840d567d22b7974f90caf86773eb6ef0e726330c Mon Sep 17 00:00:00 2001
From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
Date: Sun, 26 Oct 2025 07:27:07 -0500
Subject: [PATCH] UI tweaks (#20675)
* spacing tweaks and add link to explore for plate
* clear selected objects when changing cameras
* plate link and spacing in object lifecycle
* set tabindex to prevent tooltip from showing on reopen
* show month and day in object lifecycle timestamp
---
.../overlay/detail/ObjectLifecycle.tsx | 37 ++++++++++-------
web/src/components/timeline/DetailStream.tsx | 40 +++++++++++++------
web/src/context/detail-stream-context.tsx | 5 +++
3 files changed, 55 insertions(+), 27 deletions(-)
diff --git a/web/src/components/overlay/detail/ObjectLifecycle.tsx b/web/src/components/overlay/detail/ObjectLifecycle.tsx
index 761be65ae..954f9cd6d 100644
--- a/web/src/components/overlay/detail/ObjectLifecycle.tsx
+++ b/web/src/components/overlay/detail/ObjectLifecycle.tsx
@@ -41,7 +41,7 @@ import {
ContextMenuItem,
ContextMenuTrigger,
} from "@/components/ui/context-menu";
-import { useNavigate } from "react-router-dom";
+import { Link, useNavigate } from "react-router-dom";
import { ObjectPath } from "./ObjectPath";
import { getLifecycleItemDescription } from "@/utils/lifecycleUtil";
import { IoPlayCircleOutline } from "react-icons/io5";
@@ -289,10 +289,10 @@ export default function ObjectLifecycle({
timezone: config.ui.timezone,
date_format:
config.ui.time_format == "24hour"
- ? t("time.formattedTimestampHourMinuteSecond.24hour", {
+ ? t("time.formattedTimestamp.24hour", {
ns: "common",
})
- : t("time.formattedTimestampHourMinuteSecond.12hour", {
+ : t("time.formattedTimestamp.12hour", {
ns: "common",
}),
time_style: "medium",
@@ -305,10 +305,10 @@ export default function ObjectLifecycle({
timezone: config.ui.timezone,
date_format:
config.ui.time_format == "24hour"
- ? t("time.formattedTimestampHourMinuteSecond.24hour", {
+ ? t("time.formattedTimestamp.24hour", {
ns: "common",
})
- : t("time.formattedTimestampHourMinuteSecond.12hour", {
+ : t("time.formattedTimestamp.12hour", {
ns: "common",
}),
time_style: "medium",
@@ -412,6 +412,7 @@ export default function ObjectLifecycle({
return (
+
{!fullscreen && (
@@ -832,10 +838,12 @@ function LifecycleIconRow({
/>
-
+
-
{getLifecycleItemDescription(item)}
-
+
+ {getLifecycleItemDescription(item)}
+
+
{t("objectLifecycle.lifecycleItemDesc.header.ratio")}
@@ -893,8 +901,9 @@ function LifecycleIconRow({
)}
-
-
{formattedEventTimestamp}
+
+
+
{formattedEventTimestamp}
diff --git a/web/src/components/timeline/DetailStream.tsx b/web/src/components/timeline/DetailStream.tsx
index 87f65967b..727f1bbed 100644
--- a/web/src/components/timeline/DetailStream.tsx
+++ b/web/src/components/timeline/DetailStream.tsx
@@ -22,6 +22,7 @@ import EventMenu from "@/components/timeline/EventMenu";
import { FrigatePlusDialog } from "@/components/overlay/dialog/FrigatePlusDialog";
import { cn } from "@/lib/utils";
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
+import { Link } from "react-router-dom";
type DetailStreamProps = {
reviewItems?: ReviewSegment[];
@@ -499,15 +500,22 @@ function EventList({
}}
role="button"
>
-
{label}
- {event.data?.recognized_license_plate && (
- <>
- ·{" "}
-
- {event.data.recognized_license_plate}
-
- >
- )}
+
+
{label}
+ {event.data?.recognized_license_plate && (
+ <>
+
·
+
+
+ {event.data.recognized_license_plate}
+
+
+ >
+ )}
+
@@ -615,10 +623,11 @@ function LifecycleItem({
)}
/>
-
+
+
-
+
{getLifecycleItemDescription(item)}
@@ -638,7 +647,9 @@ function LifecycleItem({
{areaPx !== undefined && areaPct !== undefined ? (
- {areaPx} {t("pixels", { ns: "common" })} · {areaPct}%
+ {areaPx} {t("pixels", { ns: "common" })}{" "}
+ ·{" "}
+ {areaPct}%
) : (
N/A
@@ -648,7 +659,10 @@ function LifecycleItem({
-
{formattedEventTimestamp}
+
+
+
+
{formattedEventTimestamp}
);
diff --git a/web/src/context/detail-stream-context.tsx b/web/src/context/detail-stream-context.tsx
index aa7b2478b..a148833e7 100644
--- a/web/src/context/detail-stream-context.tsx
+++ b/web/src/context/detail-stream-context.tsx
@@ -58,6 +58,11 @@ export function DetailStreamProvider({
setAnnotationOffset(cfgOffset);
}, [config, camera]);
+ // Clear selected objects when exiting detail mode or changing cameras
+ useEffect(() => {
+ setSelectedObjectIds([]);
+ }, [isDetailMode, camera]);
+
const value: DetailStreamContextType = {
selectedObjectIds,
currentTime,