@workflow/web 5.0.0-beta.23 → 5.0.0-beta.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/build/client/assets/{highlighted-body-B3W2YXNL-pQbU-Oll.js → highlighted-body-B3W2YXNL-QrddlyZu.js} +1 -1
  2. package/build/client/assets/{home-Dz43xne_.js → home-BNApVOct.js} +2 -2
  3. package/build/client/assets/{manifest-608c3c54.js → manifest-379f050f.js} +1 -1
  4. package/build/client/assets/{mermaid-3ZIDBTTL-C_xy8SxZ.js → mermaid-3ZIDBTTL-Cg-Mp5Kj.js} +218 -100
  5. package/build/client/assets/{root-BlFmfRST.js → root-BsPxYsbK.js} +1 -1
  6. package/build/client/assets/root-F_dqJDC7.css +1 -0
  7. package/build/client/assets/{run-detail-C34zz02I.js → run-detail-sr7StYc6.js} +354 -331
  8. package/build/client/assets/server-build-DVBDkRDS.css +1 -0
  9. package/build/client/assets/{workflow-graph-viewer-BlDVZ5AU.js → workflow-graph-viewer-CcCwLmnF.js} +1 -1
  10. package/build/client/assets/{zstd-browser-decoder-Biv4GTD9.js → zstd-browser-decoder-OOeWOMJw.js} +1 -1
  11. package/build/server/assets/{app-BgELNM37.js → app-e2FYIgWU.js} +5 -1
  12. package/build/server/assets/{highlighted-body-B3W2YXNL-CP60Gm_l.js → highlighted-body-B3W2YXNL-B7xcG7gl.js} +6 -2
  13. package/build/server/assets/{index-D7poz6vJ.js → index-BELZxbAO.js} +7 -3
  14. package/build/server/assets/{index-C7C6cDW5.js → index-BafExO0s.js} +4 -0
  15. package/build/server/assets/{index-B8YoYr9f.js → index-DIXsjgfZ.js} +4 -0
  16. package/build/server/assets/{index-meg9qk8y.js → index-Dq5jTBN4.js} +4 -0
  17. package/build/server/assets/{mermaid-3ZIDBTTL-PK-HMOJq.js → mermaid-3ZIDBTTL-DQqBhQ9Y.js} +6 -2
  18. package/build/server/assets/{server-build-DAfWosK8.js → server-build-D7EgG_DH.js} +745 -510
  19. package/build/server/assets/{token-BCYgRbLT.js → token-guLCf66r.js} +6 -2
  20. package/build/server/assets/{token-util-M95T0pVo.js → token-util-CCeU4-vR.js} +6 -2
  21. package/build/server/assets/{zstd-browser-decoder-eXH_mKQG.js → zstd-browser-decoder-CcinVfMP.js} +7 -3
  22. package/build/server/index.js +5 -1
  23. package/package.json +5 -5
  24. package/build/client/assets/root-61NXpLSs.css +0 -1
  25. package/build/client/assets/server-build-B8TvrR_Z.css +0 -1
@@ -1,6 +1,6 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports, f as reactDomExports, G as ReactDOM, B as useNavigate, C as useSearchParams, A as Link, w as withComponentProps, H as useParams } from "./index-BXZSIDEp.js";
2
- import { q as Check, O as Copy, j as ChevronRight, o as ChevronDown, C as CircleAlert, Q as parseStepName, B as parseWorkflowName, U as ErrorCard, V as format, Z as Zap, S as Send, R as ResolveHookModal, Y as Circle, X, p as ChevronUp, N as ErrorBoundary, I as unwrapServerActionResult, u as unwrapOrThrow, W as WorkflowWebAPIError, _ as useEscapeKeydown, t as composeEventHandlers, $ as useCallbackRef, a0 as useLayoutEffect2, s as useControllableState, a1 as useId, a2 as createContext2, v as Presence, x as createContextScope, l as hideOthers, m as ReactRemoveScroll, a3 as useFocusGuards, a4 as LAYOUT, a5 as wakeUpRun, r as resumeHook, A as Alert, c as AlertTitle, d as AlertDescription, a as Skeleton$1, a6 as RunActionsButtons, F as StatusBadge, e as CopyableText, b as RelativeTime, T as Tabs, K as TabsList, L as TabsTrigger, M as TabsContent, y as cancelRun, a7 as recreateRun } from "./workflow-graph-viewer-BlDVZ5AU.js";
3
- import { c as createLucideIcon, O as cn, U as DataInspector, W as DecryptClickContext, X as Button, Y as Spinner, Z as Lock, $ as RESERVED_ATTRIBUTE_KEY_PREFIX, a0 as ContextCardProvider, h as useToast, a1 as Skeleton, a2 as Yr, a3 as isEncryptedMarker, a4 as TimestampTooltip, a5 as formatDuration, a6 as _r, a7 as RunClickContext, a8 as StreamClickContext, a9 as isExpiredMarker, aa as isDoStreamStep, ab as extractConversation, ac as hasEncryptedFields, ad as EVENT_DATA_REF_FIELDS, ae as useSidebarDataOptional, af as clsx, I as cva, ag as useRowWindow, ah as isSpanDimmedBySearch, ai as ROW_HEIGHT_PX, aj as getSpanDurationMs, ak as formatDurationPrecise, al as TooltipProvider, am as ActiveSpanProvider, an as useActiveSpan, ao as useSidebarData, ap as useReducedMotion, aq as searchSpans, ar as computeRootBounds, as as computeTimeMarkers, at as getHighResInMs, au as scrollRowIntoView, av as TIMELINE_PADDING_PX, aw as Timeline, ax as TimelineHeader, ay as IconButton, az as Tooltip, aA as TooltipTrigger, aB as TooltipContent, aC as SidebarDataProvider, aD as hydrateResourceIOWithKey, aE as hydrateResourceIO, aF as fetchHook, l as fetchEvents, H as fetchRun, aG as fetchStep, aH as fetchStreams, aI as Slot, G as useComposedRefs, aJ as Slottable, e as cn$1, aK as buttonVariants, aL as fetchEvent, aM as fetchEventsByCorrelationId, aN as isEncryptedData, aO as hydrateData, aP as getWebRevivers, T as Tooltip$1, a as TooltipTrigger$1, b as TooltipContent$1, aQ as LIVE_UPDATE_INTERVAL_MS$1, u as useServerConfig, aR as getEncryptionKeyForRun, t as toast, L as LoaderCircle, aS as StreamViewer } from "./mermaid-3ZIDBTTL-C_xy8SxZ.js";
2
+ import { q as Check, O as Copy, j as ChevronRight, o as ChevronDown, C as CircleAlert, Q as parseStepName, B as parseWorkflowName, U as ErrorCard, V as format, Z as Zap, S as Send, R as ResolveHookModal, Y as Circle, X, p as ChevronUp, N as ErrorBoundary, u as unwrapOrThrow, W as WorkflowWebAPIError, I as unwrapServerActionResult, _ as useEscapeKeydown, t as composeEventHandlers, $ as useCallbackRef, a0 as useLayoutEffect2, s as useControllableState, a1 as useId, a2 as createContext2, v as Presence, x as createContextScope, l as hideOthers, m as ReactRemoveScroll, a3 as useFocusGuards, a4 as LAYOUT, a5 as wakeUpRun, r as resumeHook, A as Alert, c as AlertTitle, d as AlertDescription, a as Skeleton$1, a6 as RunActionsButtons, F as StatusBadge, e as CopyableText, b as RelativeTime, T as Tabs, K as TabsList, L as TabsTrigger, M as TabsContent, y as cancelRun, a7 as recreateRun } from "./workflow-graph-viewer-CcCwLmnF.js";
3
+ import { c as createLucideIcon, O as cn, U as DataInspector, W as DecryptClickContext, X as Button, Y as Spinner, Z as Lock, $ as RESERVED_ATTRIBUTE_KEY_PREFIX, a0 as ContextCardProvider, h as useToast, a1 as Skeleton, a2 as Yr, a3 as isEncryptedMarker, a4 as TimestampTooltip, a5 as formatDuration, a6 as _r, a7 as RunClickContext, a8 as StreamClickContext, a9 as isExpiredMarker, aa as isDoStreamStep, ab as extractConversation, ac as hasEncryptedFields, ad as EVENT_DATA_REF_FIELDS, ae as useSidebarDataOptional, af as clsx, I as cva, ag as useRowWindow, ah as isSpanDimmedBySearch, ai as ROW_HEIGHT_PX, aj as getSpanDurationMs, ak as formatDurationPrecise, al as TooltipProvider, am as ActiveSpanProvider, an as useActiveSpan, ao as useSidebarData, ap as useReducedMotion, aq as searchSpans, ar as computeRootBounds, as as computeTimeMarkers, at as getHighResInMs, au as scrollRowIntoView, av as TIMELINE_PADDING_PX, aw as Timeline, ax as TimelineHeader, ay as IconButton, az as Tooltip, aA as TooltipTrigger, aB as TooltipContent, aC as SidebarDataProvider, aD as fetchHook, l as fetchEvents, aE as hydrateResourceIO, aF as hydrateResourceIOWithKey, H as fetchRun, aG as fetchStep, aH as fetchStreams, aI as Slot, G as useComposedRefs, aJ as Slottable, e as cn$1, aK as buttonVariants, aL as fetchEvent, aM as fetchEventsByCorrelationId, aN as isEncryptedData, aO as hydrateData, aP as getWebRevivers, T as Tooltip$1, a as TooltipTrigger$1, b as TooltipContent$1, aQ as LIVE_UPDATE_INTERVAL_MS$1, u as useServerConfig, aR as getEncryptionKeyForRun, t as toast, L as LoaderCircle, aS as StreamViewer } from "./mermaid-3ZIDBTTL-Cg-Mp5Kj.js";
4
4
  import { decrypt, importKey } from "./encryption-g14N5vQl.js";
5
5
  import "./index-B6-SzLmT.js";
6
6
  /**
@@ -327,6 +327,18 @@ function formatEventTime(date) {
327
327
  hour12: false
328
328
  }) + "." + date.getMilliseconds().toString().padStart(3, "0");
329
329
  }
330
+ function parseEventDate(value) {
331
+ if (value == null)
332
+ return null;
333
+ const date = value instanceof Date ? value : new Date(String(value));
334
+ return Number.isNaN(date.getTime()) ? null : date;
335
+ }
336
+ function getEffectiveEventDate$1(event) {
337
+ return parseEventDate(event.occurredAt) ?? new Date(event.createdAt);
338
+ }
339
+ function getEffectiveEventTime(event) {
340
+ return getEffectiveEventDate$1(event).getTime();
341
+ }
330
342
  function formatEventType(eventType) {
331
343
  return eventType.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
332
344
  }
@@ -367,13 +379,13 @@ function buildNameMaps(events, run) {
367
379
  return { correlationNameMap, workflowName };
368
380
  }
369
381
  function buildDurationMap(events) {
370
- const chronological = [...events].sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
382
+ const chronological = [...events].sort((a, b) => getEffectiveEventTime(a) - getEffectiveEventTime(b));
371
383
  const createdTimes = /* @__PURE__ */ new Map();
372
384
  const firstStartedTimes = /* @__PURE__ */ new Map();
373
385
  const startedTimes = /* @__PURE__ */ new Map();
374
386
  const durations = /* @__PURE__ */ new Map();
375
387
  for (const event of chronological) {
376
- const ts = new Date(event.createdAt).getTime();
388
+ const ts = getEffectiveEventTime(event);
377
389
  const key = event.correlationId ?? "__run__";
378
390
  const type = event.eventType;
379
391
  if (type === "step_created" || type === "run_created") {
@@ -596,7 +608,7 @@ const SORT_OPTIONS = [
596
608
  { value: "desc", label: "Newest" },
597
609
  { value: "asc", label: "Oldest" }
598
610
  ];
599
- function RowsSkeleton() {
611
+ function RowsSkeleton({ showSeparateEventOccurrenceTimestamps = false }) {
600
612
  return jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-hidden", children: Array.from({ length: 16 }, (_, i) => jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-0", style: { height: 40 }, children: [jsxRuntimeExports.jsxs("div", { className: "relative flex-shrink-0 self-stretch flex items-center", style: { width: GUTTER_WIDTH }, children: [jsxRuntimeExports.jsx("div", { style: {
601
613
  position: "absolute",
602
614
  left: 8,
@@ -608,9 +620,9 @@ function RowsSkeleton() {
608
620
  height: i % 4 === 0 ? 8 : 6,
609
621
  borderRadius: "50%",
610
622
  marginLeft: i % 4 === 0 ? 5 : 6
611
- } })] }), jsxRuntimeExports.jsx("div", { className: "w-5 flex-shrink-0 flex items-center justify-center", children: jsxRuntimeExports.jsx(Skeleton, { className: "w-5 h-5", style: { borderRadius: 4 } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "70%" } }) }), jsxRuntimeExports.jsxs("div", { className: "min-w-0 px-4 flex items-center gap-1.5", style: { flex: "2 1 0%" }, children: [jsxRuntimeExports.jsx(Skeleton, { className: "flex-shrink-0", style: { width: 6, height: 6, borderRadius: "50%" } }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "60%" } })] }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "50%" } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "75%" } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "75%" } }) })] }, i)) });
623
+ } })] }), jsxRuntimeExports.jsx("div", { className: "w-5 flex-shrink-0 flex items-center justify-center", children: jsxRuntimeExports.jsx(Skeleton, { className: "w-5 h-5", style: { borderRadius: 4 } }) }), showSeparateEventOccurrenceTimestamps && jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "70%" } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "70%" } }) }), jsxRuntimeExports.jsxs("div", { className: "min-w-0 px-4 flex items-center gap-1.5", style: { flex: "2 1 0%" }, children: [jsxRuntimeExports.jsx(Skeleton, { className: "flex-shrink-0", style: { width: 6, height: 6, borderRadius: "50%" } }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "60%" } })] }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "50%" } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "75%" } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "75%" } }) })] }, i)) });
612
624
  }
