@workflow/web 4.1.5 → 4.1.7

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.
@@ -1,5 +1,5 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports, w as withComponentProps, v as withErrorBoundaryProps, M as Meta, L as Links, S as ScrollRestoration, x as Scripts, O as Outlet, y as useRouteError, i as isRouteErrorResponse, z as Link, A as useNavigate, B as useSearchParams } from "./index-DQa-BExo.js";
2
- import { c as createLucideIcon, u as useServerConfig, T as Tooltip, a as TooltipTrigger, b as TooltipContent, r as runHealthCheck, t as toast, B as Button, L as LoaderCircle, d as cn, e as Toaster$1, S as ServerConfigProvider, f as TooltipProvider } from "./mermaid-3ZIDBTTL-B_qZU5zW.js";
2
+ import { c as createLucideIcon, u as useServerConfig, T as Tooltip, a as TooltipTrigger, b as TooltipContent, r as runHealthCheck, t as toast, B as Button, L as LoaderCircle, d as cn, e as Toaster$1, S as ServerConfigProvider, f as TooltipProvider } from "./mermaid-3ZIDBTTL-Cr7OQX4b.js";
3
3
  var M = (e, i, s, u, m, a, l, h) => {
4
4
  let d = document.documentElement, w = ["light", "dark"];
5
5
  function p(n) {
@@ -1,6 +1,6 @@
1
1
  import { j as jsxRuntimeExports, r as reactExports, f as reactDomExports, C as ReactDOM, A as useNavigate, B as useSearchParams, z as Link, w as withComponentProps, G as useParams } from "./index-DQa-BExo.js";
2
- import { O as Copy, C as CircleAlert, Q as parseStepName, B as parseWorkflowName, j as ChevronRight, q as Check, U as ErrorCard, Z as Zap, S as Send, R as ResolveHookModal, p as ChevronUp, o as ChevronDown, X, N as ErrorBoundary, V as Clock, G as CircleX, I as unwrapServerActionResult, u as unwrapOrThrow, W as WorkflowWebAPIError, Y as useEscapeKeydown, v as composeEventHandlers, _ as useCallbackRef, $ as useLayoutEffect2, t as createContextScope, a0 as createContext2, s as useControllableState, a1 as useId, w as Presence, l as hideOthers, m as ReactRemoveScroll, a2 as useFocusGuards, a3 as LAYOUT, a4 as wakeUpRun, r as resumeHook, A as Alert, c as AlertTitle, d as AlertDescription, a as Skeleton$1, a5 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, a6 as recreateRun } from "./workflow-graph-viewer-D5yEggTb.js";
3
- import { c as createLucideIcon, M as Spinner, h as useToast, N as Skeleton, O as DecryptClickContext, Y as Yr, U as isEncryptedMarker, W as formatDuration, X as DataInspector, _ as _r, Z as StreamClickContext, $ as isExpiredMarker, a0 as isDoStreamStep, a1 as extractConversation, a2 as Lock, a3 as EVENT_DATA_REF_FIELDS, a4 as clsx, a5 as useTraceViewer, a6 as styles, a7 as formatDurationForTimeline, a8 as formatWallClockTime, a9 as useImmediateStyle, aa as TIMELINE_PADDING, ab as formatTimeSelection, ac as MARKER_HEIGHT, ad as ROW_HEIGHT, ae as ROW_PADDING, af as SEARCH_HEIGHT, ag as getHighResInMs, ah as getMsInHighRes, ai as MARKER_NOTCH_HEIGHT, aj as MAP_HEIGHT, ak as SEARCH_GAP, al as MiniMap, am as SpanNodes, an as SpanDetailPanel, ao as TraceViewerContextProvider, ap as hydrateResourceIOWithKey, aq as hydrateResourceIO, ar as fetchHook, l as fetchEvents, F as fetchRun, as as fetchStep, at as hasEncryptedFields, au as fetchStreams, av as Slot, E as useComposedRefs, aw as Slottable, d as cn, ax as buttonVariants, ay as isEncryptedData, az as hydrateData, aA as getWebRevivers, T as Tooltip, a as TooltipTrigger, b as TooltipContent, aB as LIVE_UPDATE_INTERVAL_MS$1, u as useServerConfig, aC as fetchEvent, aD as getEncryptionKeyForRun, t as toast, L as LoaderCircle, aE as StreamViewer } from "./mermaid-3ZIDBTTL-B_qZU5zW.js";
2
+ import { O as Copy, C as CircleAlert, Q as parseStepName, B as parseWorkflowName, j as ChevronRight, q as Check, U as ErrorCard, Z as Zap, S as Send, R as ResolveHookModal, p as ChevronUp, o as ChevronDown, X, N as ErrorBoundary, V as Clock, G as CircleX, I as unwrapServerActionResult, u as unwrapOrThrow, W as WorkflowWebAPIError, Y as useEscapeKeydown, t as composeEventHandlers, _ as useCallbackRef, $ as useLayoutEffect2, s as useControllableState, a0 as useId, a1 as createContext2, v as Presence, x as createContextScope, l as hideOthers, m as ReactRemoveScroll, a2 as useFocusGuards, a3 as LAYOUT, a4 as wakeUpRun, r as resumeHook, A as Alert, c as AlertTitle, d as AlertDescription, a as Skeleton$1, a5 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, a6 as recreateRun } from "./workflow-graph-viewer-P4oMQJaV.js";
3
+ import { c as createLucideIcon, M as Spinner, h as useToast, N as Skeleton, O as DecryptClickContext, Y as Yr, U as isEncryptedMarker, W as formatDuration, X as DataInspector, _ as _r, Z as StreamClickContext, $ as isExpiredMarker, a0 as isDoStreamStep, a1 as extractConversation, a2 as Lock, a3 as EVENT_DATA_REF_FIELDS, a4 as clsx, a5 as useTraceViewer, a6 as styles, a7 as formatDurationForTimeline, a8 as formatWallClockTime, a9 as useImmediateStyle, aa as TIMELINE_PADDING, ab as formatTimeSelection, ac as MARKER_HEIGHT, ad as ROW_HEIGHT, ae as ROW_PADDING, af as SEARCH_HEIGHT, ag as getHighResInMs, ah as getMsInHighRes, ai as MARKER_NOTCH_HEIGHT, aj as MAP_HEIGHT, ak as SEARCH_GAP, al as MiniMap, am as SpanNodes, an as SpanDetailPanel, ao as TraceViewerContextProvider, ap as hydrateResourceIOWithKey, aq as hydrateResourceIO, ar as fetchHook, l as fetchEvents, F as fetchRun, as as fetchStep, at as hasEncryptedFields, au as fetchStreams, av as Slot, E as useComposedRefs, aw as Slottable, d as cn, ax as buttonVariants, ay as isEncryptedData, az as hydrateData, aA as getWebRevivers, aB as fetchEvent, aC as fetchEventsByCorrelationId, T as Tooltip, a as TooltipTrigger, b as TooltipContent, aD as LIVE_UPDATE_INTERVAL_MS$1, u as useServerConfig, aE as getEncryptionKeyForRun, t as toast, L as LoaderCircle, aF as StreamViewer } from "./mermaid-3ZIDBTTL-Cr7OQX4b.js";
4
4
  import { decrypt, importKey } from "./encryption-80GMP4r0.js";
5
5
  /**
6
6
  * @license lucide-react v0.575.0 - ISC
@@ -53,6 +53,33 @@ const __iconNode = [
53
53
  ["path", { d: "M9 20h6", key: "s66wpe" }]
54
54
  ];
55
55
  const Type = createLucideIcon("type", __iconNode);
56
+ const WORKFLOW_ULID_BODY = "[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}";
57
+ const STEP_ID_PATTERN = new RegExp(`^step_(${WORKFLOW_ULID_BODY})$`, "i");
58
+ const WAIT_ID_PATTERN = new RegExp(`^wait_(${WORKFLOW_ULID_BODY})$`, "i");
59
+ const HOOK_ID_PATTERN = new RegExp(`^hook_(${WORKFLOW_ULID_BODY})$`, "i");
60
+ const EVENT_ID_PATTERN = new RegExp(`^evnt_(${WORKFLOW_ULID_BODY})$`, "i");
61
+ const WORKFLOW_ID_PREFIX_PATTERN = /^(step_|wait_|hook_|evnt_|wrun_)/i;
62
+ function matchPrefixedId(pattern, prefix, kind, query) {
63
+ const match = query.match(pattern);
64
+ if (!match) {
65
+ return null;
66
+ }
67
+ return { kind, id: `${prefix}_${match[1].toUpperCase()}` };
68
+ }
69
+ function parseExactWorkflowSearchId(query) {
70
+ const trimmed = query.trim();
71
+ if (!trimmed) {
72
+ return null;
73
+ }
74
+ return matchPrefixedId(STEP_ID_PATTERN, "step", "step", trimmed) ?? matchPrefixedId(WAIT_ID_PATTERN, "wait", "wait", trimmed) ?? matchPrefixedId(HOOK_ID_PATTERN, "hook", "hook", trimmed) ?? matchPrefixedId(EVENT_ID_PATTERN, "evnt", "event", trimmed);
75
+ }
76
+ function looksLikeWorkflowIdSearchInput(query) {
77
+ const trimmed = query.trim();
78
+ if (!WORKFLOW_ID_PREFIX_PATTERN.test(trimmed)) {
79
+ return false;
80
+ }
81
+ return /\d/.test(trimmed);
82
+ }
56
83
  const STYLES$2 = `.wf-decrypt-btn{appearance:none;-webkit-appearance:none;border:none;display:inline-flex;align-items:center;justify-content:center;height:40px;padding:0 12px;border-radius:6px;font-size:14px;font-weight:500;line-height:20px;cursor:pointer;white-space:nowrap;gap:6px;transition:background 150ms}.wf-decrypt-idle{color:var(--ds-gray-1000);background:var(--ds-background-100);box-shadow:0 0 0 1px var(--ds-gray-400)}.wf-decrypt-idle:hover{background:var(--ds-gray-alpha-200)}.wf-decrypt-done{color:var(--ds-green-900);background:var(--ds-green-100);box-shadow:0 0 0 1px var(--ds-green-400);cursor:default}`;
57
84
  function DecryptButton({ decrypted = false, loading = false, onClick }) {
58
85
  return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("style", { dangerouslySetInnerHTML: { __html: STYLES$2 } }), jsxRuntimeExports.jsxs("button", { type: "button", onClick: decrypted ? void 0 : onClick, disabled: decrypted || loading, className: `wf-decrypt-btn ${decrypted ? "wf-decrypt-done" : "wf-decrypt-idle"}`, children: [loading ? jsxRuntimeExports.jsx(Spinner, { size: 14 }) : decrypted ? jsxRuntimeExports.jsxs("svg", { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }), jsxRuntimeExports.jsx("path", { d: "M7 11V7a5 5 0 0 1 9.9-1" })] }) : jsxRuntimeExports.jsxs("svg", { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }), jsxRuntimeExports.jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })] }), loading ? "Decrypting…" : decrypted ? "Decrypted" : "Decrypt"] })] });
@@ -372,27 +399,34 @@ function buildNameMaps(events, run) {
372
399
  return { correlationNameMap, workflowName };
373
400
  }
374
401
  function buildDurationMap(events) {
402
+ const chronological = [...events].sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
375
403
  const createdTimes = /* @__PURE__ */ new Map();
404
+ const firstStartedTimes = /* @__PURE__ */ new Map();
376
405
  const startedTimes = /* @__PURE__ */ new Map();
377
406
  const durations = /* @__PURE__ */ new Map();
378
- for (const event of events) {
407
+ for (const event of chronological) {
379
408
  const ts = new Date(event.createdAt).getTime();
380
409
  const key = event.correlationId ?? "__run__";
381
410
  const type = event.eventType;
382
411
  if (type === "step_created" || type === "run_created") {
383
- createdTimes.set(key, ts);
384
- }
385
- if (type === "step_started" || type === "run_started" || type === "workflow_started") {
386
- startedTimes.set(key, ts);
387
412
  if (!createdTimes.has(key)) {
388
413
  createdTimes.set(key, ts);
389
414
  }
390
- const createdAt = createdTimes.get(key);
391
- const info = durations.get(key) ?? {};
392
- if (createdAt !== void 0) {
393
- info.queued = ts - createdAt;
415
+ }
416
+ if (type === "step_started" || type === "run_started" || type === "workflow_started") {
417
+ startedTimes.set(key, ts);
418
+ if (!firstStartedTimes.has(key)) {
419
+ firstStartedTimes.set(key, ts);
420
+ if (!createdTimes.has(key)) {
421
+ createdTimes.set(key, ts);
422
+ }
423
+ const createdAt = createdTimes.get(key);
424
+ const info = durations.get(key) ?? {};
425
+ if (createdAt !== void 0) {
426
+ info.queued = ts - createdAt;
427
+ }
428
+ durations.set(key, info);
394
429
  }
395
- durations.set(key, info);
396
430
  }
397
431
  if (type === "step_completed" || type === "step_failed" || type === "run_completed" || type === "run_failed" || type === "run_cancelled" || type === "workflow_completed" || type === "workflow_failed" || type === "wait_completed" || type === "hook_disposed") {
398
432
  const startedAt = startedTimes.get(key);
@@ -603,7 +637,7 @@ function RowsSkeleton() {
603
637
  marginLeft: i % 4 === 0 ? 5 : 6
604
638
  } })] }), 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)) });
