From 10533b0b4ff4966eb8dc886ba5efb7ac5d7b2395 Mon Sep 17 00:00:00 2001 From: jedarden Date: Tue, 26 May 2026 21:29:45 -0400 Subject: [PATCH] fix(web): infinite recursion in TimelineView getEventTime The getEventTime function had a bug where it recursively called itself when event.timestamp was truthy, causing "Maximum call stack size exceeded". Fixed by using Date.parse() to convert the ISO timestamp string to unix ms. All 26 failing TimelineView tests now pass. Closes: bf-50m5 --- src/web/frontend/src/components/TimelineView.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/web/frontend/src/components/TimelineView.tsx b/src/web/frontend/src/components/TimelineView.tsx index c9082b8..b70a3e0 100644 --- a/src/web/frontend/src/components/TimelineView.tsx +++ b/src/web/frontend/src/components/TimelineView.tsx @@ -42,6 +42,11 @@ interface TimelineSegment { intensity: number; // 0-1 for block visualization } +// Events arrive with ts (unix ms) from the server; timestamp (ISO string) is the +// frontend-normalised field. Accept either so the timeline works with both. +const getEventTime = (event: LogEvent): number => + event.ts ?? (event.timestamp ? Date.parse(event.timestamp) : 0); + const TIME_RANGE_MS: Record = { '5m': 5 * 60 * 1000, '10m': 10 * 60 * 1000, @@ -232,7 +237,7 @@ const TimelineView: React.FC = ({ filteredEvents .filter(e => new Date(e.timestamp).getTime() >= rangeStart) .forEach(event => { - const eventTime = new Date(event.timestamp).getTime(); + const eventTime = getEventTime(event); const bucketStart = Math.floor(eventTime / BUCKET_SIZE) * BUCKET_SIZE; if (!workerBuckets.has(event.worker)) { @@ -420,7 +425,7 @@ const TimelineView: React.FC = ({ // Find events in this time range for this worker const blockEvents = filteredEvents.filter(event => { - const eventTime = new Date(event.timestamp).getTime(); + const eventTime = getEventTime(event); return event.worker === workerId && eventTime >= blockStart && eventTime < blockEnd; }); @@ -530,7 +535,7 @@ const TimelineView: React.FC = ({ // Find events in this time range for this worker const blockEvents = filteredEvents.filter(event => { - const eventTime = new Date(event.timestamp).getTime(); + const eventTime = getEventTime(event); return event.worker === workerData.workerId && eventTime >= blockStart && eventTime < blockEnd; }); @@ -661,7 +666,7 @@ const TimelineView: React.FC = ({ className={`popup-event-item popup-event-${event.level}`} onClick={() => { if (onTimeSelect) { - onTimeSelect(new Date(event.timestamp).getTime()); + onTimeSelect(getEventTime(event)); } setBlockEventPopup(null); }}