@workflow/web 5.0.0-beta.24 → 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-e1cf8511.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-BzGs1YV_.js → run-detail-sr7StYc6.js} +359 -355
  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-1p4IhK-Q.js → app-e2FYIgWU.js} +5 -1
  12. package/build/server/assets/{highlighted-body-B3W2YXNL-BlH6gm7c.js → highlighted-body-B3W2YXNL-B7xcG7gl.js} +6 -2
  13. package/build/server/assets/{index-BOfd00Ok.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-4IS2FONM.js → mermaid-3ZIDBTTL-DQqBhQ9Y.js} +6 -2
  18. package/build/server/assets/{server-build-CpnmV4F1.js → server-build-D7EgG_DH.js} +740 -532
  19. package/build/server/assets/{token-fPsafoXW.js → token-guLCf66r.js} +6 -2
  20. package/build/server/assets/{token-util-MV-dKCwg.js → token-util-CCeU4-vR.js} +6 -2
  21. package/build/server/assets/{zstd-browser-decoder-embi2ab_.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,24 +1111,17 @@ const MARKER_EVENT_TYPES = /* @__PURE__ */ new Set([
1081
1111
  "wait_completed",
1082
1112
  "attr_set"
1083
1113
  ]);
1084
- const findEventByType = (events, eventTypes) => {
1085
- for (const eventType of eventTypes) {
1086
- const event = events.find((e) => e.eventType === eventType);
1087
- if (event)
1088
- return event;
1089
- }
1090
- return void 0;
1091
- };
1092
- const withOccurredAt = (entity, occurredAt) => {
1093
- if (!occurredAt || entity.occurredAt != null) {
1094
- return entity;
1095
- }
1096
- return { ...entity, occurredAt };
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;
1097
1120
  };
1098
- function convertEventsToSpanEvents(events, filterTypes = true) {
1121
+ function convertEventsToSpanEvents(events, filterTypes = true, options = {}) {
1099
1122
  return events.filter((event) => filterTypes ? MARKER_EVENT_TYPES.has(event.eventType) : true).map((event) => ({
1100
1123
  name: event.eventType,
1101
- timestamp: dateToOtelTime(event.createdAt),
1124
+ timestamp: dateToOtelTime(options.preferOccurredAt ? getEventTimestamp(event) ?? event.createdAt : event.createdAt),
1102
1125
  attributes: {
1103
1126
  eventId: event.eventId,
1104
1127
  correlationId: event.correlationId,
@@ -1115,13 +1138,13 @@ const waitEventsToWaitEntity = (events) => {
1115
1138
  return null;
1116
1139
  }
1117
1140
  const completedEvent = events.find((event) => event.eventType === "wait_completed");
1118
- return withOccurredAt({
1141
+ return {
1119
1142
  waitId: startEvent.correlationId,
1120
1143
  runId: startEvent.runId,
1121
- createdAt: startEvent.createdAt,
1144
+ createdAt: getEventTimestamp(startEvent) ?? startEvent.createdAt,
1122
1145
  resumeAt: ((_a = startEvent.eventData) == null ? void 0 : _a.resumeAt) ? new Date(startEvent.eventData.resumeAt) : void 0,
1123
- completedAt: completedEvent == null ? void 0 : completedEvent.createdAt
1124
- }, startEvent.occurredAt);
1146
+ completedAt: getEventTimestamp(completedEvent)
1147
+ };
1125
1148
  };
1126
1149
  function waitToSpan(events, maxEndTime, fallbackEndTime = maxEndTime) {
1127
1150
  const wait = waitEventsToWaitEntity(events);
@@ -1177,16 +1200,16 @@ const stepEventsToStepEntity = (events) => {
1177
1200
  status = "running";
1178
1201
  attempt += 1;
1179
1202
  if (!startedAt)
1180
- startedAt = e.createdAt;
1203
+ startedAt = getEventTimestamp(e) ?? e.createdAt;
1181
1204
  completedAt = void 0;
1182
1205
  break;
1183
1206
  case "step_completed":
1184
1207
  status = "completed";
1185
- completedAt = e.createdAt;
1208
+ completedAt = getEventTimestamp(e) ?? e.createdAt;
1186
1209
  break;
1187
1210
  case "step_failed":
1188
1211
  status = "failed";
1189
- completedAt = e.createdAt;
1212
+ completedAt = getEventTimestamp(e) ?? e.createdAt;
1190
1213
  break;
1191
1214
  case "step_retrying":
1192
1215
  status = "pending";
@@ -1197,19 +1220,18 @@ const stepEventsToStepEntity = (events) => {
1197
1220
  if (attempt === 0)
1198
1221
  attempt = 1;
1199
1222
  const lastEvent = events[events.length - 1];
1200
- const occurrenceEvent = findEventByType(events, ["step_created", "step_started"]) ?? anchorEvent;
1201
- return withOccurredAt({
1223
+ return {
1202
1224
  stepId: anchorEvent.correlationId ?? "",
1203
1225
  runId: anchorEvent.runId,
1204
1226
  stepName: ((_a = createdEvent == null ? void 0 : createdEvent.eventData) == null ? void 0 : _a.stepName) ?? "",
1205
1227
  status,
1206
1228
  attempt,
1207
- createdAt: anchorEvent.createdAt,
1208
- 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,
1209
1231
  startedAt,
1210
1232
  completedAt,
1211
1233
  specVersion: anchorEvent.specVersion
1212
- }, occurrenceEvent.occurredAt);
1234
+ };
1213
1235
  };
1214
1236
  function stepToSpan(stepEvents, maxEndTime) {
1215
1237
  const step = stepEventsToStepEntity(stepEvents);
@@ -1222,13 +1244,20 @@ function stepToSpan(stepEvents, maxEndTime) {
1222
1244
  data: step
1223
1245
  };
1224
1246
  const resource = "step";
1225
- const endTime = new Date(step.completedAt ?? maxEndTime);
1226
- const events = convertEventsToSpanEvents(stepEvents, false);
1227
- 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);
1228
1252
  let activeStartTime = step.startedAt ? new Date(step.startedAt) : void 0;
1229
1253
  const firstStartEvent = stepEvents.find((event) => event.eventType === "step_started");
1230
1254
  if (firstStartEvent) {
1231
- 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);
1232
1261
  }
1233
1262
  return {
1234
1263
  spanId: String(step.stepId),
@@ -1250,7 +1279,7 @@ function stepToSpan(stepEvents, maxEndTime) {
1250
1279
  };
1251
1280
  }
1252
1281
  const hookEventsToHookEntity = (events) => {
1253
- var _a, _b;
1282
+ var _a;
1254
1283
  const createdEvent = events.find((event) => event.eventType === "hook_created");
1255
1284
  if (!createdEvent) {
1256
1285
  return null;
@@ -1258,15 +1287,15 @@ const hookEventsToHookEntity = (events) => {
1258
1287
  const receivedEvents = events.filter((event) => event.eventType === "hook_received");
1259
1288
  const disposedEvents = events.filter((event) => event.eventType === "hook_disposed");
1260
1289
  const lastReceivedEvent = receivedEvents.at(-1);
1261
- return withOccurredAt({
1290
+ return {
1262
1291
  hookId: createdEvent.correlationId,
1263
1292
  runId: createdEvent.runId,
1264
1293
  token: (_a = createdEvent.eventData) == null ? void 0 : _a.token,
1265
- createdAt: createdEvent.createdAt,
1294
+ createdAt: getEventTimestamp(createdEvent) ?? createdEvent.createdAt,
1266
1295
  receivedCount: receivedEvents.length,
1267
- lastReceivedAt: (lastReceivedEvent == null ? void 0 : lastReceivedEvent.createdAt) || void 0,
1268
- disposedAt: ((_b = disposedEvents.at(-1)) == null ? void 0 : _b.createdAt) || void 0
1269
- }, createdEvent.occurredAt);
1296
+ lastReceivedAt: getEventTimestamp(lastReceivedEvent),
1297
+ disposedAt: getEventTimestamp(disposedEvents.at(-1))
1298
+ };
1270
1299
  };
1271
1300
  function hookToSpan(hookEvents, maxEndTime) {
1272
1301
  const hook = hookEventsToHookEntity(hookEvents);
@@ -1298,19 +1327,26 @@ function hookToSpan(hookEvents, maxEndTime) {
1298
1327
  function runToSpan(run, runEvents, nowTime) {
1299
1328
  var _a;
1300
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;
1301
1337
  const { input: _i, output: _o, error: _e, ...runIdentity } = run;
1302
- const occurrenceEvent = findEventByType(runEvents, [
1303
- "run_created",
1304
- "run_started"
1305
- ]);
1306
1338
  const attributes = {
1307
1339
  resource: "run",
1308
- data: withOccurredAt(runIdentity, occurrenceEvent == null ? void 0 : occurrenceEvent.occurredAt)
1340
+ data: {
1341
+ ...runIdentity,
1342
+ createdAt: spanStartTime,
1343
+ startedAt: activeStartTime,
1344
+ completedAt
1345
+ }
1309
1346
  };
1310
- const spanStartTime = new Date(run.createdAt);
1311
- const activeStartTime = run.startedAt ? new Date(run.startedAt) : void 0;
1312
- const endTime = run.completedAt ?? now;
1313
- const events = convertEventsToSpanEvents(runEvents, false);
1347
+ const events = convertEventsToSpanEvents(runEvents, false, {
1348
+ preferOccurredAt: true
1349
+ });
1314
1350
  return {
1315
1351
  spanId: String(run.runId),
1316
1352
  name: String(((_a = parseWorkflowName(run.workflowName)) == null ? void 0 : _a.shortName) ?? "?"),
@@ -1380,7 +1416,7 @@ function groupEventsByCorrelation(events) {
1380
1416
  function computeLatestKnownTime(events, run) {
1381
1417
  let latest = new Date(run.createdAt).getTime();
1382
1418
  for (const event of events) {
1383
- const t = new Date(event.createdAt).getTime();
1419
+ const t = (getEventTimestamp(event) ?? new Date(event.createdAt)).getTime();
1384
1420
  if (t > latest)
1385
1421
  latest = t;
1386
1422
  }
@@ -1973,7 +2009,7 @@ const getModuleSpecifierFromName = (value) => {
1973
2009
  }
1974
2010
  return raw;
1975
2011
  };
1976
- const parseDateValue = (value) => {
2012
+ const parseDateValue$1 = (value) => {
1977
2013
  if (value == null) {
1978
2014
  return null;
1979
2015
  }
@@ -1988,14 +2024,14 @@ const parseDateValue = (value) => {
1988
2024
  };
1989
2025
  const formatLocalMillisecondTime = (date) => format(date, "MMM dd HH:mm:ss.SS OO").toUpperCase();
1990
2026
  const localMillisecondTimeOrNull = (value) => {
1991
- const date = parseDateValue(value);
2027
+ const date = parseDateValue$1(value);
1992
2028
  if (!date) {
1993
2029
  return null;
1994
2030
  }
1995
2031
  return formatLocalMillisecondTime(date);
1996
2032
  };
1997
2033
  const timestampWithTooltipOrNull = (value) => {
1998
- const date = parseDateValue(value);
2034
+ const date = parseDateValue$1(value);
1999
2035
  if (!date)
2000
2036
  return null;
2001
2037
  return jsxRuntimeExports.jsx(TimestampTooltip, { date, children: jsxRuntimeExports.jsx("span", { children: formatLocalMillisecondTime(date) }) });
@@ -2202,8 +2238,8 @@ const AttributePanel = ({ data, moduleSpecifier, isLoading, error, expiredAt, on
2202
2238
  return present;
2203
2239
  if (resource === "sleep")
2204
2240
  return present;
2205
- const loadingDefaults = ["input", "output"];
2206
- for (const key of loadingDefaults) {
2241
+ const loadingPlaceholders = ["input", "output"];
2242
+ for (const key of loadingPlaceholders) {
2207
2243
  if (!present.includes(key)) {
2208
2244
  present.push(key);
2209
2245
  }
@@ -2268,7 +2304,23 @@ const DATA_EVENT_TYPES = /* @__PURE__ */ new Set([
2268
2304
  "wait_completed",
2269
2305
  "attr_set"
2270
2306
  ]);
2271
- 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 }) {
2272
2324
  const [loadedData, setLoadedData] = reactExports.useState(null);
2273
2325
  const [isLoading, setIsLoading] = reactExports.useState(false);
2274
2326
  const [loadError, setLoadError] = reactExports.useState(null);
@@ -2309,16 +2361,18 @@ function EventItem({ event, onLoadEventData, encryptionKey }) {
2309
2361
  void loadEventData({ force: true });
2310
2362
  }, [encryptionKey, loadEventData]);
2311
2363
  const createdAt = new Date(event.createdAt);
2312
- 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, {
2313
2367
  hour: "numeric",
2314
2368
  minute: "numeric",
2315
2369
  second: "numeric"
2316
2370
  });
2317
2371
  const displayPayload = isLoading ? loadedData : mergedDisplay;
2318
- 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) => {
2319
2373
  if (open)
2320
2374
  handleExpand();
2321
- } : 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 }) })] });
2322
2376
  }
2323
2377
  function hasOnlyExpiredFields(data, eventType) {
2324
2378
  if (data === null || typeof data !== "object" || Array.isArray(data)) {
@@ -2354,15 +2408,52 @@ function EventDataBlock({ eventType, data }) {
2354
2408
  }
2355
2409
  return jsxRuntimeExports.jsx(CopyableDataBlock, { data });
2356
2410
  }
2357
- function EventsList({ events, isLoading = false, error, onLoadEventData, onStreamClick, onRunClick, encryptionKey }) {
2358
- 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]);
2359
2413
  const hasEvents = sortedEvents.length > 0 && !error;
2360
2414
  if (!hasEvents && !isLoading) {
2361
2415
  return jsxRuntimeExports.jsx(DetailCard, { summary: "Events", disabled: true });
2362
2416
  }
2363
- 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)) }) }) }) });
2364
2418
  }