605
639
  }
606
- function EventRow({ event, index, isFirst, isLast, isExpanded, onToggleExpand, activeGroupKey, selectedGroupKey, selectedGroupRange, correlationNameMap, workflowName, durationMap, onSelectGroup, onHoverGroup, onLoadEventData, cachedEventData, onCacheEventData, encryptionKey, onEncryptedDataDetected }) {
640
+ function EventRow({ event, index, isFirst, isLast, isExpanded, onToggleExpand, activeGroupKey, selectedGroupKey, selectedGroupRange, correlationNameMap, workflowName, durationMap, onSelectGroup, onHoverGroup, onLoadEventData, cachedEventData, onCacheEventData, encryptionKey, onEncryptedDataDetected, suppressGroupDimming = false }) {
607
641
  const [isLoading, setIsLoading] = reactExports.useState(false);
608
642
  const [loadedEventData, setLoadedEventData] = reactExports.useState(cachedEventData);
609
643
  const [loadError, setLoadError] = reactExports.useState(null);
@@ -623,7 +657,7 @@ function EventRow({ event, index, isFirst, isLast, isExpanded, onToggleExpand, a
623
657
  const durationInfo = durationKey ? durationMap.get(durationKey) : void 0;
624
658
  const hasActive = activeGroupKey !== void 0;
625
659
  const isRelated = rowGroupKey !== void 0 && rowGroupKey === activeGroupKey;
626
- const isDimmed = hasActive && !isRelated;
660
+ const isDimmed = hasActive && !isRelated && !suppressGroupDimming;
627
661
  const isPulsing = hasActive && isRelated;
628
662
  const showBranch = hasActive && isRelated && !isRun;
629
663
  const showLaneLine = selectedGroupRange !== null && index >= selectedGroupRange.first && index <= selectedGroupRange.last;
@@ -748,7 +782,8 @@ function EventRow({ event, index, isFirst, isLast, isExpanded, onToggleExpand, a
748
782
  color: "var(--ds-red-900)"
749
783
  }, 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" })] })] })] });
750
784
  }
751
- function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, isLoadingMoreEvents = false, onLoadMoreEvents, encryptionKey, isLoading = false, sortOrder: sortOrderProp, onSortOrderChange, onDecrypt, isDecrypting = false, hasEncryptedData: hasEncryptedDataProp = false }) {
785
+ function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, isLoadingMoreEvents = false, onLoadMoreEvents, encryptionKey, isLoading = false, sortOrder: sortOrderProp, onSortOrderChange, onDecrypt, isDecrypting = false, hasEncryptedData: hasEncryptedDataProp = false, onExactIdSearch }) {
786
+ const toast2 = useToast();
752
787
  const [internalSortOrder, setInternalSortOrder] = reactExports.useState("asc");
753
788
  const effectiveSortOrder = sortOrderProp ?? internalSortOrder;
754
789
  const handleSortOrderChange = reactExports.useCallback((order) => {
@@ -758,28 +793,40 @@ function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, is
758
793
  setInternalSortOrder(order);
759
794
  }
760
795
  }, [onSortOrderChange]);
796
+ const [searchQuery, setSearchQuery] = reactExports.useState("");
797
+ const [searchResults, setSearchResults] = reactExports.useState(null);
798
+ const [searchResultsTruncated, setSearchResultsTruncated] = reactExports.useState(false);
799
+ const [searchError, setSearchError] = reactExports.useState(null);
800
+ const [searchLoading, setSearchLoading] = reactExports.useState(false);
801
+ const [searchNotFound, setSearchNotFound] = reactExports.useState(false);
802
+ const searchRequestRef = reactExports.useRef(0);
803
+ const virtuosoRef = reactExports.useRef(null);
804
+ const parsedSearchId = reactExports.useMemo(() => parseExactWorkflowSearchId(searchQuery), [searchQuery]);
805
+ const isExactSearchActive = searchResults !== null;
761
806
  const sortedEvents = reactExports.useMemo(() => {
762
- if (!events || events.length === 0)
807
+ const sourceEvents = isExactSearchActive ? searchResults : events ?? [];
808
+ if (sourceEvents.length === 0)
763
809
  return [];
764
810
  const dir = effectiveSortOrder === "desc" ? -1 : 1;
765
- return [...events].sort((a, b) => dir * (new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()));
766
- }, [events, effectiveSortOrder]);
811
+ return [...sourceEvents].sort((a, b) => dir * (new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()));
812
+ }, [events, effectiveSortOrder, isExactSearchActive, searchResults]);
767
813
  const hasEncryptedInlineData = reactExports.useMemo(() => {
768
- if (!events)
814
+ const sourceEvents = isExactSearchActive ? searchResults : events;
815
+ if (!sourceEvents)
769
816
  return false;
770
- for (const event of events) {
817
+ for (const event of sourceEvents) {
771
818
  const ed = event.eventData;
772
819
  if (hasEncryptedValues(ed))
773
820
  return true;
774
821
  }
775
822
  return false;
776
- }, [events]);
823
+ }, [events, isExactSearchActive, searchResults]);
777
824
  const [foundEncryptedInLazyData, setFoundEncryptedInLazyData] = reactExports.useState(false);