613
- function EventRow$1({ event, index, isFirst, isLast, isExpanded, onToggleExpand, activeGroupKey, selectedGroupKey, selectedGroupRange, correlationNameMap, workflowName, durationMap, onSelectGroup, onHoverGroup, onLoadEventData, cachedEventData, onCacheEventData, encryptionKey, onEncryptedDataDetected, suppressGroupDimming = false }) {
625
+ function EventRow$1({ event, index, isFirst, isLast, isExpanded, onToggleExpand, activeGroupKey, selectedGroupKey, selectedGroupRange, correlationNameMap, workflowName, durationMap, onSelectGroup, onHoverGroup, onLoadEventData, cachedEventData, onCacheEventData, encryptionKey, onEncryptedDataDetected, suppressGroupDimming = false, showSeparateEventOccurrenceTimestamps = false }) {
614
626
  const [isLoading, setIsLoading] = reactExports.useState(false);
615
627
  const [loadedEventData, setLoadedEventData] = reactExports.useState(cachedEventData);
616
628
  const [loadError, setLoadError] = reactExports.useState(null);
@@ -623,6 +635,8 @@ function EventRow$1({ event, index, isFirst, isLast, isExpanded, onToggleExpand,
623
635
  const rowGroupKey = isRunLevel(event.eventType) ? "__run__" : event.correlationId ?? void 0;
624
636
  const statusDotColor = getStatusDotColor(event.eventType);
625
637
  const createdAt = new Date(event.createdAt);
638
+ const occurredAt = parseEventDate(event.occurredAt);
639
+ const displayedCreatedAt = showSeparateEventOccurrenceTimestamps ? createdAt : getEffectiveEventDate$1(event);
626
640
  const hasExistingEventData = "eventData" in event && event.eventData != null;
627
641
  const isRun = isRunLevel(event.eventType);
628
642
  const eventName = isRun ? workflowName ?? "-" : event.correlationId ? correlationNameMap.get(event.correlationId) ?? "-" : "-";
@@ -726,7 +740,7 @@ function EventRow$1({ event, index, isFirst, isLast, isExpanded, onToggleExpand,
726
740
  }, children: jsxRuntimeExports.jsx(ChevronRight, { className: "h-3 w-3 transition-transform", style: {
727
741
  color: "var(--ds-gray-900)",
728
742
  transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)"
729
- } }) }), jsxRuntimeExports.jsx("div", { className: "tabular-nums min-w-0 px-4", style: { color: "var(--ds-gray-900)", flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(TimestampTooltip, { date: createdAt, children: jsxRuntimeExports.jsx("span", { children: formatEventTime(createdAt) }) }) }), jsxRuntimeExports.jsx("div", { className: "font-medium min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", style: { color: "var(--ds-gray-900)" }, children: [jsxRuntimeExports.jsxs("span", { style: {
743
+ } }) }), showSeparateEventOccurrenceTimestamps && jsxRuntimeExports.jsx("div", { className: "tabular-nums min-w-0 px-4", style: { color: "var(--ds-gray-900)", flex: "2 1 0%" }, children: occurredAt ? jsxRuntimeExports.jsx(TimestampTooltip, { date: occurredAt, children: jsxRuntimeExports.jsx("span", { children: formatEventTime(occurredAt) }) }) : "-" }), jsxRuntimeExports.jsx("div", { className: "tabular-nums min-w-0 px-4", style: { color: "var(--ds-gray-900)", flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(TimestampTooltip, { date: displayedCreatedAt, children: jsxRuntimeExports.jsx("span", { children: formatEventTime(displayedCreatedAt) }) }) }), jsxRuntimeExports.jsx("div", { className: "font-medium min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", style: { color: "var(--ds-gray-900)" }, children: [jsxRuntimeExports.jsxs("span", { style: {
730
744
  position: "relative",
731
745
  display: "inline-flex",
732
746
  width: 6,
@@ -755,7 +769,7 @@ function EventRow$1({ event, index, isFirst, isLast, isExpanded, onToggleExpand,
755
769
  color: "var(--ds-red-900)"
756
770
  }, children: loadError }) : isLoading || loadedEventData === null && !hasAttemptedLoad && event.correlationId ? jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 p-3", children: [jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "75%" } }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "50%" } }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "60%" } })] }) : jsxRuntimeExports.jsx("div", { className: "p-2 text-xs", style: { color: "var(--ds-gray-900)" }, children: "No data" })] })] })] });
757
771
  }
758
- function EventListViewInner({ events, run, onLoadEventData, hasMoreEvents = false, isLoadingMoreEvents = false, onLoadMoreEvents, encryptionKey, isLoading = false, sortOrder: sortOrderProp, onSortOrderChange, onDecrypt, isDecrypting = false, hasEncryptedData: hasEncryptedDataProp = false, onExactIdSearch }) {
772
+ function EventListViewInner({ events, run, onLoadEventData, hasMoreEvents = false, isLoadingMoreEvents = false, onLoadMoreEvents, encryptionKey, isLoading = false, sortOrder: sortOrderProp, onSortOrderChange, onDecrypt, isDecrypting = false, hasEncryptedData: hasEncryptedDataProp = false, onExactIdSearch, showSeparateEventOccurrenceTimestamps = false }) {
759
773
  const toast2 = useToast();
760
774
  const [internalSortOrder, setInternalSortOrder] = reactExports.useState("asc");
761
775
  const effectiveSortOrder = sortOrderProp ?? internalSortOrder;
@@ -781,7 +795,7 @@ function EventListViewInner({ events, run, onLoadEventData, hasMoreEvents = fals
781
795
  if (sourceEvents.length === 0)
782
796
  return [];
783
797
  const dir = effectiveSortOrder === "desc" ? -1 : 1;
784
- return [...sourceEvents].sort((a, b) => dir * (new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()));
798
+ return [...sourceEvents].sort((a, b) => dir * (getEffectiveEventTime(a) - getEffectiveEventTime(b)));
785
799
  }, [events, effectiveSortOrder, isExactSearchActive, searchResults]);
786
800
  const hasEncryptedInlineData = reactExports.useMemo(() => {
787
801
  const sourceEvents = isExactSearchActive ? searchResults : events;
@@ -1009,14 +1023,14 @@ function EventListViewInner({ events, run, onLoadEventData, hasMoreEvents = fals
1009
1023
  borderColor: "var(--ds-gray-alpha-200)",
1010
1024
  color: "var(--ds-gray-900)",
1011
1025
  backgroundColor: "var(--ds-background-100)"
1012
- }, children: [jsxRuntimeExports.jsx("div", { className: "flex-shrink-0", style: { width: GUTTER_WIDTH } }), jsxRuntimeExports.jsx("div", { className: "w-5 flex-shrink-0" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: "Time" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: "Event Type" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: "Name" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: "Correlation ID" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: "Event ID" })] }), isRefetching || searchLoading ? jsxRuntimeExports.jsx(RowsSkeleton, {}) : sortedEvents.length === 0 ? jsxRuntimeExports.jsx("div", { className: "flex flex-1 items-center justify-center px-6 text-center text-sm", style: { color: "var(--ds-gray-700)" }, children: searchNotFound && searchQuery.trim() ? `No events found for ${searchQuery.trim()}` : searchError ? searchError : parsedSearchId && searchQuery.trim() && !onExactIdSearch ? "Exact ID search is unavailable in this view." : "No events found" }) : jsxRuntimeExports.jsx(Yr, { ref: virtuosoRef, totalCount: sortedEvents.length, overscan: 20, defaultItemHeight: 40, endReached: () => {
1026
+ }, children: [jsxRuntimeExports.jsx("div", { className: "flex-shrink-0", style: { width: GUTTER_WIDTH } }), jsxRuntimeExports.jsx("div", { className: "w-5 flex-shrink-0" }), showSeparateEventOccurrenceTimestamps && jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: "Occurred" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: "Created" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: "Event Type" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: "Name" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: "Correlation ID" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: "Event ID" })] }), isRefetching || searchLoading ? jsxRuntimeExports.jsx(RowsSkeleton, { showSeparateEventOccurrenceTimestamps }) : sortedEvents.length === 0 ? jsxRuntimeExports.jsx("div", { className: "flex flex-1 items-center justify-center px-6 text-center text-sm", style: { color: "var(--ds-gray-700)" }, children: searchNotFound && searchQuery.trim() ? `No events found for ${searchQuery.trim()}` : searchError ? searchError : parsedSearchId && searchQuery.trim() && !onExactIdSearch ? "Exact ID search is unavailable in this view." : "No events found" }) : jsxRuntimeExports.jsx(Yr, { ref: virtuosoRef, totalCount: sortedEvents.length, overscan: 20, defaultItemHeight: 40, endReached: () => {
1013
1027
  if (isExactSearchActive || !hasMoreEvents || isLoadingMoreEvents) {
1014
1028
  return;
1015
1029
  }
1016
1030
  void (onLoadMoreEvents == null ? void 0 : onLoadMoreEvents());
1017
1031
  }, itemContent: (index) => {
1018
1032
  const ev = sortedEvents[index];
1019
- return jsxRuntimeExports.jsx(EventRow$1, { event: ev, index, isFirst: index === 0, isLast: index === sortedEvents.length - 1, isExpanded: expandedEventIds.has(ev.eventId), onToggleExpand: toggleEventExpanded, activeGroupKey, selectedGroupKey, selectedGroupRange, correlationNameMap, workflowName, durationMap, onSelectGroup, onHoverGroup, onLoadEventData, cachedEventData: eventDataCacheRef.current.get(ev.eventId) ?? null, onCacheEventData: cacheEventData, encryptionKey, onEncryptedDataDetected: handleEncryptedDataDetected, suppressGroupDimming: isExactSearchActive });
1033
+ return jsxRuntimeExports.jsx(EventRow$1, { event: ev, index, isFirst: index === 0, isLast: index === sortedEvents.length - 1, isExpanded: expandedEventIds.has(ev.eventId), onToggleExpand: toggleEventExpanded, activeGroupKey, selectedGroupKey, selectedGroupRange, correlationNameMap, workflowName, durationMap, onSelectGroup, onHoverGroup, onLoadEventData, cachedEventData: eventDataCacheRef.current.get(ev.eventId) ?? null, onCacheEventData: cacheEventData, encryptionKey, onEncryptedDataDetected: handleEncryptedDataDetected, suppressGroupDimming: isExactSearchActive, showSeparateEventOccurrenceTimestamps });
1020
1034
  }, style: { flex: 1, minHeight: 0 } }), jsxRuntimeExports.jsxs("div", { className: "relative flex-shrink-0 flex items-center h-10 border-t px-4 text-xs", style: {
1021
1035
  borderColor: "var(--ds-gray-alpha-200)",
1022
1036
  color: "var(--ds-gray-900)",
@@ -1026,6 +1040,22 @@ function EventListViewInner({ events, run, onLoadEventData, hasMoreEvents = fals
1026
1040
  function EventListView(props) {
1027
1041
  return jsxRuntimeExports.jsx(ContextCardProvider, { children: jsxRuntimeExports.jsx(EventListViewInner, { ...props }) });
1028
1042
  }
1043
+ const COL_TEMPLATE = "340px 1px minmax(50px, 1fr)";
1044
+ const ROWS = [
1045
+ { id: "r0", name: 62, off: 0, bar: 72 },
1046
+ { id: "r1", name: 78, off: 6, bar: 48 },
1047
+ { id: "r2", name: 50, off: 10, bar: 55 },
1048
+ { id: "r3", name: 84, off: 18, bar: 30 },
1049
+ { id: "r4", name: 45, off: 18, bar: 42 },
1050
+ { id: "r5", name: 66, off: 34, bar: 38 },
1051
+ { id: "r6", name: 55, off: 41, bar: 25 },
1052
+ { id: "r7", name: 40, off: 50, bar: 30 }
1053
+ ];
1054
+ const HEADER_MARKERS = ["m0", "m1", "m2", "m3"];
1055
+ const HeaderDivider = () => jsxRuntimeExports.jsx("div", { className: "flex justify-center", children: jsxRuntimeExports.jsx("span", { "aria-hidden": true, className: "h-full w-px bg-gray-alpha-400" }) });
1056
+ function TraceViewerSkeleton() {
1057
+ return jsxRuntimeExports.jsxs("output", { "aria-busy": "true", "aria-label": "Loading trace", className: "flex flex-col w-full h-full min-h-0 bg-background-100", children: [jsxRuntimeExports.jsx("span", { className: "sr-only", children: "Loading trace…" }), jsxRuntimeExports.jsxs("div", { className: "shrink-0 grid", style: { gridTemplateColumns: COL_TEMPLATE }, children: [jsxRuntimeExports.jsxs("div", { className: "h-10 min-h-10 flex items-center border-b border-gray-alpha-400 pl-4 pr-2 gap-1.5", children: [jsxRuntimeExports.jsx(Skeleton, { className: "w-3.5 h-3.5 shrink-0 rounded-sm" }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3.5 w-40" })] }), jsxRuntimeExports.jsx(HeaderDivider, {}), jsxRuntimeExports.jsx("div", { className: "h-10 min-h-10 flex items-end border-b border-gray-alpha-400 px-4 pb-1 gap-2", children: jsxRuntimeExports.jsx("div", { className: "relative flex-1 flex items-end justify-between", children: HEADER_MARKERS.map((id) => jsxRuntimeExports.jsx(Skeleton, { className: "h-3.5 w-9" }, id)) }) })] }), jsxRuntimeExports.jsxs("div", { className: "grid flex-1 min-h-0 overflow-hidden", style: { gridTemplateColumns: COL_TEMPLATE }, children: [jsxRuntimeExports.jsx("div", { className: "block overflow-visible", children: jsxRuntimeExports.jsx("ul", { className: "block divide-y divide-gray-alpha-400 border-b border-gray-alpha-400", children: ROWS.map((row) => jsxRuntimeExports.jsxs("li", { className: "h-10 flex items-center pl-4 pr-2", children: [jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [jsxRuntimeExports.jsx(Skeleton, { className: "w-4 h-4 shrink-0 rounded-sm" }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3.5", style: { width: `${row.name}%` } })] }), jsxRuntimeExports.jsx(Skeleton, { className: "ml-2 h-3.5 w-10 shrink-0" })] }, row.id)) }) }), jsxRuntimeExports.jsx("span", { "aria-hidden": true, className: "h-full w-px bg-gray-alpha-400" }), jsxRuntimeExports.jsx("div", { className: "relative min-h-0", children: ROWS.map((row) => jsxRuntimeExports.jsx("div", { className: "relative h-10", children: jsxRuntimeExports.jsx("div", { className: "absolute inset-x-4 inset-y-0", children: jsxRuntimeExports.jsx(Skeleton, { className: "absolute top-1/2 -translate-y-1/2 h-6 rounded-[0.25rem]", style: { left: `${row.off}%`, width: `${row.bar}%` } }) }) }, row.id)) })] })] });
1058
+ }
1029
1059
  function shouldShowVerticalLine(eventType) {
1030
1060
  if (eventType === "hook_created" || eventType === "hook_received" || eventType === "hook_disposed") {
1031
1061
  return true;
@@ -1081,10 +1111,17 @@ const MARKER_EVENT_TYPES = /* @__PURE__ */ new Set([
1081
1111
  "wait_completed",
1082
1112
  "attr_set"
1083
1113
  ]);
1084
- function convertEventsToSpanEvents(events, filterTypes = true) {
1114
+ const getEventTimestamp = (event) => {
1115
+ const value = (event == null ? void 0 : event.occurredAt) ?? (event == null ? void 0 : event.createdAt);
1116
+ if (!value)
1117
+ return void 0;
1118
+ const date = value instanceof Date ? value : new Date(value);
1119
+ return Number.isNaN(date.getTime()) ? void 0 : date;
1120
+ };
1121
+ function convertEventsToSpanEvents(events, filterTypes = true, options = {}) {
1085
1122
  return events.filter((event) => filterTypes ? MARKER_EVENT_TYPES.has(event.eventType) : true).map((event) => ({
1086
1123
  name: event.eventType,
1087
- timestamp: dateToOtelTime(event.createdAt),
1124
+ timestamp: dateToOtelTime(options.preferOccurredAt ? getEventTimestamp(event) ?? event.createdAt : event.createdAt),
1088
1125
  attributes: {
1089
1126
  eventId: event.eventId,
1090
1127
  correlationId: event.correlationId,
@@ -1104,9 +1141,9 @@ const waitEventsToWaitEntity = (events) => {
1104
1141
  return {
1105
1142
  waitId: startEvent.correlationId,
1106
1143
  runId: startEvent.runId,
1107
- createdAt: startEvent.createdAt,
1144
+ createdAt: getEventTimestamp(startEvent) ?? startEvent.createdAt,
1108
1145
  resumeAt: ((_a = startEvent.eventData) == null ? void 0 : _a.resumeAt) ? new Date(startEvent.eventData.resumeAt) : void 0,
1109
- completedAt: completedEvent == null ? void 0 : completedEvent.createdAt
1146
+ completedAt: getEventTimestamp(completedEvent)
1110
1147
  };
1111
1148
  };
1112
1149
  function waitToSpan(events, maxEndTime, fallbackEndTime = maxEndTime) {
@@ -1163,16 +1200,16 @@ const stepEventsToStepEntity = (events) => {
1163
1200
  status = "running";
1164
1201
  attempt += 1;
1165
1202
  if (!startedAt)
1166
- startedAt = e.createdAt;
1203
+ startedAt = getEventTimestamp(e) ?? e.createdAt;
1167
1204
  completedAt = void 0;
1168
1205
  break;
1169
1206
  case "step_completed":
1170
1207
  status = "completed";
1171
- completedAt = e.createdAt;
1208
+ completedAt = getEventTimestamp(e) ?? e.createdAt;
1172
1209
  break;
1173
1210
  case "step_failed":
1174
1211
  status = "failed";
1175
- completedAt = e.createdAt;
1212
+ completedAt = getEventTimestamp(e) ?? e.createdAt;
1176
1213
  break;
1177
1214
  case "step_retrying":
1178
1215
  status = "pending";
@@ -1189,8 +1226,8 @@ const stepEventsToStepEntity = (events) => {
1189
1226
  stepName: ((_a = createdEvent == null ? void 0 : createdEvent.eventData) == null ? void 0 : _a.stepName) ?? "",
1190
1227
  status,
1191
1228
  attempt,
1192
- createdAt: anchorEvent.createdAt,
1193
- updatedAt: (lastEvent == null ? void 0 : lastEvent.createdAt) ?? anchorEvent.createdAt,
1229
+ createdAt: getEventTimestamp(anchorEvent) ?? anchorEvent.createdAt,
1230
+ updatedAt: getEventTimestamp(lastEvent) ?? (lastEvent == null ? void 0 : lastEvent.createdAt) ?? anchorEvent.createdAt,
1194
1231
  startedAt,
1195
1232
  completedAt,
1196
1233
  specVersion: anchorEvent.specVersion
@@ -1207,13 +1244,20 @@ function stepToSpan(stepEvents, maxEndTime) {
1207
1244
  data: step
1208
1245
  };
1209
1246
  const resource = "step";
1210
- const endTime = new Date(step.completedAt ?? maxEndTime);
1211
- const events = convertEventsToSpanEvents(stepEvents, false);
1212
- const spanStartTime = new Date(step.createdAt);
1247
+ const events = convertEventsToSpanEvents(stepEvents, false, {
1248
+ preferOccurredAt: true
1249
+ });
1250
+ const spanStartEvent = stepEvents.find((event) => event.eventType === "step_created") ?? stepEvents[0];
1251
+ const spanStartTime = getEventTimestamp(spanStartEvent) ?? new Date(step.createdAt);
1213
1252
  let activeStartTime = step.startedAt ? new Date(step.startedAt) : void 0;
1214
1253
  const firstStartEvent = stepEvents.find((event) => event.eventType === "step_started");
1215
1254
  if (firstStartEvent) {
1216
- activeStartTime = new Date(firstStartEvent.createdAt);
1255
+ activeStartTime = getEventTimestamp(firstStartEvent) ?? new Date(firstStartEvent.createdAt);
1256
+ }
1257
+ let endTime = new Date(maxEndTime);
1258
+ if (step.completedAt) {
1259
+ const completedEvent = stepEvents.slice().reverse().find((event) => event.eventType === "step_completed" || event.eventType === "step_failed");
1260
+ endTime = getEventTimestamp(completedEvent) ?? new Date(step.completedAt);
1217
1261
  }
1218
1262
  return {
1219
1263
  spanId: String(step.stepId),
@@ -1235,7 +1279,7 @@ function stepToSpan(stepEvents, maxEndTime) {
1235
1279
  };
1236
1280
  }
1237
1281
  const hookEventsToHookEntity = (events) => {
1238
- var _a, _b;
1282
+ var _a;
1239
1283
  const createdEvent = events.find((event) => event.eventType === "hook_created");
1240
1284
  if (!createdEvent) {
1241
1285
  return null;
@@ -1247,10 +1291,10 @@ const hookEventsToHookEntity = (events) => {
1247
1291
  hookId: createdEvent.correlationId,
1248
1292
  runId: createdEvent.runId,
1249
1293
  token: (_a = createdEvent.eventData) == null ? void 0 : _a.token,
1250
- createdAt: createdEvent.createdAt,
1294
+ createdAt: getEventTimestamp(createdEvent) ?? createdEvent.createdAt,
1251
1295
  receivedCount: receivedEvents.length,
1252
- lastReceivedAt: (lastReceivedEvent == null ? void 0 : lastReceivedEvent.createdAt) || void 0,
1253
- disposedAt: ((_b = disposedEvents.at(-1)) == null ? void 0 : _b.createdAt) || void 0
1296
+ lastReceivedAt: getEventTimestamp(lastReceivedEvent),
1297
+ disposedAt: getEventTimestamp(disposedEvents.at(-1))
1254
1298
  };
1255
1299
  };
1256
1300
  function hookToSpan(hookEvents, maxEndTime) {
@@ -1283,15 +1327,26 @@ function hookToSpan(hookEvents, maxEndTime) {
1283
1327
  function runToSpan(run, runEvents, nowTime) {
1284
1328
  var _a;
1285
1329
  const now = nowTime ?? /* @__PURE__ */ new Date();
1330
+ const runCreatedEvent = runEvents.find((event) => event.eventType === "run_created");
1331
+ const runStartedEvent = runEvents.find((event) => event.eventType === "run_started");
1332
+ const terminalEvent = runEvents.slice().reverse().find((event) => event.eventType === "run_completed" || event.eventType === "run_failed" || event.eventType === "run_cancelled");
1333
+ const spanStartTime = getEventTimestamp(runCreatedEvent) ?? new Date(run.createdAt);
1334
+ const activeStartTime = getEventTimestamp(runStartedEvent) ?? (run.startedAt ? new Date(run.startedAt) : void 0);
1335
+ const completedAt = getEventTimestamp(terminalEvent) ?? run.completedAt ?? void 0;
1336
+ const endTime = completedAt ?? now;
1286
1337
  const { input: _i, output: _o, error: _e, ...runIdentity } = run;
1287
1338
  const attributes = {
1288
1339
  resource: "run",
1289
- data: runIdentity
1340
+ data: {
1341
+ ...runIdentity,
1342
+ createdAt: spanStartTime,
1343
+ startedAt: activeStartTime,
1344
+ completedAt
1345
+ }
1290
1346
  };
1291
- const spanStartTime = new Date(run.createdAt);
1292
- const activeStartTime = run.startedAt ? new Date(run.startedAt) : void 0;
1293
- const endTime = run.completedAt ?? now;
1294
- const events = convertEventsToSpanEvents(runEvents, false);
1347
+ const events = convertEventsToSpanEvents(runEvents, false, {
1348
+ preferOccurredAt: true
1349
+ });
1295
1350
  return {
1296
1351
  spanId: String(run.runId),
1297
1352
  name: String(((_a = parseWorkflowName(run.workflowName)) == null ? void 0 : _a.shortName) ?? "?"),
@@ -1361,7 +1416,7 @@ function groupEventsByCorrelation(events) {
1361
1416
  function computeLatestKnownTime(events, run) {
1362
1417
  let latest = new Date(run.createdAt).getTime();
1363
1418
  for (const event of events) {
1364
- const t = new Date(event.createdAt).getTime();
1419
+ const t = (getEventTimestamp(event) ?? new Date(event.createdAt)).getTime();
1365
1420
  if (t > latest)
1366
1421
  latest = t;
1367
1422
  }
@@ -1954,7 +2009,7 @@ const getModuleSpecifierFromName = (value) => {
1954
2009
  }
1955
2010
  return raw;
1956
2011
  };
1957
- const parseDateValue = (value) => {
2012
+ const parseDateValue$1 = (value) => {
1958
2013
  if (value == null) {
1959
2014
  return null;
1960
2015
  }
@@ -1969,14 +2024,14 @@ const parseDateValue = (value) => {
1969
2024
  };
1970
2025
  const formatLocalMillisecondTime = (date) => format(date, "MMM dd HH:mm:ss.SS OO").toUpperCase();
1971
2026
  const localMillisecondTimeOrNull = (value) => {
1972
- const date = parseDateValue(value);
2027
+ const date = parseDateValue$1(value);
1973
2028
  if (!date) {
1974
2029
  return null;
1975
2030
  }
1976
2031
  return formatLocalMillisecondTime(date);
1977
2032
  };
1978
2033
  const timestampWithTooltipOrNull = (value) => {
1979
- const date = parseDateValue(value);
2034
+ const date = parseDateValue$1(value);
1980
2035
  if (!date)
1981
2036
  return null;
1982
2037
  return jsxRuntimeExports.jsx(TimestampTooltip, { date, children: jsxRuntimeExports.jsx("span", { children: formatLocalMillisecondTime(date) }) });
@@ -2183,8 +2238,8 @@ const AttributePanel = ({ data, moduleSpecifier, isLoading, error, expiredAt, on
2183
2238
  return present;
2184
2239
  if (resource === "sleep")
2185
2240
  return present;
2186
- const loadingDefaults = ["input", "output"];
2187
- for (const key of loadingDefaults) {
2241
+ const loadingPlaceholders = ["input", "output"];
2242
+ for (const key of loadingPlaceholders) {
2188
2243
  if (!present.includes(key)) {
2189
2244
  present.push(key);
2190
2245
  }
@@ -2249,7 +2304,23 @@ const DATA_EVENT_TYPES = /* @__PURE__ */ new Set([
2249
2304
  "wait_completed",
2250
2305
  "attr_set"
2251
2306
  ]);
2252
- function EventItem({ event, onLoadEventData, encryptionKey }) {
2307
+ const parseDateValue = (value) => {
2308
+ if (value == null)
2309
+ return null;
2310
+ const date = value instanceof Date ? value : new Date(String(value));
2311
+ return Number.isNaN(date.getTime()) ? null : date;
2312
+ };
2313
+ const getEffectiveEventDate = (event) => parseDateValue(event.occurredAt) ?? new Date(event.createdAt);
2314
+ const formatEventTimestamp = (date) => date.toLocaleString(void 0, {
2315
+ month: "short",
2316
+ day: "numeric",
2317
+ hour: "numeric",
2318
+ minute: "numeric",
2319
+ second: "numeric",
2320
+ fractionalSecondDigits: 3,
2321
+ timeZoneName: "short"
2322
+ });
2323
+ function EventItem({ event, onLoadEventData, encryptionKey, showSeparateEventOccurrenceTimestamps = false }) {
2253
2324
  const [loadedData, setLoadedData] = reactExports.useState(null);
2254
2325
  const [isLoading, setIsLoading] = reactExports.useState(false);
2255
2326
  const [loadError, setLoadError] = reactExports.useState(null);
@@ -2290,16 +2361,18 @@ function EventItem({ event, onLoadEventData, encryptionKey }) {
2290
2361
  void loadEventData({ force: true });
2291
2362
  }, [encryptionKey, loadEventData]);
2292
2363
  const createdAt = new Date(event.createdAt);
2293
- const createdAtTime = createdAt.toLocaleTimeString(void 0, {
2364
+ const occurredAt = parseDateValue(event.occurredAt);
2365
+ const displayedCreatedAt = showSeparateEventOccurrenceTimestamps ? createdAt : getEffectiveEventDate(event);
2366
+ const displayedCreatedAtTime = displayedCreatedAt.toLocaleTimeString(void 0, {
2294
2367
  hour: "numeric",
2295
2368
  minute: "numeric",
2296
2369
  second: "numeric"
2297
2370
  });
2298
2371
  const displayPayload = isLoading ? loadedData : mergedDisplay;
2299
- return jsxRuntimeExports.jsxs(DetailCard, { variant: "card", summaryClassName: "px-3 py-2", summary: jsxRuntimeExports.jsxs("div", { className: "flex w-full items-center justify-between gap-3", children: [jsxRuntimeExports.jsx("span", { className: "text-gray-1000 text-label-12 font-mono", children: event.eventType }), jsxRuntimeExports.jsx("span", { className: "shrink-0 text-label-13 text-gray-900", children: createdAtTime })] }), onToggle: canHaveData ? (open) => {
2372
+ return jsxRuntimeExports.jsxs(DetailCard, { variant: "card", summaryClassName: "px-3 py-2", summary: jsxRuntimeExports.jsxs("div", { className: "flex w-full items-center justify-between gap-3", children: [jsxRuntimeExports.jsx("span", { className: "text-gray-1000 text-label-12 font-mono", children: event.eventType }), jsxRuntimeExports.jsx("span", { className: "shrink-0 text-label-13 text-gray-900", children: displayedCreatedAtTime })] }), onToggle: canHaveData ? (open) => {
2300
2373
  if (open)
2301
2374
  handleExpand();
2302
- } : void 0, children: [jsxRuntimeExports.jsxs("div", { className: "flex flex-col bg-background-200 [&:has(+_*)]:border-b [&:has(+_*)]:border-gray-alpha-400", children: [jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2 py-2 px-3", children: [jsxRuntimeExports.jsx("span", { className: "text-label-12 text-gray-900", children: "Event ID" }), jsxRuntimeExports.jsx("span", { className: "max-w-[70%] truncate text-right text-label-12 font-mono", children: event.eventId })] }), event.correlationId && jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2 py-2 px-3", children: [jsxRuntimeExports.jsx("span", { className: "text-label-12 text-gray-900", children: "Correlation ID" }), jsxRuntimeExports.jsx("span", { className: "max-w-[70%] truncate text-right text-label-12 font-mono", children: event.correlationId })] })] }), isLoading && jsxRuntimeExports.jsxs("div", { className: "p-3", children: [jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-[35%]" }), jsxRuntimeExports.jsx(Skeleton, { className: "mt-2 h-4 w-[90%]" }), jsxRuntimeExports.jsx(Skeleton, { className: "mt-2 h-4 w-[75%]" })] }), loadError && jsxRuntimeExports.jsx(ErrorCard, { title: "Failed to load event data", details: loadError, className: "mt-2" }), displayPayload != null && jsxRuntimeExports.jsx("div", { className: "[&>div]:border-none [&>div]:rounded-none", children: jsxRuntimeExports.jsx(EventDataBlock, { eventType: event.eventType, data: displayPayload }) })] });
2375
+ } : void 0, children: [jsxRuntimeExports.jsxs("div", { className: "flex flex-col bg-background-200 [&:has(+_*)]:border-b [&:has(+_*)]:border-gray-alpha-400", children: [showSeparateEventOccurrenceTimestamps && occurredAt && jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2 py-2 px-3", children: [jsxRuntimeExports.jsx("span", { className: "text-label-12 text-gray-900", children: "Occurred" }), jsxRuntimeExports.jsx(TimestampTooltip, { date: occurredAt, children: jsxRuntimeExports.jsx("span", { className: "max-w-[70%] truncate text-right text-label-12 font-mono", children: formatEventTimestamp(occurredAt) }) })] }), jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2 py-2 px-3", children: [jsxRuntimeExports.jsx("span", { className: "text-label-12 text-gray-900", children: "Event ID" }), jsxRuntimeExports.jsx("span", { className: "max-w-[70%] truncate text-right text-label-12 font-mono", children: event.eventId })] }), event.correlationId && jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2 py-2 px-3", children: [jsxRuntimeExports.jsx("span", { className: "text-label-12 text-gray-900", children: "Correlation ID" }), jsxRuntimeExports.jsx("span", { className: "max-w-[70%] truncate text-right text-label-12 font-mono", children: event.correlationId })] })] }), isLoading && jsxRuntimeExports.jsxs("div", { className: "p-3", children: [jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-[35%]" }), jsxRuntimeExports.jsx(Skeleton, { className: "mt-2 h-4 w-[90%]" }), jsxRuntimeExports.jsx(Skeleton, { className: "mt-2 h-4 w-[75%]" })] }), loadError && jsxRuntimeExports.jsx(ErrorCard, { title: "Failed to load event data", details: loadError, className: "mt-2" }), displayPayload != null && jsxRuntimeExports.jsx("div", { className: "[&>div]:border-none [&>div]:rounded-none", children: jsxRuntimeExports.jsx(EventDataBlock, { eventType: event.eventType, data: displayPayload }) })] });
2303
2376
  }
2304
2377
  function hasOnlyExpiredFields(data, eventType) {
2305
2378
  if (data === null || typeof data !== "object" || Array.isArray(data)) {
@@ -2335,15 +2408,52 @@ function EventDataBlock({ eventType, data }) {
2335
2408
  }
2336
2409
  return jsxRuntimeExports.jsx(CopyableDataBlock, { data });
2337
2410
  }
2338
- function EventsList({ events, isLoading = false, error, onLoadEventData, onStreamClick, onRunClick, encryptionKey }) {
2339
- const sortedEvents = reactExports.useMemo(() => [...events].sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()), [events]);
2411
+ function EventsList({ events, isLoading = false, error, onLoadEventData, onStreamClick, onRunClick, encryptionKey, showSeparateEventOccurrenceTimestamps = false }) {
2412
+ const sortedEvents = reactExports.useMemo(() => [...events].sort((a, b) => getEffectiveEventDate(a).getTime() - getEffectiveEventDate(b).getTime()), [events]);
2340
2413
  const hasEvents = sortedEvents.length > 0 && !error;
2341
2414
  if (!hasEvents && !isLoading) {
2342
2415
  return jsxRuntimeExports.jsx(DetailCard, { summary: "Events", disabled: true });
2343
2416
  }
2344
- return jsxRuntimeExports.jsx(RunClickContext.Provider, { value: onRunClick, children: jsxRuntimeExports.jsx(StreamClickContext.Provider, { value: onStreamClick, children: jsxRuntimeExports.jsx(DetailCard, { summary: "Events", contentClassName: "mb-0", defaultOpen: true, children: isLoading ? jsxRuntimeExports.jsx("div", { className: "flex flex-col -mx-4", children: [0, 1, 2].map((i) => jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-3 bg-background-200 px-4 py-2", children: [jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-32 rounded" }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-16 rounded" })] }, i)) }) : jsxRuntimeExports.jsx("div", { className: "flex flex-col -mx-4", children: sortedEvents.map((event) => jsxRuntimeExports.jsx(EventItem, { event, onLoadEventData, encryptionKey }, event.eventId)) }) }) }) });
2417
+ return jsxRuntimeExports.jsx(RunClickContext.Provider, { value: onRunClick, children: jsxRuntimeExports.jsx(StreamClickContext.Provider, { value: onStreamClick, children: jsxRuntimeExports.jsx(DetailCard, { summary: "Events", contentClassName: "mb-0", defaultOpen: true, children: isLoading ? jsxRuntimeExports.jsx("div", { className: "flex flex-col -mx-4", children: [0, 1, 2].map((i) => jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-3 bg-background-200 px-4 py-2", children: [jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-32 rounded" }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-16 rounded" })] }, i)) }) : jsxRuntimeExports.jsx("div", { className: "flex flex-col -mx-4", children: sortedEvents.map((event) => jsxRuntimeExports.jsx(EventItem, { event, onLoadEventData, encryptionKey, showSeparateEventOccurrenceTimestamps }, event.eventId)) }) }) }) });
2345
2418
  }
2346
2419
  const hasField = (value, key) => key in value;
2420
+ const RESOURCES_WITH_FETCHED_DETAIL = /* @__PURE__ */ new Set(["run", "step", "sleep"]);
2421
+ function resourceNeedsFetchedDetail(resource) {
2422
+ return resource !== void 0 && RESOURCES_WITH_FETCHED_DETAIL.has(resource);
2423
+ }
2424
+ function deriveSpanDetailView(args) {
2425
+ const { resource, resourceId, inlineData, fetchedDetail, fetchedError } = args;
2426
+ const matchedDetail = spanDetailMatchesSelection(fetchedDetail, resource, resourceId) ? fetchedDetail : null;
2427
+ const displayData = mergeSpanDetail(inlineData, matchedDetail);
2428
+ if (!resource || !resourceId) {
2429
+ return { status: "idle", displayData, detail: null, error: void 0 };
2430
+ }
2431
+ if (fetchedError) {
2432
+ return {
2433
+ status: "error",
2434
+ displayData,
2435
+ detail: matchedDetail,
2436
+ error: fetchedError
2437
+ };
2438
+ }
2439
+ if (!resourceNeedsFetchedDetail(resource)) {
2440
+ return {
2441
+ status: "ready",
2442
+ displayData,
2443
+ detail: matchedDetail,
2444
+ error: void 0
2445
+ };
2446
+ }
2447
+ if (matchedDetail !== null) {
2448
+ return {
2449
+ status: "ready",
2450
+ displayData,
2451
+ detail: matchedDetail,
2452
+ error: void 0
2453
+ };
2454
+ }
2455
+ return { status: "loading", displayData, detail: null, error: void 0 };
2456
+ }
2347
2457
  function spanDetailMatchesSelection(detail, resource, resourceId) {
2348
2458
  if (!detail || typeof detail !== "object" || !resource || !resourceId) {
2349
2459
  return false;
@@ -2376,16 +2486,88 @@ function mergeSpanDetail(spanData, detail) {
2376
2486
  }
2377
2487
  return merged;
2378
2488
  }
2379
- function isStep(data) {
2380
- return data !== null && typeof data === "object" && "stepId" in data;
2489
+ function deriveSpanSelection(selectedSpan) {
2490
+ if (!selectedSpan)
2491
+ return null;
2492
+ const { resource, data } = selectedSpan;
2493
+ if (resource === "step" && data && typeof data === "object" && "stepId" in data) {
2494
+ const step = data;
2495
+ return { resource: "step", resourceId: step.stepId, runId: step.runId };
2496
+ }
2497
+ if (resource === "run" && data && typeof data === "object" && "runId" in data) {
2498
+ return { resource: "run", resourceId: data.runId };
2499
+ }
2500
+ if (resource === "hook" && data && typeof data === "object" && "hookId" in data) {
2501
+ return { resource: "hook", resourceId: data.hookId };
2502
+ }
2503
+ if (resource === "sleep") {
2504
+ if (!selectedSpan.spanId)
2505
+ return null;
2506
+ const waitData = data;
2507
+ return {
2508
+ resource: "sleep",
2509
+ resourceId: selectedSpan.spanId,
2510
+ runId: waitData == null ? void 0 : waitData.runId
2511
+ };
2512
+ }
2513
+ return null;
2381
2514
  }
2382
- function isWorkflowRun(data) {
2383
- return data !== null && typeof data === "object" && "runId" in data;
2515
+ function useSelectedSpanDetail(selectedSpan, fetchSpanDetail) {
2516
+ const selection = reactExports.useMemo(() => deriveSpanSelection(selectedSpan), [selectedSpan]);
2517
+ const resource = selection == null ? void 0 : selection.resource;
2518
+ const resourceId = selection == null ? void 0 : selection.resourceId;
2519
+ const runId = selection == null ? void 0 : selection.runId;
2520
+ const selectionKey = resource && resourceId ? `${resource}:${resourceId}` : null;
2521
+ const needsFetch = resourceNeedsFetchedDetail(resource);
2522
+ const [fetched, setFetched] = reactExports.useState({ detail: null, error: null, errorKey: null });
2523
+ const tokenRef = reactExports.useRef(0);
2524
+ const selectionRef = reactExports.useRef(selection);
2525
+ selectionRef.current = selection;
2526
+ reactExports.useEffect(() => {
2527
+ if (!selectionKey || !needsFetch) {
2528
+ return;
2529
+ }
2530
+ const activeSelection = selectionRef.current;
2531
+ if (!activeSelection) {
2532
+ return;
2533
+ }
2534
+ const token = ++tokenRef.current;
2535
+ fetchSpanDetail(activeSelection).then((detail) => {
2536
+ if (tokenRef.current !== token)
2537
+ return;
2538
+ setFetched({ detail, error: null, errorKey: null });
2539
+ }).catch((err) => {
2540
+ if (tokenRef.current !== token)
2541
+ return;
2542
+ setFetched({
2543
+ detail: null,
2544
+ error: err instanceof Error ? err : new Error(String(err)),
2545
+ errorKey: selectionKey
2546
+ });
2547
+ });
2548
+ }, [selectionKey, runId, needsFetch, fetchSpanDetail]);
2549
+ const scopedError = fetched.errorKey === selectionKey ? fetched.error : null;
2550
+ const view = reactExports.useMemo(() => deriveSpanDetailView({
2551
+ resource,
2552
+ resourceId,
2553
+ inlineData: selectedSpan == null ? void 0 : selectedSpan.data,
2554
+ fetchedDetail: fetched.detail,
2555
+ fetchedError: scopedError
2556
+ }), [resource, resourceId, selectedSpan == null ? void 0 : selectedSpan.data, fetched.detail, scopedError]);
2557
+ return {
2558
+ status: view.status,
2559
+ resource,
2560
+ resourceId,
2561
+ runId,
2562
+ displayData: view.displayData,
2563
+ detail: view.detail,
2564
+ error: view.error
2565
+ };
2384
2566
  }
2385
2567
  function isHook(data) {
2386
2568
  return data !== null && typeof data === "object" && "hookId" in data;
2387
2569
  }
2388
- function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spanDetailError, spanDetailLoading, onSpanSelect, onWakeUpSleep, onLoadEventData, onResolveHook, encryptionKey, onDecrypt, isDecrypting = false, selectedSpan }) {
2570
+ function EntityDetailPanel({ run, onStreamClick, onRunClick, fetchSpanDetail, onWakeUpSleep, onLoadEventData, onResolveHook, encryptionKey, onDecrypt, isDecrypting = false, selectedSpan, showSeparateEventOccurrenceTimestamps = false }) {
2389
2571
  const toast2 = useToast();
2390
2572
  const [stoppingSleep, setStoppingSleep] = reactExports.useState(false);
2391
2573
  const [showResolveHookModal, setShowResolveHookModal] = reactExports.useState(false);
@@ -2396,41 +2578,8 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
2396
2578
  const data = selectedSpan == null ? void 0 : selectedSpan.data;
2397
2579
  const rawEvents = selectedSpan == null ? void 0 : selectedSpan.rawEvents;
2398
2580
  const rawEventsLength = (rawEvents == null ? void 0 : rawEvents.length) ?? 0;
2399
- const { resource, resourceId, runId } = reactExports.useMemo(() => {
2400
- if (!selectedSpan) {
2401
- return { resource: void 0, resourceId: void 0, runId: void 0 };
2402
- }
2403
- const res = selectedSpan.resource;
2404
- if (res === "step" && isStep(data)) {
2405
- return { resource: "step", resourceId: data.stepId, runId: data.runId };
2406
- }
2407
- if (res === "run" && isWorkflowRun(data)) {
2408
- return { resource: "run", resourceId: data.runId, runId: void 0 };
2409
- }
2410
- if (res === "hook" && isHook(data)) {
2411
- return { resource: "hook", resourceId: data.hookId, runId: void 0 };
2412
- }
2413
- if (res === "sleep") {
2414
- const waitData = data;
2415
- return {
2416
- resource: "sleep",
2417
- resourceId: selectedSpan.spanId,
2418
- runId: waitData == null ? void 0 : waitData.runId
2419
- };
2420
- }
2421
- return { resource: void 0, resourceId: void 0, runId: void 0 };
2422
- }, [selectedSpan, data]);
2423
- const onSpanSelectRef = reactExports.useRef(onSpanSelect);
2424
- onSpanSelectRef.current = onSpanSelect;
2425
- reactExports.useEffect(() => {
2426
- if (resource && resourceId && ["run", "step", "hook", "sleep"].includes(resource)) {
2427
- onSpanSelectRef.current({
2428
- resource,
2429
- resourceId,
2430
- runId
2431
- });
2432
- }
2433
- }, [resource, resourceId, runId]);
2581
+ const { status, resource, resourceId, displayData, detail: matchedSpanDetailData, error } = useSelectedSpanDetail(selectedSpan, fetchSpanDetail);
2582
+ const loading = status === "loading";
2434
2583
  const canWakeUp = reactExports.useMemo(() => {
2435
2584
  if (resource !== "sleep" || !rawEvents)
2436
2585
  return false;
@@ -2463,9 +2612,6 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
2463
2612
  run.status,
2464
2613
  resolvedHookIds
2465
2614
  ]);
2466
- const error = spanDetailError ?? void 0;
2467
- const loading = spanDetailLoading ?? false;
2468
- const matchedSpanDetailData = reactExports.useMemo(() => spanDetailMatchesSelection(spanDetailData, resource, resourceId) ? spanDetailData : null, [spanDetailData, resource, resourceId]);
2469
2615
  const hookToken = reactExports.useMemo(() => {
2470
2616
  if (resource !== "hook" || !resourceId)
2471
2617
  return void 0;
@@ -2550,7 +2696,6 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
2550
2696
  setResolvingHook(false);
2551
2697
  }
2552
2698
  }, [onResolveHook, hookToken, resolvingHook, matchedSpanDetailData, data]);
2553
- const displayData = reactExports.useMemo(() => mergeSpanDetail(data, matchedSpanDetailData), [data, matchedSpanDetailData]);
2554
2699
  const moduleSpecifier = reactExports.useMemo(() => {
2555
2700
  const displayRecord = displayData;
2556
2701
  const displayStepName = displayRecord.stepName;
@@ -2579,43 +2724,7 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
2579
2724
  }, children: [jsxRuntimeExports.jsx(Zap, { className: "h-4 w-4" }), stoppingSleep ? "Waking up..." : "Wake Up Sleep"] }), resource === "hook" && canResolveHook && jsxRuntimeExports.jsxs("button", { type: "button", onClick: () => setShowResolveHookModal(true), disabled: resolvingHook, className: clsx("flex items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium", "disabled:opacity-50 disabled:cursor-not-allowed transition-colors", resolvingHook ? "opacity-50 cursor-not-allowed" : "cursor-pointer"), style: {
2580
2725
  background: "var(--ds-gray-1000)",
2581
2726
  color: "var(--ds-background-100)"
2582
- }, children: [jsxRuntimeExports.jsx(Send, { className: "h-4 w-4" }), "Resolve Hook"] })] })] }), jsxRuntimeExports.jsx(AttributePanel, { data: displayData, moduleSpecifier, expiredAt: run.expiredAt, isLoading: loading, error: error ?? void 0, onStreamClick, onRunClick, onDecrypt, isDecrypting, resource }), rawEvents && jsxRuntimeExports.jsx(EventsList, { events: rawEvents, onLoadEventData, onStreamClick, onRunClick, encryptionKey })] }) }), jsxRuntimeExports.jsx(ResolveHookModal, { isOpen: showResolveHookModal, onClose: () => setShowResolveHookModal(false), onSubmit: handleResolveHook, isSubmitting: resolvingHook })] });
2583
- }
2584
- const kbdVariants = cva("inline-flex items-center justify-center rounded px-1 text-center font-sans", {
2585
- variants: {
2586
- variant: {
2587
- subtle: "bg-background-100/20",
2588
- outline: "border border-gray-alpha-400 bg-background-100 font-medium text-gray-900"
2589
- },
2590
- size: {
2591
- default: "h-5 min-w-5 text-xs leading-none",
2592
- compact: "h-4 min-h-4 min-w-4 text-[11px] leading-none",
2593
- search: "h-5 min-h-5 min-w-5 text-[13px] leading-[1.7em]"
2594
- }
2595
- },
2596
- defaultVariants: {
2597
- variant: "subtle",
2598
- size: "default"
2599
- }
2600
- });
2601
- function Kbd({ children, className, variant, size, ...props }) {
2602
- return jsxRuntimeExports.jsx("kbd", { className: cn(kbdVariants({ variant, size, className })), ...props, children });
2603
- }
2604
- const COL_TEMPLATE = "340px 1px minmax(50px, 1fr)";
2605
- const ROWS = [
2606
- { id: "r0", name: 62, off: 0, bar: 72 },
2607
- { id: "r1", name: 78, off: 6, bar: 48 },
2608
- { id: "r2", name: 50, off: 10, bar: 55 },
2609
- { id: "r3", name: 84, off: 18, bar: 30 },
2610
- { id: "r4", name: 45, off: 18, bar: 42 },
2611
- { id: "r5", name: 66, off: 34, bar: 38 },
2612
- { id: "r6", name: 55, off: 41, bar: 25 },
2613
- { id: "r7", name: 40, off: 50, bar: 30 }
2614
- ];
2615
- const HEADER_MARKERS = ["m0", "m1", "m2", "m3"];
2616
- const HeaderDivider = () => jsxRuntimeExports.jsx("div", { className: "flex justify-center", children: jsxRuntimeExports.jsx("span", { "aria-hidden": true, className: "h-full w-px bg-gray-alpha-400" }) });
2617
- function TraceViewerSkeleton() {
2618
- return jsxRuntimeExports.jsxs("output", { "aria-busy": "true", "aria-label": "Loading trace", className: "flex flex-col w-full h-full min-h-0 bg-background-100", children: [jsxRuntimeExports.jsx("span", { className: "sr-only", children: "Loading trace…" }), jsxRuntimeExports.jsxs("div", { className: "shrink-0 grid", style: { gridTemplateColumns: COL_TEMPLATE }, children: [jsxRuntimeExports.jsxs("div", { className: "h-10 min-h-10 flex items-center border-b border-gray-alpha-400 pl-4 pr-2 gap-1.5", children: [jsxRuntimeExports.jsx(Skeleton, { className: "w-3.5 h-3.5 shrink-0 rounded-sm" }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3.5 w-40" })] }), jsxRuntimeExports.jsx(HeaderDivider, {}), jsxRuntimeExports.jsx("div", { className: "h-10 min-h-10 flex items-end border-b border-gray-alpha-400 px-4 pb-1 gap-2", children: jsxRuntimeExports.jsx("div", { className: "relative flex-1 flex items-end justify-between", children: HEADER_MARKERS.map((id) => jsxRuntimeExports.jsx(Skeleton, { className: "h-3.5 w-9" }, id)) }) })] }), jsxRuntimeExports.jsxs("div", { className: "grid flex-1 min-h-0 overflow-hidden", style: { gridTemplateColumns: COL_TEMPLATE }, children: [jsxRuntimeExports.jsx("div", { className: "block overflow-visible", children: jsxRuntimeExports.jsx("ul", { className: "block divide-y divide-gray-alpha-400 border-b border-gray-alpha-400", children: ROWS.map((row) => jsxRuntimeExports.jsxs("li", { className: "h-10 flex items-center pl-4 pr-2", children: [jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [jsxRuntimeExports.jsx(Skeleton, { className: "w-4 h-4 shrink-0 rounded-sm" }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3.5", style: { width: `${row.name}%` } })] }), jsxRuntimeExports.jsx(Skeleton, { className: "ml-2 h-3.5 w-10 shrink-0" })] }, row.id)) }) }), jsxRuntimeExports.jsx("span", { "aria-hidden": true, className: "h-full w-px bg-gray-alpha-400" }), jsxRuntimeExports.jsx("div", { className: "relative min-h-0", children: ROWS.map((row) => jsxRuntimeExports.jsx("div", { className: "relative h-10", children: jsxRuntimeExports.jsx("div", { className: "absolute inset-x-4 inset-y-0", children: jsxRuntimeExports.jsx(Skeleton, { className: "absolute top-1/2 -translate-y-1/2 h-6 rounded-[0.25rem]", style: { left: `${row.off}%`, width: `${row.bar}%` } }) }) }, row.id)) })] })] });
2727
+ }, children: [jsxRuntimeExports.jsx(Send, { className: "h-4 w-4" }), "Resolve Hook"] })] })] }), jsxRuntimeExports.jsx(AttributePanel, { data: displayData, moduleSpecifier, expiredAt: run.expiredAt, isLoading: loading, error: error ?? void 0, onStreamClick, onRunClick, onDecrypt, isDecrypting, resource }), rawEvents && jsxRuntimeExports.jsx(EventsList, { events: rawEvents, onLoadEventData, onStreamClick, onRunClick, encryptionKey, showSeparateEventOccurrenceTimestamps })] }) }), jsxRuntimeExports.jsx(ResolveHookModal, { isOpen: showResolveHookModal, onClose: () => setShowResolveHookModal(false), onSubmit: handleResolveHook, isSubmitting: resolvingHook })] });
2619
2728
  }
2620
2729
  function useIntersectionObserver(elementRef, { threshold = 0, rootRef, rootMargin = "0%", freezeOnceVisible = false } = {}) {
2621
2730
  const [entry, setEntry] = reactExports.useState();
@@ -2652,6 +2761,26 @@ function useLoadMoreOnScroll(loadMore, { hasMore, isLoadingMore, rootRef, rootMa
2652
2761
  }, [entry == null ? void 0 : entry.isIntersecting, hasMore, isLoadingMore]);
2653
2762
  return sentinelRef;
2654
2763
  }
2764
+ const kbdVariants = cva("inline-flex items-center justify-center rounded px-1 text-center font-sans", {
2765
+ variants: {
2766
+ variant: {
2767
+ subtle: "bg-background-100/20",
2768
+ outline: "border border-gray-alpha-400 bg-background-100 font-medium text-gray-900"
2769
+ },
2770
+ size: {
2771
+ default: "h-5 min-w-5 text-xs leading-none",
2772
+ compact: "h-4 min-h-4 min-w-4 text-[11px] leading-none",
2773
+ search: "h-5 min-h-5 min-w-5 text-[13px] leading-[1.7em]"
2774
+ }
2775
+ },
2776
+ defaultVariants: {
2777
+ variant: "subtle",
2778
+ size: "default"
2779
+ }
2780
+ });
2781
+ function Kbd({ children, className, variant, size, ...props }) {
2782
+ return jsxRuntimeExports.jsx("kbd", { className: cn(kbdVariants({ variant, size, className })), ...props, children });
2783
+ }
2655
2784
  const WorkflowIcon = () => {
2656
2785
  return jsxRuntimeExports.jsx("svg", { "data-testid": "geist-icon", height: "16", strokeLinejoin: "round", style: { color: "currentColor" }, viewBox: "0 0 16 16", width: "16", children: jsxRuntimeExports.jsx("path", { d: "M5.75 7L6.4209 7.33594L4.85254 10.4717C5.38789 10.771 5.75 11.3431 5.75 12V14C5.75 14.9665 4.96648 15.75 4 15.75H2C1.03352 15.75 0.25 14.9665 0.25 14V12C0.25 11.0335 1.03352 10.25 2 10.25H3.28711L5.0791 6.66504L5.75 7ZM14 10.25C14.9665 10.25 15.75 11.0335 15.75 12V14C15.75 14.9665 14.9665 15.75 14 15.75H12C11.1185 15.75 10.3909 15.098 10.2695 14.25H7V12.75H10.25V12C10.25 11.0335 11.0335 10.25 12 10.25H14ZM2 11.75C1.86192 11.75 1.75 11.8619 1.75 12V14C1.75 14.1381 1.86192 14.25 2 14.25H4C4.13808 14.25 4.25 14.1381 4.25 14V12C4.25 11.8619 4.13808 11.75 4 11.75H2ZM12 11.75C11.8619 11.75 11.75 11.8619 11.75 12V14C11.75 14.1381 11.8619 14.25 12 14.25H14C14.1381 14.25 14.25 14.1381 14.25 14V12C14.25 11.8619 14.1381 11.75 14 11.75H12ZM9 0.25C9.96649 0.25 10.75 1.03351 10.75 2V4C10.75 4.44642 10.5808 4.85197 10.3057 5.16113L12.2041 8.6416L10.8877 9.36035L8.91895 5.75H7C6.03351 5.75 5.25 4.96649 5.25 4V2C5.25 1.03351 6.03351 0.25 7 0.25H9ZM7 1.75C6.86193 1.75 6.75 1.86193 6.75 2V4C6.75 4.13807 6.86193 4.25 7 4.25H9C9.13807 4.25 9.25 4.13807 9.25 4V2C9.25 1.86193 9.13807 1.75 9 1.75H7Z", fill: "currentColor" }) });
2657
2786
  };
@@ -2698,57 +2827,6 @@ const EventList = ({ spans, activeSpanId, searchResult, onSelectSpan }) => {
2698
2827
  paddingBottom: (spans.length - end) * ROW_HEIGHT_PX
2699
2828
  }, children: spans.slice(start, end).map((span) => jsxRuntimeExports.jsx(EventRow, { span, isSelected: span.spanId === activeSpanId, isDimmed: isSpanDimmedBySearch(span.spanId, searchResult), onSelectSpan }, span.spanId)) });
2700
2829
  };
2701
- const hint = "_hint_1dmsq_3";
2702
- const styles = {
2703
- hint
2704
- };
2705
- const DISMISSALS_KEY = "workflow-step-shortcut-helper-dismissals";
2706
- const DISMISSAL_LIMIT = 3;
2707
- const HINT_ROTATION_MS = 8e3;
2708
- function getAltKeyLabel() {
2709
- if (typeof navigator === "undefined")
2710
- return "Alt";
2711
- return navigator.platform.toLowerCase().includes("mac") ? "Option" : "Alt";
2712
- }
2713
- function readDismissals() {
2714
- try {
2715
- const dismissals = Number.parseInt(window.localStorage.getItem(DISMISSALS_KEY) ?? "0", 10);
2716
- return Number.isNaN(dismissals) ? 0 : dismissals;
2717
- } catch {
2718
- return 0;
2719
- }
2720
- }
2721
- function AltHint() {
2722
- return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: ["Hold", jsxRuntimeExports.jsx(Kbd, { variant: "outline", size: "compact", className: "mx-1", children: getAltKeyLabel() }), "to see delta between spans"] });
2723
- }
2724
- function NavHint() {
2725
- return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: ["Use", jsxRuntimeExports.jsx(Kbd, { variant: "outline", size: "compact", className: "ml-1", children: "J" }), jsxRuntimeExports.jsx("span", { className: "mx-1", children: "/" }), jsxRuntimeExports.jsx(Kbd, { variant: "outline", size: "compact", className: "mr-1", children: "K" }), "to move between spans"] });
2726
- }
2727
- function TraceShortcutHelper({ hasMultipleSpans, reducedMotion }) {
2728
- const [visible, setVisible] = reactExports.useState(false);
2729
- const [index, setIndex] = reactExports.useState(0);
2730
- reactExports.useEffect(() => {
2731
- setVisible(readDismissals() < DISMISSAL_LIMIT);
2732
- }, []);
2733
- reactExports.useEffect(() => {
2734
- if (reducedMotion)
2735
- return;
2736
- const id = setInterval(() => {
2737
- setIndex((i) => i === 0 ? 1 : 0);
2738
- }, HINT_ROTATION_MS);
2739
- return () => clearInterval(id);
2740
- }, [reducedMotion]);
2741
- if (!visible || !hasMultipleSpans)
2742
- return null;
2743
- const dismiss = () => {
2744
- try {
2745
- window.localStorage.setItem(DISMISSALS_KEY, String(readDismissals() + 1));
2746
- } catch {
2747
- }
2748
- setVisible(false);
2749
- };
2750
- return jsxRuntimeExports.jsxs("div", { className: "group absolute bottom-3 left-1/2 z-10 hidden h-8 max-w-[calc(100%-2rem)] -translate-x-1/2 items-center gap-1 text-xs leading-none text-gray-900 md:inline-flex", children: [jsxRuntimeExports.jsx("span", { "aria-live": "polite", "aria-atomic": "true", className: "inline-flex items-center whitespace-nowrap", children: reducedMotion ? jsxRuntimeExports.jsx(AltHint, {}) : jsxRuntimeExports.jsx("span", { className: `inline-flex items-center ${styles.hint}`, children: index === 0 ? jsxRuntimeExports.jsx(AltHint, {}) : jsxRuntimeExports.jsx(NavHint, {}) }, index) }), jsxRuntimeExports.jsx("button", { type: "button", className: "inline-flex h-5 w-5 items-center justify-center rounded text-muted-foreground opacity-0 transition-opacity hover:bg-accent hover:text-foreground group-hover:opacity-100 focus-visible:opacity-100 motion-reduce:transition-none", onClick: dismiss, "aria-label": "Dismiss trace shortcuts helper", children: jsxRuntimeExports.jsx(X, { className: "h-3 w-3" }) })] });
2751
- }
2752
2830
  const GUTTER_PX = 1;
2753
2831
  const MIN_PX = 50;
2754
2832
  const DEFAULT_START_PX = 340;
@@ -2846,6 +2924,57 @@ function SplitPane({ children, className, defaultStartWidth = DEFAULT_START_PX,
2846
2924
  }
2847
2925
  return jsxRuntimeExports.jsxs("div", { ref: setContainerRef, className: cn("grid h-full min-h-0 content-start overflow-x-hidden overflow-y-auto", isDragging && "select-none", className), style: { gridTemplateColumns: colTemplate, height: "100%" }, children: [start, gutter, end] });
2848
2926
  }
2927
+ const hint = "_hint_1dmsq_3";
2928
+ const styles = {
2929
+ hint
2930
+ };
2931
+ const DISMISSALS_KEY = "workflow-step-shortcut-helper-dismissals";
2932
+ const DISMISSAL_LIMIT = 3;
2933
+ const HINT_ROTATION_MS = 8e3;
2934
+ function getAltKeyLabel() {
2935
+ if (typeof navigator === "undefined")
2936
+ return "Alt";
2937
+ return navigator.platform.toLowerCase().includes("mac") ? "Option" : "Alt";
2938
+ }
2939
+ function readDismissals() {
2940
+ try {
2941
+ const dismissals = Number.parseInt(window.localStorage.getItem(DISMISSALS_KEY) ?? "0", 10);
2942
+ return Number.isNaN(dismissals) ? 0 : dismissals;
2943
+ } catch {
2944
+ return 0;
2945
+ }
2946
+ }
2947
+ function AltHint() {
2948
+ return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: ["Hold", jsxRuntimeExports.jsx(Kbd, { variant: "outline", size: "compact", className: "mx-1", children: getAltKeyLabel() }), "to see delta between spans"] });
2949
+ }
2950
+ function NavHint() {
2951
+ return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: ["Use", jsxRuntimeExports.jsx(Kbd, { variant: "outline", size: "compact", className: "ml-1", children: "J" }), jsxRuntimeExports.jsx("span", { className: "mx-1", children: "/" }), jsxRuntimeExports.jsx(Kbd, { variant: "outline", size: "compact", className: "mr-1", children: "K" }), "to move between spans"] });
2952
+ }
2953
+ function TraceShortcutHelper({ hasMultipleSpans, reducedMotion }) {
2954
+ const [visible, setVisible] = reactExports.useState(false);
2955
+ const [index, setIndex] = reactExports.useState(0);
2956
+ reactExports.useEffect(() => {
2957
+ setVisible(readDismissals() < DISMISSAL_LIMIT);
2958
+ }, []);
2959
+ reactExports.useEffect(() => {
2960
+ if (reducedMotion)
2961
+ return;
2962
+ const id = setInterval(() => {
2963
+ setIndex((i) => i === 0 ? 1 : 0);
2964
+ }, HINT_ROTATION_MS);
2965
+ return () => clearInterval(id);
2966
+ }, [reducedMotion]);
2967
+ if (!visible || !hasMultipleSpans)
2968
+ return null;
2969
+ const dismiss = () => {
2970
+ try {
2971
+ window.localStorage.setItem(DISMISSALS_KEY, String(readDismissals() + 1));
2972
+ } catch {
2973
+ }
2974
+ setVisible(false);
2975
+ };
2976
+ return jsxRuntimeExports.jsxs("div", { className: "group absolute bottom-3 left-1/2 z-10 hidden h-8 max-w-[calc(100%-2rem)] -translate-x-1/2 items-center gap-1 text-xs leading-none text-gray-900 md:inline-flex", children: [jsxRuntimeExports.jsx("span", { "aria-live": "polite", "aria-atomic": "true", className: "inline-flex items-center whitespace-nowrap", children: reducedMotion ? jsxRuntimeExports.jsx(AltHint, {}) : jsxRuntimeExports.jsx("span", { className: `inline-flex items-center ${styles.hint}`, children: index === 0 ? jsxRuntimeExports.jsx(AltHint, {}) : jsxRuntimeExports.jsx(NavHint, {}) }, index) }), jsxRuntimeExports.jsx("button", { type: "button", className: "inline-flex h-5 w-5 items-center justify-center rounded text-muted-foreground opacity-0 transition-opacity hover:bg-accent hover:text-foreground group-hover:opacity-100 focus-visible:opacity-100 motion-reduce:transition-none", onClick: dismiss, "aria-label": "Dismiss trace shortcuts helper", children: jsxRuntimeExports.jsx(X, { className: "h-3 w-3" }) })] });
2977
+ }
2849
2978
  const MIN_VIEWPORT_MS = 1e-3;