2365
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
+ }
2366
2457
  function spanDetailMatchesSelection(detail, resource, resourceId) {
2367
2458
  if (!detail || typeof detail !== "object" || !resource || !resourceId) {
2368
2459
  return false;
@@ -2395,16 +2486,88 @@ function mergeSpanDetail(spanData, detail) {
2395
2486
  }
2396
2487
  return merged;
2397
2488
  }
2398
- function isStep(data) {
2399
- 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;
2400
2514
  }
2401
- function isWorkflowRun(data) {
2402
- 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
+ };
2403
2566
  }
2404
2567
  function isHook(data) {
2405
2568
  return data !== null && typeof data === "object" && "hookId" in data;
2406
2569
  }
2407
- 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 }) {
2408
2571
  const toast2 = useToast();
2409
2572
  const [stoppingSleep, setStoppingSleep] = reactExports.useState(false);
2410
2573
  const [showResolveHookModal, setShowResolveHookModal] = reactExports.useState(false);
@@ -2415,41 +2578,8 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
2415
2578
  const data = selectedSpan == null ? void 0 : selectedSpan.data;
2416
2579
  const rawEvents = selectedSpan == null ? void 0 : selectedSpan.rawEvents;
2417
2580
  const rawEventsLength = (rawEvents == null ? void 0 : rawEvents.length) ?? 0;
2418
- const { resource, resourceId, runId } = reactExports.useMemo(() => {
2419
- if (!selectedSpan) {
2420
- return { resource: void 0, resourceId: void 0, runId: void 0 };
2421
- }
2422
- const res = selectedSpan.resource;
2423
- if (res === "step" && isStep(data)) {
2424
- return { resource: "step", resourceId: data.stepId, runId: data.runId };
2425
- }
2426
- if (res === "run" && isWorkflowRun(data)) {
2427
- return { resource: "run", resourceId: data.runId, runId: void 0 };
2428
- }
2429
- if (res === "hook" && isHook(data)) {
2430
- return { resource: "hook", resourceId: data.hookId, runId: void 0 };
2431
- }
2432
- if (res === "sleep") {
2433
- const waitData = data;
2434
- return {
2435
- resource: "sleep",
2436
- resourceId: selectedSpan.spanId,
2437
- runId: waitData == null ? void 0 : waitData.runId
2438
- };
2439
- }
2440
- return { resource: void 0, resourceId: void 0, runId: void 0 };
2441
- }, [selectedSpan, data]);
2442
- const onSpanSelectRef = reactExports.useRef(onSpanSelect);
2443
- onSpanSelectRef.current = onSpanSelect;
2444
- reactExports.useEffect(() => {
2445
- if (resource && resourceId && ["run", "step", "hook", "sleep"].includes(resource)) {
2446
- onSpanSelectRef.current({
2447
- resource,
2448
- resourceId,
2449
- runId
2450
- });
2451
- }
2452
- }, [resource, resourceId, runId]);
2581
+ const { status, resource, resourceId, displayData, detail: matchedSpanDetailData, error } = useSelectedSpanDetail(selectedSpan, fetchSpanDetail);
2582
+ const loading = status === "loading";
2453
2583
  const canWakeUp = reactExports.useMemo(() => {
2454
2584
  if (resource !== "sleep" || !rawEvents)
2455
2585
  return false;
@@ -2482,9 +2612,6 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
2482
2612
  run.status,
2483
2613
  resolvedHookIds
2484
2614
  ]);
2485
- const error = spanDetailError ?? void 0;
2486
- const loading = spanDetailLoading ?? false;
2487
- const matchedSpanDetailData = reactExports.useMemo(() => spanDetailMatchesSelection(spanDetailData, resource, resourceId) ? spanDetailData : null, [spanDetailData, resource, resourceId]);
2488
2615
  const hookToken = reactExports.useMemo(() => {
2489
2616
  if (resource !== "hook" || !resourceId)
2490
2617
  return void 0;
@@ -2569,7 +2696,6 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
2569
2696
  setResolvingHook(false);
2570
2697
  }
2571
2698
  }, [onResolveHook, hookToken, resolvingHook, matchedSpanDetailData, data]);