778
825
  const handleEncryptedDataDetected = reactExports.useCallback(() => {
779
826
  setFoundEncryptedInLazyData(true);
780
827
  }, []);
781
828
  const hasEncryptedData = hasEncryptedDataProp || hasEncryptedInlineData || foundEncryptedInLazyData;
782
- const { correlationNameMap, workflowName } = reactExports.useMemo(() => buildNameMaps(events ?? null, run ?? null), [events, run]);
829
+ const { correlationNameMap, workflowName } = reactExports.useMemo(() => buildNameMaps(isExactSearchActive ? searchResults : events ?? null, run ?? null), [events, isExactSearchActive, run, searchResults]);
783
830
  const durationMap = reactExports.useMemo(() => buildDurationMap(sortedEvents), [sortedEvents]);
784
831
  const [selectedGroupKey, setSelectedGroupKey] = reactExports.useState(void 0);
785
832
  const [hoveredGroupKey, setHoveredGroupKey] = reactExports.useState(void 0);
@@ -847,58 +894,100 @@ function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, is
847
894
  }
848
895
  return first >= 0 ? { first, last } : null;
849
896
  }, [activeGroupKey, sortedEvents]);
850
- const [searchQuery, setSearchQuery] = reactExports.useState("");
851
- const virtuosoRef = reactExports.useRef(null);
852
- const searchIndex = reactExports.useMemo(() => {
853
- const entries = [];
854
- for (let i = 0; i < sortedEvents.length; i++) {
855
- const ev = sortedEvents[i];
856
- const isRun = isRunLevel(ev.eventType);
857
- const name = isRun ? workflowName ?? "" : ev.correlationId ? correlationNameMap.get(ev.correlationId) ?? "" : "";
858
- entries.push({
859
- fields: [
860
- ev.eventId,
861
- ev.correlationId ?? "",
862
- ev.eventType,
863
- formatEventType(ev.eventType),
864
- name
865
- ].map((f) => f.toLowerCase()),
866
- groupKey: ev.correlationId ?? (isRun ? "__run__" : void 0),
867
- eventId: ev.eventId,
868
- index: i
869
- });
870
- }
871
- return entries;
872
- }, [sortedEvents, correlationNameMap, workflowName]);
873
897
  reactExports.useEffect(() => {
874
- var _a;
875
- const q = searchQuery.trim().toLowerCase();
876
- if (!q) {
898
+ const trimmed = searchQuery.trim();
899
+ if (!trimmed) {
900
+ searchRequestRef.current += 1;
901
+ setSearchResults(null);
902
+ setSearchResultsTruncated(false);
903
+ setSearchError(null);
904
+ setSearchLoading(false);
905
+ setSearchNotFound(false);
877
906
  setSelectedGroupKey(void 0);
878
907
  return;
879
908
  }
880
- let bestMatch = null;
881
- let bestScore = 0;
882
- for (const entry of searchIndex) {
883
- for (const field of entry.fields) {
884
- if (field && field.includes(q)) {
885
- const score = q.length / field.length;
886
- if (score > bestScore) {
887
- bestScore = score;
888
- bestMatch = entry;
909
+ const parsed = parseExactWorkflowSearchId(trimmed);
910
+ if (!parsed || !onExactIdSearch) {
911
+ setSearchResults(null);
912
+ setSearchLoading(false);
913
+ setSearchNotFound(false);
914
+ return;
915
+ }
916
+ const requestId = ++searchRequestRef.current;
917
+ setSearchLoading(true);
918
+ setSearchNotFound(false);
919
+ setSearchError(null);
920
+ const abortController = new AbortController();
921
+ const timer = setTimeout(() => {
922
+ void (async () => {
923
+ var _a;
924
+ try {
925
+ const results = await onExactIdSearch(parsed.id, parsed.kind, abortController.signal);
926
+ if (abortController.signal.aborted || searchRequestRef.current !== requestId) {
927
+ return;
928
+ }
929
+ if (results.status === "error") {
930
+ setSearchResults([]);
931
+ setSearchResultsTruncated(false);
932
+ setSearchNotFound(false);
933
+ setSearchError(results.message);
934
+ setSelectedGroupKey(void 0);
935
+ return;
936
+ }
937
+ if (results.status === "not_found" || results.status === "ok" && results.events.length === 0) {
938
+ setSearchResults([]);
939
+ setSearchResultsTruncated(false);
940
+ setSearchNotFound(true);
941
+ setSearchError(null);
942
+ setSelectedGroupKey(void 0);
943
+ return;
944
+ }
945
+ setSearchResults(results.events);
946
+ setSearchResultsTruncated(Boolean(results.truncated));
947
+ setSearchNotFound(false);
948
+ setSearchError(null);
949
+ setSelectedGroupKey(parsed.kind === "event" ? (() => {
950
+ const first = results.events[0];
951
+ if (!first)
952
+ return void 0;
953
+ return isRunLevel(first.eventType) ? "__run__" : first.correlationId ?? void 0;
954
+ })() : parsed.id);
955
+ (_a = virtuosoRef.current) == null ? void 0 : _a.scrollToIndex({
956
+ index: 0,
957
+ align: "start",
958
+ behavior: "smooth"
959
+ });
960
+ } catch {
961
+ if (abortController.signal.aborted || searchRequestRef.current !== requestId) {
962
+ return;
963
+ }
964
+ setSearchResults([]);
965
+ setSearchResultsTruncated(false);
966
+ setSearchNotFound(false);
967
+ setSearchError("Failed to search events. Try again.");
968
+ setSelectedGroupKey(void 0);
969
+ } finally {
970
+ if (searchRequestRef.current === requestId && !abortController.signal.aborted) {
971
+ setSearchLoading(false);
889
972
  }
890
973
  }
891
- }
974
+ })();
975
+ }, 300);
976
+ return () => {
977
+ clearTimeout(timer);
978
+ abortController.abort();
979
+ };
980
+ }, [searchQuery, onExactIdSearch]);
981
+ const handleSearchKeyDown = reactExports.useCallback((event) => {
982
+ if (event.key !== "Enter") {
983
+ return;
892
984
  }
893
- if (bestMatch) {
894
- setSelectedGroupKey(bestMatch.groupKey);
895
- (_a = virtuosoRef.current) == null ? void 0 : _a.scrollToIndex({
896
- index: bestMatch.index,
897
- align: "center",
898
- behavior: "smooth"
899
- });
985
+ const trimmed = searchQuery.trim();
986
+ if (!trimmed || parseExactWorkflowSearchId(trimmed) || !onExactIdSearch || !looksLikeWorkflowIdSearchInput(trimmed)) {
987
+ return;
900
988
  }
901
- }, [searchQuery, searchIndex]);
989
+ toast2.info("Enter a full step ID, wait ID, hook ID, or event ID");
990
+ }, [searchQuery, onExactIdSearch, toast2]);
902
991
  const hasHadEventsRef = reactExports.useRef(false);
903
992
  if (sortedEvents.length > 0) {
904
993
  hasHadEventsRef.current = true;
@@ -908,9 +997,6 @@ function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, is
908
997
  if (isInitialLoad) {
909
998
  return jsxRuntimeExports.jsxs("div", { className: "h-full flex flex-col overflow-hidden", children: [jsxRuntimeExports.jsx("div", { style: { padding: 6 }, children: jsxRuntimeExports.jsx(Skeleton, { style: { height: 40, borderRadius: 6 } }) }), jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-0 h-10 border-b flex-shrink-0", style: { borderColor: "var(--ds-gray-alpha-200)" }, 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: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: 40 } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: 72 } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: 44 } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: 92 } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: 60 } }) })] }), jsxRuntimeExports.jsx(RowsSkeleton, {})] });
910
999
  }
911
- if (!isLoading && (!events || events.length === 0)) {
912
- return jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-full text-sm", style: { color: "var(--ds-gray-700)" }, children: "No events found" });
913
- }
914
1000
  return jsxRuntimeExports.jsx(DecryptClickContext.Provider, { value: onDecrypt ? { onDecrypt, isDecrypting } : void 0, children: jsxRuntimeExports.jsxs("div", { className: "h-full flex flex-col overflow-hidden", children: [jsxRuntimeExports.jsx("style", { children: `@keyframes workflow-dot-pulse{0%{transform:scale(1);opacity:.7}70%,100%{transform:scale(2.2);opacity:0}}` }), jsxRuntimeExports.jsxs("div", { style: {
915
1001
  padding: 6,
916
1002
  backgroundColor: "var(--ds-background-100)",
@@ -934,7 +1020,7 @@ function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, is
934
1020
  justifyContent: "center",
935
1021
  color: "var(--ds-gray-800)",
936
1022
  flexShrink: 0
937
- }, children: jsxRuntimeExports.jsxs("svg", { width: 16, height: 16, viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", focusable: "false", children: [jsxRuntimeExports.jsx("circle", { cx: "7", cy: "7", r: "4.5", stroke: "currentColor", strokeWidth: "1.5" }), jsxRuntimeExports.jsx("path", { d: "M11.5 11.5L14 14", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })] }) }), jsxRuntimeExports.jsx("input", { type: "search", placeholder: "Search by name, event type, or ID…", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), style: {
1023
+ }, children: jsxRuntimeExports.jsxs("svg", { width: 16, height: 16, viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", focusable: "false", children: [jsxRuntimeExports.jsx("circle", { cx: "7", cy: "7", r: "4.5", stroke: "currentColor", strokeWidth: "1.5" }), jsxRuntimeExports.jsx("path", { d: "M11.5 11.5L14 14", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })] }) }), jsxRuntimeExports.jsx("input", { type: "search", placeholder: "Search by step ID, wait ID, hook ID, or event ID…", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onKeyDown: handleSearchKeyDown, disabled: !onExactIdSearch, title: onExactIdSearch ? void 0 : "Exact ID search is unavailable in this view.", style: {
938
1024
  marginLeft: -16,
939
1025
  paddingInline: 12,
940
1026
  fontFamily: "inherit",
@@ -943,24 +1029,26 @@ function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, is
943
1029
  border: "none",
944
1030
  outline: "none",
945
1031
  height: 40,
946
- width: "100%"
1032
+ width: "100%",
1033
+ opacity: onExactIdSearch ? 1 : 0.5,
1034
+ cursor: onExactIdSearch ? "text" : "not-allowed"
947
1035
  } })] }), jsxRuntimeExports.jsx(MenuDropdown, { options: SORT_OPTIONS, value: effectiveSortOrder, onChange: handleSortOrderChange }), (hasEncryptedData || encryptionKey) && onDecrypt && jsxRuntimeExports.jsx(DecryptButton, { decrypted: !!encryptionKey, loading: isDecrypting, onClick: onDecrypt })] }), jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-0 text-[13px] font-medium h-10 border-b flex-shrink-0", style: {
948
1036
  borderColor: "var(--ds-gray-alpha-200)",
949
1037
  color: "var(--ds-gray-900)",
950
1038
  backgroundColor: "var(--ds-background-100)"
951
- }, 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 ? jsxRuntimeExports.jsx(RowsSkeleton, {}) : jsxRuntimeExports.jsx(Yr, { ref: virtuosoRef, totalCount: sortedEvents.length, overscan: 20, defaultItemHeight: 40, endReached: () => {
952
- if (!hasMoreEvents || isLoadingMoreEvents) {
1039
+ }, 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: () => {
1040
+ if (isExactSearchActive || !hasMoreEvents || isLoadingMoreEvents) {
953
1041
  return;
954
1042
  }
955
1043
  void (onLoadMoreEvents == null ? void 0 : onLoadMoreEvents());
956
1044
  }, itemContent: (index) => {
957
1045
  const ev = sortedEvents[index];
958
- return jsxRuntimeExports.jsx(EventRow, { 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 });
1046
+ return jsxRuntimeExports.jsx(EventRow, { 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 });
959
1047
  }, 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: {
960
1048
  borderColor: "var(--ds-gray-alpha-200)",
961
1049
  color: "var(--ds-gray-900)",
962
1050
  backgroundColor: "var(--ds-background-100)"
963
- }, children: [jsxRuntimeExports.jsxs("span", { children: [sortedEvents.length, " event", sortedEvents.length !== 1 ? "s" : "", " loaded"] }), hasMoreEvents && jsxRuntimeExports.jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: jsxRuntimeExports.jsx("div", { className: "pointer-events-auto", children: jsxRuntimeExports.jsx(LoadMoreButton, { loading: isLoadingMoreEvents, onClick: () => void (onLoadMoreEvents == null ? void 0 : onLoadMoreEvents()) }) }) })] })] }) });
1051
+ }, children: [jsxRuntimeExports.jsx("span", { children: isExactSearchActive ? searchError ? searchError : searchNotFound ? `No events found for ${searchQuery.trim()}` : `${sortedEvents.length} event${sortedEvents.length !== 1 ? "s" : ""} for ${searchQuery.trim()}${searchResultsTruncated ? " (results may be truncated)" : ""}` : `${sortedEvents.length} event${sortedEvents.length !== 1 ? "s" : ""} loaded` }), !isExactSearchActive && hasMoreEvents && jsxRuntimeExports.jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: jsxRuntimeExports.jsx("div", { className: "pointer-events-auto", children: jsxRuntimeExports.jsx(LoadMoreButton, { loading: isLoadingMoreEvents, onClick: () => void (onLoadMoreEvents == null ? void 0 : onLoadMoreEvents()) }) }) })] })] }) });
964
1052
  }