2850
2979
  const ZOOM_DEBOUNCE_MS = 150;
2851
2980
  function useAnimatedViewport(initial) {
@@ -3256,7 +3385,7 @@ function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
3256
3385
  e.stopPropagation();
3257
3386
  setSearchQuery("");
3258
3387
  }
3259
- }, placeholder: "Search spans...", "aria-label": "Search spans", className: "flex-1 min-w-0 bg-transparent text-sm text-gray-1000 placeholder:text-gray-800 outline-none" }), searchQuery && jsxRuntimeExports.jsx("button", { type: "button", "aria-label": "Clear search", onClick: () => setSearchQuery(""), className: "-mr-2 hidden h-full max-w-full shrink-0 cursor-pointer items-center rounded-r-md border-0 bg-transparent px-2.5 font-inherit text-base text-gray-900 no-underline transition-colors duration-150 ease-in hover:text-gray-1000 focus-visible:-outline-offset-1 focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--ds-focus-color)] min-[961px]:flex", children: jsxRuntimeExports.jsx(Kbd, { variant: "outline", size: "search", children: "Esc" }) })] }), endHeader: jsxRuntimeExports.jsx(TimelineHeader, { markers: timeMarkers, hoverInfo }), children: [jsxRuntimeExports.jsxs("div", { className: "block overflow-visible", children: [jsxRuntimeExports.jsx(EventList, { spans: trace.spans, activeSpanId, searchResult, onSelectSpan: handleSelectSpan }), jsxRuntimeExports.jsx("div", { ref: loadMoreSentinelRef, className: "flex justify-center", children: isLoadingMore ? jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center gap-2 py-3 text-sm text-gray-800", children: [jsxRuntimeExports.jsx(Spinner, { size: 14 }), jsxRuntimeExports.jsx("span", { children: "Loading spans…" })] }) : null })] }), jsxRuntimeExports.jsx("div", { ref: timelineRef, className: "block min-h-0 overflow-visible relative", onDoubleClick: resetZoom, onMouseMove: handleTimelineMouseMove, onMouseLeave: handleTimelineMouseLeave, children: jsxRuntimeExports.jsx(Timeline, { spans: trace.spans, viewStart: viewport.start, viewEnd: viewport.end, markers: timeMarkers, selectedId: activeSpanId, searchResult, onSelect: handleSelectSpan, onRevealTime: handleRevealTime, hoverFraction, altHeld }) })] }), jsxRuntimeExports.jsxs("div", { className: "absolute right-3 bottom-3 z-[5] flex items-center border border-gray-alpha-400 rounded-md bg-background-100 shadow-sm overflow-hidden divide-x divide-gray-alpha-400", children: [jsxRuntimeExports.jsx(IconButton, { variant: "muted", size: "small", onClick: zoomOut, "aria-label": "Zoom out", children: jsxRuntimeExports.jsx(ZoomOut, { className: "w-4 h-4" }) }), jsxRuntimeExports.jsx(IconButton, { variant: "muted", size: "small", onClick: resetZoom, "aria-label": "Reset zoom", children: jsxRuntimeExports.jsx(RotateCcw, { className: "w-3.5 h-3.5" }) }), jsxRuntimeExports.jsx(IconButton, { variant: "muted", size: "small", onClick: zoomIn, "aria-label": "Zoom in", children: jsxRuntimeExports.jsx(ZoomIn, { className: "w-4 h-4" }) })] })] }), activeSpan ? jsxRuntimeExports.jsxs("aside", { className: "flex flex-col h-full max-h-full bg-background-100 border-l border-gray-alpha-400 overflow-auto", children: [jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2 shrink-0 px-4 pt-3 pb-3", children: [jsxRuntimeExports.jsx("span", { className: "text-label-14 font-medium text-gray-1000 truncate block", children: selectedSpanName }), jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-0.5 shrink-0", children: [jsxRuntimeExports.jsxs(Tooltip, { children: [jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: jsxRuntimeExports.jsx(IconButton, { "aria-label": "Navigate up", "aria-keyshortcuts": "K", onClick: handleSelectPrevSpan, disabled: !prevSpanId, children: jsxRuntimeExports.jsx(ChevronUp, { className: "w-4 h-4" }) }) }), prevSpanId ? jsxRuntimeExports.jsxs(TooltipContent, { children: ["Navigate up", jsxRuntimeExports.jsx(Kbd, { children: "K" })] }) : null] }), jsxRuntimeExports.jsxs(Tooltip, { children: [jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: jsxRuntimeExports.jsx(IconButton, { "aria-label": "Navigate down", "aria-keyshortcuts": "J", onClick: handleSelectNextSpan, disabled: !nextSpanId, children: jsxRuntimeExports.jsx(ChevronDown, { className: "w-4 h-4" }) }) }), nextSpanId ? jsxRuntimeExports.jsxs(TooltipContent, { children: ["Navigate down", jsxRuntimeExports.jsx(Kbd, { children: "J" })] }) : null] }), jsxRuntimeExports.jsx("div", { "aria-hidden": true, className: "w-px h-4 bg-gray-alpha-400 mx-1" }), jsxRuntimeExports.jsx(IconButton, { "aria-label": "Close span details", "aria-keyshortcuts": "Escape", onClick: handleClearActiveSpan, children: jsxRuntimeExports.jsx(X, { className: "w-4 h-4" }) })] })] }), jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto", children: jsxRuntimeExports.jsx(ErrorBoundary, { children: jsxRuntimeExports.jsx(EntityDetailPanel, { run: sidebar.run, onStreamClick: sidebar.onStreamClick, onRunClick: sidebar.onRunClick, spanDetailData: sidebar.spanDetailData, spanDetailError: sidebar.spanDetailError, spanDetailLoading: sidebar.spanDetailLoading, onSpanSelect: sidebar.onSpanSelect, onWakeUpSleep: sidebar.onWakeUpSleep, onLoadEventData: sidebar.onLoadEventData, onResolveHook: sidebar.onResolveHook, encryptionKey: sidebar.encryptionKey, onDecrypt: sidebar.onDecrypt, isDecrypting: sidebar.isDecrypting, selectedSpan }) }) })] }) : null, jsxRuntimeExports.jsx(TraceShortcutHelper, { hasMultipleSpans: trace.spans.length > 1, reducedMotion })] });
3388
+ }, placeholder: "Search spans...", "aria-label": "Search spans", className: "flex-1 min-w-0 bg-transparent text-sm text-gray-1000 placeholder:text-gray-800 outline-none" }), searchQuery && jsxRuntimeExports.jsx("button", { type: "button", "aria-label": "Clear search", onClick: () => setSearchQuery(""), className: "-mr-2 hidden h-full max-w-full shrink-0 cursor-pointer items-center rounded-r-md border-0 bg-transparent px-2.5 font-inherit text-base text-gray-900 no-underline transition-colors duration-150 ease-in hover:text-gray-1000 focus-visible:-outline-offset-1 focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--ds-focus-color)] min-[961px]:flex", children: jsxRuntimeExports.jsx(Kbd, { variant: "outline", size: "search", children: "Esc" }) })] }), endHeader: jsxRuntimeExports.jsx(TimelineHeader, { markers: timeMarkers, hoverInfo }), children: [jsxRuntimeExports.jsxs("div", { className: "block overflow-visible", children: [jsxRuntimeExports.jsx(EventList, { spans: trace.spans, activeSpanId, searchResult, onSelectSpan: handleSelectSpan }), jsxRuntimeExports.jsx("div", { ref: loadMoreSentinelRef, className: "flex justify-center", children: isLoadingMore ? jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center gap-2 py-3 text-sm text-gray-800", children: [jsxRuntimeExports.jsx(Spinner, { size: 14 }), jsxRuntimeExports.jsx("span", { children: "Loading spans…" })] }) : null })] }), jsxRuntimeExports.jsx("div", { ref: timelineRef, className: "block min-h-0 overflow-visible relative", onDoubleClick: resetZoom, onMouseMove: handleTimelineMouseMove, onMouseLeave: handleTimelineMouseLeave, children: jsxRuntimeExports.jsx(Timeline, { spans: trace.spans, viewStart: viewport.start, viewEnd: viewport.end, markers: timeMarkers, selectedId: activeSpanId, searchResult, onSelect: handleSelectSpan, onRevealTime: handleRevealTime, hoverFraction, altHeld }) })] }), jsxRuntimeExports.jsxs("div", { className: "absolute right-3 bottom-3 z-[5] flex items-center border border-gray-alpha-400 rounded-md bg-background-100 shadow-sm overflow-hidden divide-x divide-gray-alpha-400", children: [jsxRuntimeExports.jsx(IconButton, { variant: "muted", size: "small", onClick: zoomOut, "aria-label": "Zoom out", children: jsxRuntimeExports.jsx(ZoomOut, { className: "w-4 h-4" }) }), jsxRuntimeExports.jsx(IconButton, { variant: "muted", size: "small", onClick: resetZoom, "aria-label": "Reset zoom", children: jsxRuntimeExports.jsx(RotateCcw, { className: "w-3.5 h-3.5" }) }), jsxRuntimeExports.jsx(IconButton, { variant: "muted", size: "small", onClick: zoomIn, "aria-label": "Zoom in", children: jsxRuntimeExports.jsx(ZoomIn, { className: "w-4 h-4" }) })] })] }), activeSpan ? jsxRuntimeExports.jsxs("aside", { className: "flex flex-col h-full max-h-full bg-background-100 border-l border-gray-alpha-400 overflow-auto", children: [jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2 shrink-0 px-4 pt-3 pb-3", children: [jsxRuntimeExports.jsx("span", { className: "text-label-14 font-medium text-gray-1000 truncate block", children: selectedSpanName }), jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-0.5 shrink-0", children: [jsxRuntimeExports.jsxs(Tooltip, { children: [jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: jsxRuntimeExports.jsx(IconButton, { "aria-label": "Navigate up", "aria-keyshortcuts": "K", onClick: handleSelectPrevSpan, disabled: !prevSpanId, children: jsxRuntimeExports.jsx(ChevronUp, { className: "w-4 h-4" }) }) }), prevSpanId ? jsxRuntimeExports.jsxs(TooltipContent, { children: ["Navigate up", jsxRuntimeExports.jsx(Kbd, { children: "K" })] }) : null] }), jsxRuntimeExports.jsxs(Tooltip, { children: [jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: jsxRuntimeExports.jsx(IconButton, { "aria-label": "Navigate down", "aria-keyshortcuts": "J", onClick: handleSelectNextSpan, disabled: !nextSpanId, children: jsxRuntimeExports.jsx(ChevronDown, { className: "w-4 h-4" }) }) }), nextSpanId ? jsxRuntimeExports.jsxs(TooltipContent, { children: ["Navigate down", jsxRuntimeExports.jsx(Kbd, { children: "J" })] }) : null] }), jsxRuntimeExports.jsx("div", { "aria-hidden": true, className: "w-px h-4 bg-gray-alpha-400 mx-1" }), jsxRuntimeExports.jsx(IconButton, { "aria-label": "Close span details", "aria-keyshortcuts": "Escape", onClick: handleClearActiveSpan, children: jsxRuntimeExports.jsx(X, { className: "w-4 h-4" }) })] })] }), jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto", children: jsxRuntimeExports.jsx(ErrorBoundary, { children: jsxRuntimeExports.jsx(EntityDetailPanel, { run: sidebar.run, onStreamClick: sidebar.onStreamClick, onRunClick: sidebar.onRunClick, fetchSpanDetail: sidebar.fetchSpanDetail, onWakeUpSleep: sidebar.onWakeUpSleep, onLoadEventData: sidebar.onLoadEventData, onResolveHook: sidebar.onResolveHook, encryptionKey: sidebar.encryptionKey, onDecrypt: sidebar.onDecrypt, isDecrypting: sidebar.isDecrypting, selectedSpan, showSeparateEventOccurrenceTimestamps: sidebar.showSeparateEventOccurrenceTimestamps }) }) })] }) : null, jsxRuntimeExports.jsx(TraceShortcutHelper, { hasMultipleSpans: trace.spans.length > 1, reducedMotion })] });
3260
3389
  }