2572
- const displayData = reactExports.useMemo(() => mergeSpanDetail(data, matchedSpanDetailData), [data, matchedSpanDetailData]);
2573
2699
  const moduleSpecifier = reactExports.useMemo(() => {
2574
2700
  const displayRecord = displayData;
2575
2701
  const displayStepName = displayRecord.stepName;
@@ -2598,43 +2724,7 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
2598
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: {
2599
2725
  background: "var(--ds-gray-1000)",
2600
2726
  color: "var(--ds-background-100)"
2601
- }, 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 })] });
2602
- }
2603
- const kbdVariants = cva("inline-flex items-center justify-center rounded px-1 text-center font-sans", {
2604
- variants: {
2605
- variant: {
2606
- subtle: "bg-background-100/20",
2607
- outline: "border border-gray-alpha-400 bg-background-100 font-medium text-gray-900"
2608
- },
2609
- size: {
2610
- default: "h-5 min-w-5 text-xs leading-none",
2611
- compact: "h-4 min-h-4 min-w-4 text-[11px] leading-none",
2612
- search: "h-5 min-h-5 min-w-5 text-[13px] leading-[1.7em]"
2613
- }
2614
- },
2615
- defaultVariants: {
2616
- variant: "subtle",
2617
- size: "default"
2618
- }
2619
- });
2620
- function Kbd({ children, className, variant, size, ...props }) {
2621
- return jsxRuntimeExports.jsx("kbd", { className: cn(kbdVariants({ variant, size, className })), ...props, children });
2622
- }
2623
- const COL_TEMPLATE = "340px 1px minmax(50px, 1fr)";
2624
- const ROWS = [
2625
- { id: "r0", name: 62, off: 0, bar: 72 },
2626
- { id: "r1", name: 78, off: 6, bar: 48 },
2627
- { id: "r2", name: 50, off: 10, bar: 55 },
2628
- { id: "r3", name: 84, off: 18, bar: 30 },
2629
- { id: "r4", name: 45, off: 18, bar: 42 },
2630
- { id: "r5", name: 66, off: 34, bar: 38 },
2631
- { id: "r6", name: 55, off: 41, bar: 25 },
2632
- { id: "r7", name: 40, off: 50, bar: 30 }
2633
- ];
2634
- const HEADER_MARKERS = ["m0", "m1", "m2", "m3"];
2635
- 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" }) });
2636
- function TraceViewerSkeleton() {
2637
- 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 })] });
2638
2728
  }
