diff --git a/src/Web/autopilot-monitor-web/app/sessions/components/EventTimeline.tsx b/src/Web/autopilot-monitor-web/app/sessions/components/EventTimeline.tsx
index 05f49156..497e435c 100644
--- a/src/Web/autopilot-monitor-web/app/sessions/components/EventTimeline.tsx
+++ b/src/Web/autopilot-monitor-web/app/sessions/components/EventTimeline.tsx
@@ -180,8 +180,12 @@ export default function EventTimeline({
Raw Events ({sortedBySequence.length})
- {sortedBySequence.map((ev) => (
-
+ {sortedBySequence.map((ev, i) => (
+ 0 ? getDisplayTime(sortedBySequence[i - 1]) : null}
+ />
))}
@@ -341,11 +345,12 @@ function PhaseSection({
{isExpanded && (
- {events.map((event) => (
+ {events.map((event, i) => (
0 ? getDisplayTime(events[i - 1]) : null}
/>
))}
@@ -372,7 +377,32 @@ const BACKFILL_TOOLTIP =
"If enrollment progressed afterwards, this error was already resolved by a retry. " +
"The timestamp shown is the original event-log time.";
-function EventRow({ event, showScriptOutput }: { event: EnrollmentEvent; showScriptOutput?: boolean }) {
+// Display timestamp of a row: backfilled events show the original event-log time.
+function getDisplayTime(event: EnrollmentEvent): Date {
+ return getBackfillInfo(event).recordedAt ?? new Date(event.timestamp);
+}
+
+// Rows render time-of-day only, so a multi-hour/multi-day gap to the previous row
+// (and the date change it implies) is invisible without expanding event details.
+// Shown on the row AFTER the gap; hover reveals the full date.
+function GapBadge({ prevTime, eventTime }: { prevTime: Date | null; eventTime: Date }) {
+ if (!prevTime) return null;
+ const gapMs = eventTime.getTime() - prevTime.getTime();
+ if (gapMs < 60 * 60 * 1000) return null;
+ const label = gapMs >= 48 * 60 * 60 * 1000
+ ? `+${Math.round(gapMs / (24 * 60 * 60 * 1000))}d`
+ : `+${Math.round(gapMs / (60 * 60 * 1000))}h`;
+ return (
+
+ ⏱ {label}
+
+ );
+}
+
+function EventRow({ event, showScriptOutput, prevDisplayTime }: { event: EnrollmentEvent; showScriptOutput?: boolean; prevDisplayTime?: Date | null }) {
const [showDetails, setShowDetails] = useState(false);
const [showRaw, setShowRaw] = useState(false);
const [copied, setCopied] = useState(false);
@@ -458,6 +488,7 @@ function EventRow({ event, showScriptOutput }: { event: EnrollmentEvent; showScr
(reported {new Date(event.timestamp).toLocaleTimeString()})
)}
+
{isBackfilled && (
normalizeEventDataForDisplay(event.data), [event.data]);
const hasDetails = detailData && Object.keys(detailData).length > 0;
@@ -806,6 +837,7 @@ function RawEventRow({ event }: { event: EnrollmentEvent }) {
{event.sequence}
{(recordedAt ?? new Date(event.timestamp)).toLocaleTimeString()}
+
{event.severity}
{isBackfilled && (
⟲