3261
3390
  const NewTraceViewer = ({ run, events, sidebarData, onLoadMore, hasMore, isLoadingMore, loading = false }) => {
3262
3391
  const trace = reactExports.useMemo(() => {
@@ -3298,130 +3427,48 @@ async function fetchResourceWithCorrelationId(env, resource, resourceId, options
3298
3427
  }
3299
3428
  return { data: resourceData, correlationId };
3300
3429
  }
3301
- function useWorkflowResourceData(env, resource, resourceId, options = {}) {
3302
- const { refreshInterval = 0, runId, enabled = true, encryptionKey } = options;
3303
- const [data, setData] = reactExports.useState(
3304
- null
3305
- );
3306
- const [loading, setLoading] = reactExports.useState(enabled);
3307
- const [error, setError] = reactExports.useState(null);
3308
- const hydrate = reactExports.useCallback(
3309
- async (resource2) => encryptionKey ? hydrateResourceIOWithKey(resource2, encryptionKey) : hydrateResourceIO(resource2),
3310
- [encryptionKey]
3311
- );
3312
- const prevSelectionRef = reactExports.useRef("");
3313
- const fetchData = reactExports.useCallback(async () => {
3314
- if (!enabled) {
3315
- setLoading(false);
3316
- return;
3317
- }
3318
- const selectionKey = `${resource}:${resourceId}`;
3319
- if (selectionKey !== prevSelectionRef.current) {
3320
- setData(null);
3321
- prevSelectionRef.current = selectionKey;
3322
- }
3323
- setError(null);
3324
- setLoading(true);
3325
- if (resource === "hook") {
3326
- try {
3327
- const { error: error2, result } = await unwrapServerActionResult(
3328
- fetchHook(env, resourceId, "all")
3329
- );
3330
- if (error2) {
3331
- setError(error2);
3332
- return;
3333
- }
3334
- try {
3335
- setData(await hydrate(result));
3336
- } catch (hydrateError) {
3337
- setError(
3338
- hydrateError instanceof Error ? hydrateError : new Error(String(hydrateError))
3339
- );
3340
- }
3341
- } finally {
3342
- setLoading(false);
3343
- }
3344
- return;
3345
- }
3346
- if (resource === "sleep") {
3347
- try {
3348
- if (!runId) {
3349
- setError(new Error("runId is required for loading sleep details"));
3350
- return;
3351
- }
3352
- const { error: error2, result } = await unwrapServerActionResult(
3353
- fetchEvents(env, runId, {
3354
- sortOrder: "asc",
3355
- limit: 1e3,
3356
- withData: true
3357
- })
3358
- );
3359
- if (error2) {
3360
- setError(error2);
3361
- return;
3362
- }
3363
- try {
3364
- const allEvents = result.data.map(
3365
- hydrateResourceIO
3366
- );
3367
- const waitEvents = await Promise.all(
3368
- allEvents.filter((e) => e.correlationId === resourceId).map(hydrate)
3369
- );
3370
- const data2 = waitEventsToWaitEntity(waitEvents);
3371
- if (data2 === null) {
3372
- setError(
3373
- new Error(
3374
- `Failed to load ${resource} details: missing required event data`
3375
- )
3376
- );
3377
- return;
3378
- }
3379
- setData(data2);
3380
- } catch (hydrateError) {
3381
- setError(
3382
- hydrateError instanceof Error ? hydrateError : new Error(String(hydrateError))
3383
- );
3384
- }
3385
- } finally {
3386
- setLoading(false);
3387
- }
3388
- return;
3430
+ async function fetchSpanDetailResource(env, selection, options = {}) {
3431
+ const { resource, resourceId, runId } = selection;
3432
+ const { encryptionKey } = options;
3433
+ const hydrate = async (value) => encryptionKey ? hydrateResourceIOWithKey(value, encryptionKey) : hydrateResourceIO(value);
3434
+ if (resource === "hook") {
3435
+ const result = await unwrapOrThrow(fetchHook(env, resourceId, "all"));
3436
+ return hydrate(result);
3437
+ }
3438
+ if (resource === "sleep") {
3439
+ if (!runId) {
3440
+ throw new WorkflowWebAPIError(
3441
+ "runId is required for loading sleep details",
3442
+ { layer: "client" }
3443
+ );
3389
3444
  }
3390
- try {
3391
- const { data: resourceData } = await fetchResourceWithCorrelationId(
3392
- env,
3393
- resource,
3394
- resourceId,
3395
- { runId }
3445
+ const result = await unwrapOrThrow(
3446
+ fetchEvents(env, runId, { sortOrder: "asc", limit: 1e3, withData: true })
3447
+ );
3448
+ const allEvents = result.data.map(
3449
+ hydrateResourceIO
3450
+ );
3451
+ const waitEvents = await Promise.all(
3452
+ allEvents.filter((e) => e.correlationId === resourceId).map(hydrate)
3453
+ );
3454
+ const data2 = waitEventsToWaitEntity(waitEvents);
3455
+ if (data2 === null) {
3456
+ throw new WorkflowWebAPIError(
3457
+ `Failed to load ${resource} details: missing required event data`,
3458
+ { layer: "client" }
3396
3459
  );
3397
- setData(await hydrate(resourceData));
3398
- } catch (error2) {
3399
- if (error2 instanceof Error) {
3400
- setError(error2);
3401
- } else {
3402
- setError(new Error(String(error2)));
3403
- }
3404
- return;
3405
- } finally {
3406
- setLoading(false);
3407
3460
  }
3408
- }, [env, resource, resourceId, runId, enabled, hydrate]);
3409
- reactExports.useEffect(() => {
3410
- fetchData();
3411
- }, [fetchData]);
3412
- reactExports.useEffect(() => {
3413
- if (!refreshInterval || refreshInterval <= 0) {
3414
- return;
3461
+ return data2;
3462
+ }
3463
+ const { data } = await fetchResourceWithCorrelationId(
3464
+ env,
3465
+ resource,
3466
+ resourceId,
3467
+ {
3468
+ runId
3415
3469
  }
3416
- const interval = setInterval(fetchData, refreshInterval);
3417
- return () => clearInterval(interval);
3418
- }, [refreshInterval, fetchData]);
3419
- return {
3420
- data,
3421
- loading,
3422
- error,
3423
- refresh: fetchData
3424
- };
3470
+ );
3471
+ return hydrate(data);
3425
3472
  }
3426
3473
  function mergeById(prev, next, idKey) {
3427
3474
  const combined = [...prev, ...next];
@@ -5426,30 +5473,15 @@ function RunDetailView({
5426
5473
  encryptionKey: encryptionKey ?? void 0,
5427
5474
  enabled: activeTab === "events"
5428
5475
  });
5429
- const [spanSelection, setSpanSelection] = reactExports.useState(
5430
- null
5431
- );
5432
- const {
5433
- data: spanDetailData,
5434
- loading: spanDetailLoading,
5435
- error: spanDetailError,
5436
- refresh: refreshSpanDetail
5437
- } = useWorkflowResourceData(
5438
- env,
5439
- (spanSelection == null ? void 0 : spanSelection.resource) ?? "run",
5440
- (spanSelection == null ? void 0 : spanSelection.resourceId) ?? "",
5441
- {
5442
- runId: spanSelection == null ? void 0 : spanSelection.runId,
5443
- enabled: Boolean(
5444
- (spanSelection == null ? void 0 : spanSelection.resource) && (spanSelection == null ? void 0 : spanSelection.resourceId) && spanSelection.resource !== "hook"
5445
- ),
5476
+ const fetchSpanDetail = reactExports.useCallback(
5477
+ (selection) => fetchSpanDetailResource(env, selection, {
5446
5478
  encryptionKey: encryptionKey ?? void 0
5447
- }
5479
+ }),
5480
+ [env, encryptionKey]
5448
5481
  );
5449
5482
  const [isDecrypting, setIsDecrypting] = reactExports.useState(false);
5450
5483
  const handleDecrypt = reactExports.useCallback(async () => {
5451
5484
  if (encryptionKey) {
5452
- refreshSpanDetail();
5453
5485
  return;
5454
5486
  }
5455
5487
  setIsDecrypting(true);
@@ -5467,18 +5499,12 @@ function RunDetailView({
5467
5499
  } finally {
5468
5500
  setIsDecrypting(false);
5469
5501
  }
5470
- }, [encryptionKey, env, runId, refreshSpanDetail]);
5471
- const handleSpanSelect = reactExports.useCallback((info) => {
5472
- setSpanSelection(info);
5473
- }, []);
5502
+ }, [encryptionKey, env, runId]);
5474
5503
  const sidebarData = reactExports.useMemo(
5475
5504
  () => ({
5476
5505
  run,
5477
5506
  events: allEvents ?? [],
5478
- spanDetailData: spanDetailData ?? null,
5479
- spanDetailError,
5480
- spanDetailLoading,
5481
- onSpanSelect: handleSpanSelect,
5507
+ fetchSpanDetail,
5482
5508
  onStreamClick: handleStreamClick,
5483
5509
  onRunClick: handleRunRefClick,
5484
5510
  onWakeUpSleep: handleWakeUpSleep,
@@ -5492,10 +5518,7 @@ function RunDetailView({
5492
5518
  [
5493
5519
  run,
5494
5520
  allEvents,
5495
- spanDetailData,
5496
- spanDetailError,
5497
- spanDetailLoading,
5498
- handleSpanSelect,
5521
+ fetchSpanDetail,
5499
5522
  handleStreamClick,
5500
5523
  handleRunRefClick,
5501
5524
  handleWakeUpSleep,