2639
2729
  function useIntersectionObserver(elementRef, { threshold = 0, rootRef, rootMargin = "0%", freezeOnceVisible = false } = {}) {
2640
2730
  const [entry, setEntry] = reactExports.useState();
@@ -2671,6 +2761,26 @@ function useLoadMoreOnScroll(loadMore, { hasMore, isLoadingMore, rootRef, rootMa
2671
2761
  }, [entry == null ? void 0 : entry.isIntersecting, hasMore, isLoadingMore]);
2672
2762
  return sentinelRef;
2673
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
+ }
2674
2784
  const WorkflowIcon = () => {
2675
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" }) });
2676
2786
  };
@@ -2717,57 +2827,6 @@ const EventList = ({ spans, activeSpanId, searchResult, onSelectSpan }) => {
2717
2827
  paddingBottom: (spans.length - end) * ROW_HEIGHT_PX
2718
2828
  }, children: spans.slice(start, end).map((span) => jsxRuntimeExports.jsx(EventRow, { span, isSelected: span.spanId === activeSpanId, isDimmed: isSpanDimmedBySearch(span.spanId, searchResult), onSelectSpan }, span.spanId)) });
2719
2829
  };
2720
- const hint = "_hint_1dmsq_3";
2721
- const styles = {
2722
- hint
2723
- };
2724
- const DISMISSALS_KEY = "workflow-step-shortcut-helper-dismissals";
2725
- const DISMISSAL_LIMIT = 3;
2726
- const HINT_ROTATION_MS = 8e3;
2727
- function getAltKeyLabel() {
2728
- if (typeof navigator === "undefined")
2729
- return "Alt";
2730
- return navigator.platform.toLowerCase().includes("mac") ? "Option" : "Alt";
2731
- }
2732
- function readDismissals() {
2733
- try {
2734
- const dismissals = Number.parseInt(window.localStorage.getItem(DISMISSALS_KEY) ?? "0", 10);
2735
- return Number.isNaN(dismissals) ? 0 : dismissals;
2736
- } catch {
2737
- return 0;
2738
- }
2739
- }
2740
- function AltHint() {
2741
- return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: ["Hold", jsxRuntimeExports.jsx(Kbd, { variant: "outline", size: "compact", className: "mx-1", children: getAltKeyLabel() }), "to see delta between spans"] });
2742
- }
2743
- function NavHint() {
2744
- 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"] });
2745
- }
2746
- function TraceShortcutHelper({ hasMultipleSpans, reducedMotion }) {
2747
- const [visible, setVisible] = reactExports.useState(false);
2748
- const [index, setIndex] = reactExports.useState(0);
2749
- reactExports.useEffect(() => {
2750
- setVisible(readDismissals() < DISMISSAL_LIMIT);
2751
- }, []);
2752
- reactExports.useEffect(() => {
2753
- if (reducedMotion)
2754
- return;
2755
- const id = setInterval(() => {
2756
- setIndex((i) => i === 0 ? 1 : 0);
2757
- }, HINT_ROTATION_MS);
2758
- return () => clearInterval(id);
2759
- }, [reducedMotion]);
2760
- if (!visible || !hasMultipleSpans)
2761
- return null;
2762
- const dismiss = () => {
2763
- try {
2764
- window.localStorage.setItem(DISMISSALS_KEY, String(readDismissals() + 1));
2765
- } catch {
2766
- }
2767
- setVisible(false);
2768
- };
2769
- 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" }) })] });
2770
- }
2771
2830
  const GUTTER_PX = 1;