965
1053
  function ConversationView({ messages }) {
966
1054
  if (messages.length === 0) {
@@ -3388,7 +3476,7 @@ function hookToSpan(hookEvents, maxEndTime) {
3388
3476
  const endTime = hook.disposedAt || maxEndTime;
3389
3477
  return {
3390
3478
  spanId: String(hook.hookId),
3391
- name: String(hook.hookId),
3479
+ name: hook.token ?? String(hook.hookId),
3392
3480
  kind: 1,
3393
3481
  // INTERNAL span kind
3394
3482
  resource: "hook",
@@ -4054,7 +4142,7 @@ const WorkflowTraceViewer = ({ run, events, isLoading, error, spanDetailData, sp
4054
4142
  if (!trace) {
4055
4143
  return jsxRuntimeExports.jsxs("div", { className: "relative w-full h-full", children: [jsxRuntimeExports.jsx("div", { className: "border-b border-gray-alpha-400 w-full" }), jsxRuntimeExports.jsx(Skeleton, { className: "w-full ml-2 mt-1 mb-1 h-[56px]" }), jsxRuntimeExports.jsxs("div", { className: "p-2 relative w-full", children: [jsxRuntimeExports.jsx(Skeleton, { className: "w-full mt-6 h-[20px]" }), jsxRuntimeExports.jsx(Skeleton, { className: "w-[10%] mt-2 ml-6 h-[20px]" }), jsxRuntimeExports.jsx(Skeleton, { className: "w-[10%] mt-2 ml-12 h-[20px]" }), jsxRuntimeExports.jsx(Skeleton, { className: "w-[20%] mt-2 ml-16 h-[20px]" })] })] });
4056
4144
  }
4057
- return jsxRuntimeExports.jsxs("div", { className: "relative w-full h-full flex", children: [jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0 relative", children: jsxRuntimeExports.jsxs(TraceViewerContextProvider, { customSpanClassNameFunc: getCustomSpanClassName, customSpanEventClassNameFunc: getCustomSpanEventClassName, children: [jsxRuntimeExports.jsx(SelectionBridge, { onSelectionChange: handleSelectionChange }), jsxRuntimeExports.jsx(DeselectBridge, { triggerDeselect: deselectTrigger }), jsxRuntimeExports.jsx(SelectBridge, { selectRequest }), jsxRuntimeExports.jsx(TraceViewerWithContextMenu, { trace, run, isLive, onWakeUpSleep, onCancelRun, onResolveHook, onLoadMoreSpans, hasMoreSpans, isLoadingMoreSpans, children: jsxRuntimeExports.jsx(TraceViewerTimeline, { eagerRender: true, height: "100%", isLive, trace, knownDurationMs: traceWithMeta == null ? void 0 : traceWithMeta.knownDurationMs, hasMoreData: hasMoreSpans || Boolean(isLoading), footer: jsxRuntimeExports.jsx(TraceViewerFooter, { hasMore: hasMoreSpans, isLive, isInitialLoading: Boolean(isLoading) }) }) })] }) }), selectedSpan && jsxRuntimeExports.jsxs("div", { className: "relative border-l flex-shrink-0 flex flex-col", style: {
4145
+ return jsxRuntimeExports.jsxs("div", { className: "relative w-full h-full flex flex-row", children: [jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0 relative", children: jsxRuntimeExports.jsxs(TraceViewerContextProvider, { customSpanClassNameFunc: getCustomSpanClassName, customSpanEventClassNameFunc: getCustomSpanEventClassName, children: [jsxRuntimeExports.jsx(SelectionBridge, { onSelectionChange: handleSelectionChange }), jsxRuntimeExports.jsx(DeselectBridge, { triggerDeselect: deselectTrigger }), jsxRuntimeExports.jsx(SelectBridge, { selectRequest }), jsxRuntimeExports.jsx(TraceViewerWithContextMenu, { trace, run, isLive, onWakeUpSleep, onCancelRun, onResolveHook, onLoadMoreSpans, hasMoreSpans, isLoadingMoreSpans, children: jsxRuntimeExports.jsx(TraceViewerTimeline, { eagerRender: true, height: "100%", isLive, trace, knownDurationMs: traceWithMeta == null ? void 0 : traceWithMeta.knownDurationMs, hasMoreData: hasMoreSpans || Boolean(isLoading), footer: jsxRuntimeExports.jsx(TraceViewerFooter, { hasMore: hasMoreSpans, isLive, isInitialLoading: Boolean(isLoading) }) }) })] }) }), selectedSpan && jsxRuntimeExports.jsxs("div", { className: "relative border-l flex-shrink-0 flex flex-col", style: {
4058
4146
  width: panelWidth,
4059
4147
  borderColor: "var(--ds-gray-200)",
4060
4148
  backgroundColor: "var(--ds-background-100)"
@@ -6022,6 +6110,7 @@ function useStreamReader(env, streamId, runId, encryptionKey, runStatus) {
6022
6110
  }
6023
6111
  const INITIAL_PAGE_SIZE = 100;
6024
6112
  const LOAD_MORE_PAGE_SIZE = 100;
6113
+ const MAX_CORRELATION_SEARCH_PAGES = 30;
6025
6114
  function useEventsListData(env, runId, options = {}) {
6026
6115
  const { sortOrder = "asc", encryptionKey, enabled = true } = options;
6027
6116
  const [events, setEvents] = reactExports.useState([]);
@@ -6033,6 +6122,16 @@ function useEventsListData(env, runId, options = {}) {
6033
6122
  const isFetchingRef = reactExports.useRef(false);
6034
6123
  const encryptionKeyRef = reactExports.useRef(encryptionKey);
6035
6124
  encryptionKeyRef.current = encryptionKey;
6125
+ const hydrateEvents = reactExports.useCallback(async (rawEvents) => {
6126
+ const hydrated = rawEvents.map(hydrateResourceIO);
6127
+ const key = encryptionKeyRef.current;
6128
+ if (key) {
6129
+ return Promise.all(
6130
+ hydrated.map((ev) => hydrateResourceIOWithKey(ev, key))
6131
+ );
6132
+ }
6133
+ return hydrated;
6134
+ }, []);
6036
6135
  const fetchInitial = reactExports.useCallback(async () => {
6037
6136
  if (isFetchingRef.current) return;
6038
6137
  isFetchingRef.current = true;
@@ -6052,16 +6151,7 @@ function useEventsListData(env, runId, options = {}) {
6052
6151
  if (fetchError) {
6053
6152
  setError(fetchError);
6054
6153
  } else {
6055
- const hydrated = result.data.map(hydrateResourceIO);
6056
- const key = encryptionKeyRef.current;
6057
- if (key) {
6058
- const decrypted = await Promise.all(
6059
- hydrated.map((ev) => hydrateResourceIOWithKey(ev, key))
6060
- );
6061
- setEvents(decrypted);
6062
- } else {
6063
- setEvents(hydrated);
6064
- }
6154
+ setEvents(await hydrateEvents(result.data));
6065
6155
  setCursor(result.hasMore ? result.cursor : void 0);
6066
6156
  setHasMore(Boolean(result.hasMore));
6067
6157
  }
@@ -6071,7 +6161,7 @@ function useEventsListData(env, runId, options = {}) {
6071
6161
  setLoading(false);
6072
6162
  isFetchingRef.current = false;
6073
6163
  }
6074
- }, [env, runId, sortOrder]);
6164
+ }, [env, runId, sortOrder, hydrateEvents]);
6075
6165
  reactExports.useEffect(() => {
6076
6166
  if (enabled) fetchInitial();
6077
6167
  }, [fetchInitial, enabled]);
@@ -6102,16 +6192,8 @@ function useEventsListData(env, runId, options = {}) {
6102
6192
  setError(fetchError);
6103
6193
  } else {
6104
6194
  if (result.data.length > 0) {
6105
- const hydrated = result.data.map(hydrateResourceIO);
6106
- const key = encryptionKeyRef.current;
6107
- if (key) {
6108
- const decrypted = await Promise.all(
6109
- hydrated.map((ev) => hydrateResourceIOWithKey(ev, key))
6110
- );
6111
- setEvents((prev) => [...prev, ...decrypted]);
6112
- } else {
6113
- setEvents((prev) => [...prev, ...hydrated]);
6114
- }
6195
+ const hydrated = await hydrateEvents(result.data);
6196
+ setEvents((prev) => [...prev, ...hydrated]);
6115
6197
  }
6116
6198
  setCursor(result.hasMore ? result.cursor : void 0);
6117
6199
  setHasMore(Boolean(result.hasMore));
@@ -6121,14 +6203,65 @@ function useEventsListData(env, runId, options = {}) {
6121
6203
  } finally {
6122
6204
  setLoadingMore(false);
6123
6205
  }
6124
- }, [env, runId, sortOrder, cursor, loadingMore]);
6206
+ }, [env, runId, sortOrder, cursor, loadingMore, hydrateEvents]);
6207
+ const searchByExactId = reactExports.useCallback(
6208
+ async (id, kind, signal) => {
6209
+ if (signal == null ? void 0 : signal.aborted) {
6210
+ throw new DOMException("Aborted", "AbortError");
6211
+ }
6212
+ if (kind === "event") {
6213
+ const { error: fetchError, result } = await unwrapServerActionResult(
6214
+ fetchEvent(env, runId, id, "none")
6215
+ );
6216
+ if (fetchError || (signal == null ? void 0 : signal.aborted)) {
6217
+ return fetchError ? { status: "error", message: fetchError.message } : (() => {
6218
+ throw new DOMException("Aborted", "AbortError");
6219
+ })();
6220
+ }
6221
+ const [event] = await hydrateEvents([result]);
6222
+ return (event == null ? void 0 : event.runId) === runId ? { status: "ok", events: [event] } : { status: "not_found" };
6223
+ }
6224
+ const matched = [];
6225
+ let nextCursor;
6226
+ let pagesFetched = 0;
6227
+ let truncated = false;
6228
+ do {
6229
+ if (signal == null ? void 0 : signal.aborted) {
6230
+ throw new DOMException("Aborted", "AbortError");
6231
+ }
6232
+ const { error: fetchError, result } = await unwrapServerActionResult(
6233
+ fetchEventsByCorrelationId(env, id, {
6234
+ cursor: nextCursor,
6235
+ sortOrder,
6236
+ limit: 100,
6237
+ withData: false
6238
+ })
6239
+ );
6240
+ if (fetchError) {
6241
+ return { status: "error", message: fetchError.message };
6242
+ }
6243
+ if (signal == null ? void 0 : signal.aborted) {
6244
+ throw new DOMException("Aborted", "AbortError");
6245
+ }
6246
+ pagesFetched += 1;
6247
+ const hydrated = await hydrateEvents(result.data);
6248
+ matched.push(...hydrated.filter((event) => event.runId === runId));
6249
+ const hitPageCap = pagesFetched >= MAX_CORRELATION_SEARCH_PAGES;
6250
+ truncated = truncated || hitPageCap && Boolean(result.hasMore && result.cursor);
6251
+ nextCursor = !hitPageCap && result.hasMore && result.cursor ? result.cursor : void 0;
6252
+ } while (nextCursor);
6253
+ return matched.length > 0 ? { status: "ok", events: matched, truncated: truncated || void 0 } : { status: "not_found" };
6254
+ },
6255
+ [env, runId, sortOrder, hydrateEvents]
6256
+ );
6125
6257
  return {
6126
6258
  events,
6127
6259
  loading,
6128
6260
  error,
6129
6261
  hasMore,
6130
6262
  loadingMore,
6131
- loadMore
6263
+ loadMore,
6264
+ searchByExactId
6132
6265
  };
6133
6266
  }
6134
6267
  function LiveStatus({ hasError, errorMessage }) {
@@ -6276,7 +6409,8 @@ function RunDetailView({
6276
6409
  loading: eventsListLoading,
6277
6410
  hasMore: hasMoreEventsTab,
6278
6411
  loadingMore: loadingMoreEventsTab,
6279
- loadMore: loadMoreEventsTab
6412
+ loadMore: loadMoreEventsTab,
6413
+ searchByExactId
6280
6414
  } = useEventsListData(env, runId, {
6281
6415
  sortOrder: eventsSortOrder,
6282
6416
  encryptionKey: encryptionKey ?? void 0,
@@ -6320,7 +6454,6 @@ function RunDetailView({
6320
6454
  return;
6321
6455
  }
6322
6456
  setEncryptionKey(keyResult);
6323
- toast.success("Run data decrypted successfully");
6324
6457
  } finally {
6325
6458
  setIsDecrypting(false);
6326
6459
  }
@@ -6558,7 +6691,8 @@ function RunDetailView({
6558
6691
  onSortOrderChange: setEventsSortOrder,
6559
6692
  onDecrypt: handleDecrypt,
6560
6693
  isDecrypting,
6561
- hasEncryptedData
6694
+ hasEncryptedData,
6695
+ onExactIdSearch: searchByExactId
6562
6696
  }
6563
6697
  ) }) }) }),
6564
6698
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "streams", className: "mt-0 flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, { title: "Failed to load stream data", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-full flex gap-4", children: [
@@ -1,7 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { c as createLucideIcon, aF as cn, d as cn$1, G as cva, aG as composeRefs, E as useComposedRefs, aH as useFloating, aI as offset, aJ as shift, aK as flip, aL as size, aM as arrow, aN as hide, aO as limitShift, aP as autoUpdate, T as Tooltip, a as TooltipTrigger, b as TooltipContent, aQ as cancelRun$1, aR as reenqueueRun$1, aS as wakeUpRun$1, aT as resumeHook$1, aU as recreateRun$1, p as createContextScope$1, n as useComposedRefs$1, v as createSlot, W as formatDuration, B as Button, t as toast, s as useId$1, P as Primitive$1, q as composeEventHandlers$1, x as useControllableState$1, m as useCallbackRef$2, H as Presence$1 } from "./mermaid-3ZIDBTTL-B_qZU5zW.js";
4
+ import { c as createLucideIcon, aG as cn, d as cn$1, G as cva, aH as composeRefs, E as useComposedRefs, aI as useFloating, aJ as offset, aK as shift, aL as limitShift, aM as flip, aN as size, aO as arrow, aP as hide, aQ as autoUpdate, T as Tooltip, a as TooltipTrigger, b as TooltipContent, aR as cancelRun$1, aS as reenqueueRun$1, aT as wakeUpRun$1, aU as resumeHook$1, aV as recreateRun$1, v as createContextScope$1, n as useComposedRefs$1, w as createSlot, W as formatDuration, B as Button, t as toast, p as useId$1, P as Primitive$1, o as composeEventHandlers$1, x as useControllableState$1, m as useCallbackRef$2, H as Presence$1 } from "./mermaid-3ZIDBTTL-Cr7OQX4b.js";
5
5
  import { r as reactExports, j as jsxRuntimeExports, f as reactDomExports, R as ReactExports, H as React, C as ReactDOM, a as requireReact, I as getDefaultExportFromCjs } from "./index-DQa-BExo.js";
6
6
  function parseName(tag, name) {
7
7
  if (typeof name !== "string") {
@@ -16140,8 +16140,8 @@ export {
16140
16140
  Zap as Z,
16141
16141
  useCallbackRef$1 as _,
16142
16142
  Skeleton as a,
16143
- createContext2 as a0,
16144
- useId as a1,
16143
+ useId as a0,
16144
+ createContext2 as a1,
16145
16145
  useFocusGuards as a2,
16146
16146
  LAYOUT as a3,
16147
16147
  wakeUpRun as a4,
@@ -16165,11 +16165,11 @@ export {
16165
16165
  Check as q,
16166
16166
  resumeHook as r,
16167
16167
  useControllableState as s,
16168
- createContextScope as t,
16168
+ composeEventHandlers as t,
16169
16169
  unwrapOrThrow as u,
16170
- composeEventHandlers as v,
16171
- Presence as w,
16172
- useSize as x,
16170
+ Presence as v,
16171
+ useSize as w,
16172
+ createContextScope as x,
16173
16173
  cancelRun as y,
16174
16174
  reenqueueRun as z
16175
16175
  };
@@ -9176,7 +9176,7 @@ const app = express();
9176
9176
  app.all(
9177
9177
  "*",
9178
9178
  createRequestHandler({
9179
- build: () => import("./server-build-Mddyhj54.js").then((n) => n.G)
9179
+ build: () => import("./server-build-DBNmVwSJ.js").then((n) => n.G)
9180
9180
  })
9181
9181
  );
9182
9182
  app.use(
@@ -1,5 +1,5 @@
1
- import { y as R, K as Ks, z as jsxRuntimeExports, A as Qe } from "./server-build-Mddyhj54.js";
2
- import { r as reactExports } from "./app-fdUHF124.js";
1
+ import { y as R, K as Ks, z as jsxRuntimeExports, A as Qe } from "./server-build-DBNmVwSJ.js";
2
+ import { r as reactExports } from "./app-CthB1gsr.js";
3
3
  import "node:stream";
4
4
  import "util";
5
5
  import "crypto";