From de1c1f3fb4a6cd3976dfe622d55c3b28f735e1c3 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Sun, 26 Oct 2025 11:43:25 -0500 Subject: [PATCH] More detail pane tweaks --- web/src/components/timeline/DetailStream.tsx | 69 ++++++++++++++------ web/src/context/detail-stream-context.tsx | 2 + 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/web/src/components/timeline/DetailStream.tsx b/web/src/components/timeline/DetailStream.tsx index 727f1bbed..5d2466fa0 100644 --- a/web/src/components/timeline/DetailStream.tsx +++ b/web/src/components/timeline/DetailStream.tsx @@ -430,7 +430,8 @@ function EventList({ }: EventListProps) { const { data: config } = useSWR("config"); - const { selectedObjectIds, toggleObjectSelection } = useDetailStream(); + const { selectedObjectIds, setSelectedObjectIds, toggleObjectSelection } = + useDetailStream(); const isSelected = selectedObjectIds.includes(event.id); @@ -438,13 +439,19 @@ function EventList({ const handleObjectSelect = (event: Event | undefined) => { if (event) { - // onSeek(event.start_time ?? 0); - toggleObjectSelection(event.id); + setSelectedObjectIds([]); + setSelectedObjectIds([event.id]); + onSeek(event.start_time ?? 0); } else { - toggleObjectSelection(undefined); + setSelectedObjectIds([]); } }; + const handleTimelineClick = (ts: number, play?: boolean) => { + handleObjectSelect(event); + onSeek(ts, play); + }; + // Clear selection when effectiveTime has passed this event's end_time useEffect(() => { if (isSelected && effectiveTime && event.end_time) { @@ -468,11 +475,6 @@ function EventList({ isSelected ? "bg-secondary-highlight" : "outline-transparent duration-500", - !isSelected && - (effectiveTime ?? 0) >= (event.start_time ?? 0) - 0.5 && - (effectiveTime ?? 0) <= - (event.end_time ?? event.start_time ?? 0) + 0.5 && - "bg-secondary-highlight", )} >
@@ -480,12 +482,18 @@ function EventList({
= (event.start_time ?? 0) - 0.5 && + (effectiveTime ?? 0) <= + (event.end_time ?? event.start_time ?? 0) + 0.5 + ? "bg-selected" + : "bg-muted-foreground", )} onClick={(e) => { e.stopPropagation(); - handleObjectSelect(isSelected ? undefined : event); + onSeek(event.start_time ?? 0); + handleObjectSelect(event); }} + role="button" > {getIconForLabel( event.sub_label ? event.label + "-verified" : event.label, @@ -497,6 +505,7 @@ function EventList({ onClick={(e) => { e.stopPropagation(); onSeek(event.start_time ?? 0); + handleObjectSelect(event); }} role="button" > @@ -532,8 +541,10 @@ function EventList({
@@ -546,6 +557,7 @@ type LifecycleItemProps = { isActive?: boolean; onSeek?: (timestamp: number, play?: boolean) => void; effectiveTime?: number; + isTimelineActive?: boolean; }; function LifecycleItem({ @@ -553,6 +565,7 @@ function LifecycleItem({ isActive, onSeek, effectiveTime, + isTimelineActive = false, }: LifecycleItemProps) { const { t } = useTranslation("views/events"); const { data: config } = useSWR("config"); @@ -617,8 +630,9 @@ function LifecycleItem({
= (item?.timestamp ?? 0)) && + isTimelineActive && "fill-selected duration-300", )} /> @@ -673,10 +687,14 @@ function ObjectTimeline({ eventId, onSeek, effectiveTime, + startTime, + endTime, }: { eventId: string; onSeek: (ts: number, play?: boolean) => void; effectiveTime?: number; + startTime?: number; + endTime?: number; }) { const { t } = useTranslation("views/events"); const { data: timeline, isValidating } = useSWR([ @@ -698,9 +716,17 @@ function ObjectTimeline({ ); } + // Check if current time is within the event's start/stop range + const isWithinEventRange = + effectiveTime !== undefined && + startTime !== undefined && + endTime !== undefined && + effectiveTime >= startTime && + effectiveTime <= endTime; + // Calculate how far down the blue line should extend based on effectiveTime const calculateLineHeight = () => { - if (!timeline || timeline.length === 0) return 0; + if (!timeline || timeline.length === 0 || !isWithinEventRange) return 0; const currentTime = effectiveTime ?? 0; @@ -742,15 +768,19 @@ function ObjectTimeline({ ); }; - const blueLineHeight = calculateLineHeight(); + const activeLineHeight = calculateLineHeight(); return (
-
+ {isWithinEventRange && ( +
+ )}
{timeline.map((event, idx) => { const isActive = @@ -763,6 +793,7 @@ function ObjectTimeline({ onSeek={onSeek} isActive={isActive} effectiveTime={effectiveTime} + isTimelineActive={isWithinEventRange} /> ); })} diff --git a/web/src/context/detail-stream-context.tsx b/web/src/context/detail-stream-context.tsx index a148833e7..c1faae12c 100644 --- a/web/src/context/detail-stream-context.tsx +++ b/web/src/context/detail-stream-context.tsx @@ -7,6 +7,7 @@ export interface DetailStreamContextType { currentTime: number; camera: string; annotationOffset: number; // milliseconds + setSelectedObjectIds: React.Dispatch>; setAnnotationOffset: (ms: number) => void; toggleObjectSelection: (id: string | undefined) => void; isDetailMode: boolean; @@ -69,6 +70,7 @@ export function DetailStreamProvider({ camera, annotationOffset, setAnnotationOffset, + setSelectedObjectIds, toggleObjectSelection, isDetailMode, };