2772
2831
  const MIN_PX = 50;
2773
2832
  const DEFAULT_START_PX = 340;
@@ -2865,6 +2924,57 @@ function SplitPane({ children, className, defaultStartWidth = DEFAULT_START_PX,
2865
2924
  }
2866
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] });
2867
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
+ }
2868
2978
  const MIN_VIEWPORT_MS = 1e-3;
2869
2979
  const ZOOM_DEBOUNCE_MS = 150;
2870
2980
  function useAnimatedViewport(initial) {
@@ -3275,7 +3385,7 @@ function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
3275
3385
  e.stopPropagation();
3276
3386
  setSearchQuery("");
3277
3387
  }
3278
- }, 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 })] });
3279
3389
  }
3280
3390
  const NewTraceViewer = ({ run, events, sidebarData, onLoadMore, hasMore, isLoadingMore, loading = false }) => {
3281
3391
  const trace = reactExports.useMemo(() => {
@@ -3317,130 +3427,48 @@ async function fetchResourceWithCorrelationId(env, resource, resourceId, options
3317
3427
  }
3318
3428
  return { data: resourceData, correlationId };
3319
3429
  }
3320
- function useWorkflowResourceData(env, resource, resourceId, options = {}) {
3321
- const { refreshInterval = 0, runId, enabled = true, encryptionKey } = options;
3322
- const [data, setData] = reactExports.useState(
3323
- null
3324
- );
3325
- const [loading, setLoading] = reactExports.useState(enabled);
3326
- const [error, setError] = reactExports.useState(null);
3327
- const hydrate = reactExports.useCallback(
3328
- async (resource2) => encryptionKey ? hydrateResourceIOWithKey(resource2, encryptionKey) : hydrateResourceIO(resource2),
3329
- [encryptionKey]
3330
- );
3331
- const prevSelectionRef = reactExports.useRef("");
3332
- const fetchData = reactExports.useCallback(async () => {
3333
- if (!enabled) {
3334
- setLoading(false);
3335
- return;
3336
- }
3337
- const selectionKey = `${resource}:${resourceId}`;
3338
- if (selectionKey !== prevSelectionRef.current) {
3339
- setData(null);
3340
- prevSelectionRef.current = selectionKey;
3341
- }
3342
- setError(null);
3343
- setLoading(true);
3344
- if (resource === "hook") {
3345
- try {
3346
- const { error: error2, result } = await unwrapServerActionResult(
3347
- fetchHook(env, resourceId, "all")
3348
- );
3349
- if (error2) {
3350
- setError(error2);
3351
- return;
3352
- }
3353
- try {
3354
- setData(await hydrate(result));
3355
- } catch (hydrateError) {
3356
- setError(
3357
- hydrateError instanceof Error ? hydrateError : new Error(String(hydrateError))
3358
- );
3359
- }
3360
- } finally {
3361
- setLoading(false);
3362
- }
3363
- return;
3364
- }
3365
- if (resource === "sleep") {
3366
- try {
3367
- if (!runId) {
3368
- setError(new Error("runId is required for loading sleep details"));
3369
- return;
3370
- }
3371
- const { error: error2, result } = await unwrapServerActionResult(
3372
- fetchEvents(env, runId, {
3373
- sortOrder: "asc",
3374
- limit: 1e3,
3375
- withData: true
3376
- })
3377
- );
3378
- if (error2) {
3379
- setError(error2);
3380
- return;
3381
- }
3382
- try {
3383
- const allEvents = result.data.map(
3384
- hydrateResourceIO
3385
- );
3386
- const waitEvents = await Promise.all(
3387
- allEvents.filter((e) => e.correlationId === resourceId).map(hydrate)
3388
- );
3389
- const data2 = waitEventsToWaitEntity(waitEvents);
3390
- if (data2 === null) {
3391
- setError(
3392
- new Error(
3393
- `Failed to load ${resource} details: missing required event data`
3394
- )
3395
- );
3396
- return;
3397
- }
3398
- setData(data2);
3399
- } catch (hydrateError) {
3400
- setError(
3401
- hydrateError instanceof Error ? hydrateError : new Error(String(hydrateError))
3402
- );
3403
- }
3404
- } finally {
3405
- setLoading(false);
3406
- }
3407
- 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
+ );
3408
3444
  }
3409
- try {
3410
- const { data: resourceData } = await fetchResourceWithCorrelationId(
3411
- env,
3412
- resource,
3413
- resourceId,
3414
- { 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" }
3415
3459
  );
3416
- setData(await hydrate(resourceData));
3417
- } catch (error2) {
3418
- if (error2 instanceof Error) {
3419
- setError(error2);
3420
- } else {
3421
- setError(new Error(String(error2)));
3422
- }
3423
- return;
3424
- } finally {
3425
- setLoading(false);
3426
3460
  }
3427
- }, [env, resource, resourceId, runId, enabled, hydrate]);
3428
- reactExports.useEffect(() => {
3429
- fetchData();
3430
- }, [fetchData]);
3431
- reactExports.useEffect(() => {
3432
- if (!refreshInterval || refreshInterval <= 0) {
3433
- return;
3461
+ return data2;
3462
+ }
3463
+ const { data } = await fetchResourceWithCorrelationId(
3464
+ env,
3465
+ resource,
3466
+ resourceId,
3467
+ {
3468
+ runId
3434
3469
  }
3435
- const interval = setInterval(fetchData, refreshInterval);
3436
- return () => clearInterval(interval);
3437
- }, [refreshInterval, fetchData]);
3438
- return {
3439
- data,
3440
- loading,
3441
- error,
3442
- refresh: fetchData
3443
- };
3470
+ );
3471
+ return hydrate(data);
3444
3472
  }
3445
3473
  function mergeById(prev, next, idKey) {
3446
3474
  const combined = [...prev, ...next];
@@ -5445,30 +5473,15 @@ function RunDetailView({
5445
5473
  encryptionKey: encryptionKey ?? void 0,
5446
5474
  enabled: activeTab === "events"
5447
5475
  });
5448
- const [spanSelection, setSpanSelection] = reactExports.useState(
5449
- null
5450
- );
5451
- const {
5452
- data: spanDetailData,
5453
- loading: spanDetailLoading,
5454
- error: spanDetailError,
5455
- refresh: refreshSpanDetail
5456
- } = useWorkflowResourceData(
5457
- env,
5458
- (spanSelection == null ? void 0 : spanSelection.resource) ?? "run",
5459
- (spanSelection == null ? void 0 : spanSelection.resourceId) ?? "",
5460
- {
5461
- runId: spanSelection == null ? void 0 : spanSelection.runId,
5462
- enabled: Boolean(
5463
- (spanSelection == null ? void 0 : spanSelection.resource) && (spanSelection == null ? void 0 : spanSelection.resourceId) && spanSelection.resource !== "hook"
5464
- ),
5476
+ const fetchSpanDetail = reactExports.useCallback(
5477
+ (selection) => fetchSpanDetailResource(env, selection, {
5465
5478
  encryptionKey: encryptionKey ?? void 0
5466
- }
5479
+ }),
5480
+ [env, encryptionKey]
5467
5481
  );
5468
5482
  const [isDecrypting, setIsDecrypting] = reactExports.useState(false);
5469
5483
  const handleDecrypt = reactExports.useCallback(async () => {
5470
5484
  if (encryptionKey) {
5471
- refreshSpanDetail();
5472
5485
  return;
5473
5486
  }
5474
5487
  setIsDecrypting(true);
@@ -5486,18 +5499,12 @@ function RunDetailView({
5486
5499
  } finally {
5487
5500
  setIsDecrypting(false);
5488
5501
  }
5489
- }, [encryptionKey, env, runId, refreshSpanDetail]);
5490
- const handleSpanSelect = reactExports.useCallback((info) => {
5491
- setSpanSelection(info);
5492
- }, []);
5502
+ }, [encryptionKey, env, runId]);
5493
5503
  const sidebarData = reactExports.useMemo(
5494
5504
  () => ({
5495
5505
  run,
5496
5506
  events: allEvents ?? [],
5497
- spanDetailData: spanDetailData ?? null,
5498
- spanDetailError,
5499
- spanDetailLoading,
5500
- onSpanSelect: handleSpanSelect,
5507
+ fetchSpanDetail,
5501
5508
  onStreamClick: handleStreamClick,
5502
5509
  onRunClick: handleRunRefClick,
5503
5510
  onWakeUpSleep: handleWakeUpSleep,
@@ -5511,10 +5518,7 @@ function RunDetailView({
5511
5518
  [
5512
5519
  run,
5513
5520
  allEvents,
5514
- spanDetailData,
5515
- spanDetailError,
5516
- spanDetailLoading,
5517
- handleSpanSelect,
5521
+ fetchSpanDetail,
5518
5522
  handleStreamClick,
5519
5523
  handleRunRefClick,
5520
5524
  handleWakeUpSleep,