@workflow/web 5.0.0-beta.26 → 5.0.0-beta.28

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 (28) hide show
  1. package/build/client/assets/{encryption-g14N5vQl.js → encryption-BQTnudEZ.js} +1 -1
  2. package/build/client/assets/{entry.client-DOJDY_4b.js → entry.client-DQZ2hM2V.js} +24 -24
  3. package/build/client/assets/{highlighted-body-B3W2YXNL-QrddlyZu.js → highlighted-body-B3W2YXNL-CQ-a-eYE.js} +1 -1
  4. package/build/client/assets/{home-BNApVOct.js → home-DuZRFOMe.js} +1698 -234
  5. package/build/client/assets/{index-B6-SzLmT.js → index-ConSkUmc.js} +0 -2
  6. package/build/client/assets/{index-C7C6cDW5.js → index-HqNj_XIX.js} +10 -10
  7. package/build/client/assets/{manifest-379f050f.js → manifest-bb838d97.js} +1 -1
  8. package/build/client/assets/{mermaid-3ZIDBTTL-Cg-Mp5Kj.js → mermaid-3ZIDBTTL-QcES6x1o.js} +767 -279
  9. package/build/client/assets/root-BT69a3LD.css +1 -0
  10. package/build/client/assets/{root-BsPxYsbK.js → root-BiHTsCtP.js} +1 -1
  11. package/build/client/assets/{run-detail-sr7StYc6.js → run-detail-DSpZ5dnN.js} +925 -759
  12. package/build/client/assets/server-build-BkKXPNcO.css +1 -0
  13. package/build/client/assets/{workflow-graph-viewer-CcCwLmnF.js → workflow-graph-viewer-CyKfZJOQ.js} +227 -220
  14. package/build/client/assets/{zstd-browser-decoder-OOeWOMJw.js → zstd-browser-decoder-BigjGoI1.js} +2 -2
  15. package/build/server/assets/{app-DQ35jFT1.js → app-Cl6-bhGd.js} +43 -43
  16. package/build/server/assets/{highlighted-body-B3W2YXNL-DUlvgLoF.js → highlighted-body-B3W2YXNL-Daljn6fi.js} +4 -4
  17. package/build/server/assets/index-B_N7SdQh.js +115 -0
  18. package/build/server/assets/{index-BafExO0s.js → index-BfLBLRRi.js} +10 -10
  19. package/build/server/assets/{mermaid-3ZIDBTTL-BdnRYE9a.js → mermaid-3ZIDBTTL-xnUhfFrD.js} +4 -4
  20. package/build/server/assets/{server-build-0CazaFkH.js → server-build-D5Nuwxaw.js} +40483 -37602
  21. package/build/server/assets/{token-DK_R23fr.js → token-DDgfwjzz.js} +2 -2
  22. package/build/server/assets/{token-util-CaJAmsYa.js → token-util-CthtfGuG.js} +2 -2
  23. package/build/server/assets/{zstd-browser-decoder-pCjqxVHM.js → zstd-browser-decoder-zp5ZpR7T.js} +5 -5
  24. package/build/server/index.js +1 -1
  25. package/package.json +11 -9
  26. package/build/client/assets/root-F_dqJDC7.css +0 -1
  27. package/build/client/assets/server-build-DVBDkRDS.css +0 -1
  28. package/build/server/assets/index-BgRt1-Z6.js +0 -100
@@ -1,8 +1,8 @@
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, 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
- import { decrypt, importKey } from "./encryption-g14N5vQl.js";
5
- import "./index-B6-SzLmT.js";
2
+ import { C as Check, a as Copy, d as CircleAlert, U as parseStepName, G as parseWorkflowName, V as ErrorCard, Y as format, Z as Zap, S as Send, R as ResolveHookModal, t as ChevronUp, X, Q as ErrorBoundary, _ as Circle, u as unwrapOrThrow, W as WorkflowWebAPIError, K as unwrapServerActionResult, $ as useEscapeKeydown, w as composeEventHandlers, a0 as useCallbackRef, a1 as useLayoutEffect2, v as useControllableState, a2 as useId, a3 as createContext2, x as Presence, z as createContextScope, p as hideOthers, q as ReactRemoveScroll, a4 as useFocusGuards, a5 as LAYOUT, a6 as wakeUpRun, n as resumeHook, A as Alert, e as AlertTitle, g as getErrorTitle, h as AlertDescription, i as getErrorMessage, b as Skeleton$1, a7 as RunActionsButtons, H as StatusBadge, j as CopyableText, c as RelativeTime, T as Tabs, M as TabsList, N as TabsTrigger, O as TabsContent, B as cancelRun, a8 as recreateRun } from "./workflow-graph-viewer-CyKfZJOQ.js";
3
+ import { c as createLucideIcon, W as cn, X as DataInspector, Y as DecryptClickContext, Z as Button, $ as Spinner, a0 as Lock, a1 as CollapsibleRoot, a2 as CollapsibleTrigger, a3 as CollapsibleContent, M as cva, a4 as RESERVED_ATTRIBUTE_KEY_PREFIX, a5 as ContextCardProvider, h as useToast, a6 as Skeleton, a7 as Yr, a8 as isEncryptedMarker, C as ChevronRight, a9 as TimestampTooltip, aa as formatDuration, ab as _r, ac as RunClickContext, ad as StreamClickContext, ae as Collapsible, af as isExpiredMarker, ag as isDoStreamStep, ah as extractConversation, ai as hasEncryptedFields, aj as getEventDataRefFields, ak as useSidebarDataOptional, al as clsx, am as useActiveSpan, an as useSidebarData, ao as Tooltip, ap as TooltipTrigger, aq as IconButton, ar as TooltipContent, H as ChevronDown, as as useRowWindow, at as isSpanDimmedBySearch, au as ROW_HEIGHT_PX, av as getSpanDurationMs, aw as isSpanErrored, ax as formatDurationPrecise, ay as TooltipProvider, az as ActiveSpanProvider, aA as useReducedMotion, aB as searchSpans, aC as computeRootBounds, aD as computeTimeMarkers, aE as clampViewportToRoot, aF as getHighResInMs, aG as scrollRowIntoView, aH as TIMELINE_PADDING_PX, aI as Minimap, aJ as Timeline, aK as TimelineHeader, aL as wheelZoomScaleFactor, aM as wheelDeltaToPixels, aN as SidebarDataProvider, aO as fetchHook, l as fetchEvents, aP as hydrateResourceIOAsync, J as fetchRun, aQ as fetchStep, aR as hydrateResourceIO, aS as fetchStreams, aT as Slot, I as useComposedRefs, aU as Slottable, e as cn$1, aV as buttonVariants, aW as fetchEvent, aX as fetchEventsByCorrelationId, aY as isEncryptedData, aZ as hydrateData, a_ as getWebRevivers, T as Tooltip$1, a as TooltipTrigger$1, b as TooltipContent$1, a$ as LIVE_UPDATE_INTERVAL_MS$1, u as useServerConfig, b0 as getEncryptionKeyForRun, t as toast, L as LoaderCircle, b1 as StreamViewer } from "./mermaid-3ZIDBTTL-QcES6x1o.js";
4
+ import { decrypt, importKey } from "./encryption-BQTnudEZ.js";
5
+ import "./index-ConSkUmc.js";
6
6
  /**
7
7
  * @license lucide-react v0.575.0 - ISC
8
8
  *
@@ -125,251 +125,561 @@ function CopyButton({ copyText, ariaLabel, className }) {
125
125
  });
126
126
  }, children: jsxRuntimeExports.jsxs("div", { className: "relative w-3 h-3", children: [jsxRuntimeExports.jsx("div", { className: cn("absolute inset-0 flex items-center justify-center transition-all duration-150 ease-out", copied ? "scale-100 opacity-100" : "scale-0 opacity-0"), children: jsxRuntimeExports.jsx(Check, { className: "w-3 h-3" }) }), jsxRuntimeExports.jsx("div", { className: cn("absolute inset-0 flex items-center justify-center transition-all duration-150 ease-out", copied ? "scale-0 opacity-0" : "scale-100 opacity-100"), children: jsxRuntimeExports.jsx(Copy, { className: "w-3 h-3" }) })] }) });
127
127
  }
128
- const encryptedPlaceholderPreview = `{
129
- "input": "[encrypted]",
130
- "result": "[encrypted]"
131
- }`;
132
- function EncryptedDataBlock() {
133
- const ctx = reactExports.useContext(DecryptClickContext);
134
- return jsxRuntimeExports.jsxs("div", { className: "relative min-h-20 overflow-hidden rounded-md border border-gray-alpha-400 bg-background-100", children: [jsxRuntimeExports.jsx("pre", { "aria-hidden": "true", className: "pointer-events-none m-0 select-none p-3 font-mono text-label-12 text-gray-900 blur-[4px]", children: encryptedPlaceholderPreview }), jsxRuntimeExports.jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: ctx ? jsxRuntimeExports.jsxs(Button, { onClick: ctx.onDecrypt, disabled: ctx.isDecrypting, size: "xs", children: [ctx.isDecrypting ? jsxRuntimeExports.jsx(Spinner, { size: 10 }) : jsxRuntimeExports.jsx(Lock, { className: "h-3 w-3" }), jsxRuntimeExports.jsx("span", { children: "Decrypt" })] }) : jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1 rounded border border-gray-alpha-400 bg-gray-100 px-1.5 py-0.5 text-button-12 font-medium text-gray-700", children: [jsxRuntimeExports.jsx(Lock, { className: "h-3 w-3" }), "Encrypted"] }) })] });
135
- }
136
- const serializeForClipboard = (value) => {
137
- if (typeof value === "string")
138
- return value;
139
- if (typeof value === "number" || typeof value === "boolean" || value === null) {
140
- return String(value);
141
- }
142
- try {
143
- return JSON.stringify(value, null, 2);
144
- } catch {
145
- return String(value);
128
+ const ELLIPSIS = "…";
129
+ const MIN_START = 3;
130
+ const MIN_END = 3;
131
+ const MIN_KEPT = MIN_START + MIN_END;
132
+ const graphemeSegmenter = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
133
+ function toGraphemes(text) {
134
+ if (graphemeSegmenter) {
135
+ return [...graphemeSegmenter.segment(text)].map((s) => s.segment);
146
136
  }
147
- };
148
- function CopyableDataBlock({ data }) {
149
- return jsxRuntimeExports.jsxs("div", { className: "relative overflow-x-auto rounded-md border border-gray-alpha-400 p-3", children: [jsxRuntimeExports.jsx(CopyButton, { copyText: serializeForClipboard(data), ariaLabel: "Copy data", className: "absolute right-2 top-2 z-10 flex h-6 w-6 items-center justify-center rounded-md border border-gray-alpha-400 !bg-background-100 p-0 text-gray-900 transition-transform transition-colors duration-100 hover:bg-gray-200 active:scale-95 active:bg-gray-300" }), jsxRuntimeExports.jsx(DataInspector, { data })] });
137
+ return Array.from(text);
150
138
  }
151
- function DetailCard({ summary, children, onToggle, disabled = false, defaultOpen = false, variant = "section", trailing, summaryClassName, contentClassName }) {
152
- const [open, setOpen] = reactExports.useState(defaultOpen);
153
- const handleToggle = (e) => {
154
- if (e.target !== e.currentTarget)
155
- return;
156
- const next = e.currentTarget.open;
157
- setOpen(next);
158
- onToggle == null ? void 0 : onToggle(next);
139
+ function buildCandidate(graphemes, kept) {
140
+ if (kept <= 0) {
141
+ return {
142
+ prefixText: "",
143
+ prefixGraphemeCount: 0,
144
+ suffixText: "",
145
+ suffixGraphemeCount: 0,
146
+ text: ELLIPSIS,
147
+ truncated: true
148
+ };
149
+ }
150
+ const suffixGraphemeCount = kept >= MIN_KEPT ? Math.max(MIN_END, Math.floor(kept / 2)) : Math.floor(kept / 2);
151
+ const prefixGraphemeCount = kept - suffixGraphemeCount;
152
+ const prefixText = graphemes.slice(0, prefixGraphemeCount).join("");
153
+ const suffixText = suffixGraphemeCount > 0 ? graphemes.slice(-suffixGraphemeCount).join("") : "";
154
+ return {
155
+ prefixText,
156
+ prefixGraphemeCount,
157
+ suffixText,
158
+ suffixGraphemeCount,
159
+ text: prefixText + ELLIPSIS + suffixText,
160
+ truncated: true
159
161
  };
160
- if (variant === "card") {
161
- if (disabled) {
162
- return jsxRuntimeExports.jsx("div", { className: cn("list-none px-3 py-4 bg-background-200 [&::-webkit-details-marker]:hidden", summaryClassName), style: { cursor: "not-allowed", opacity: 0.8 }, children: summary });
163
- }
164
- return jsxRuntimeExports.jsxs("details", { className: "group/card last:border-b border-gray-alpha-400", open, onToggle: handleToggle, children: [jsxRuntimeExports.jsx("summary", { className: cn("list-none cursor-pointer px-3 py-4 border-t border-gray-alpha-400 bg-background-200 hover:bg-gray-100 [&::-webkit-details-marker]:hidden", summaryClassName), children: jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5", children: [jsxRuntimeExports.jsx(ChevronRight, { size: 14, className: cn("shrink-0 text-gray-700 group-hover/card:text-gray-1000", open && "rotate-90") }), summary] }) }), jsxRuntimeExports.jsx("div", { className: contentClassName, children })] });
162
+ }
163
+ function middleTruncate(graphemes, availableWidth, measure, fullWidth) {
164
+ const fullText = graphemes.join("");
165
+ const resolvedFullWidth = fullWidth ?? measure(fullText);
166
+ if (availableWidth <= 0 || graphemes.length === 0) {
167
+ return {
168
+ prefixText: fullText,
169
+ prefixGraphemeCount: graphemes.length,
170
+ suffixText: "",
171
+ suffixGraphemeCount: 0,
172
+ text: fullText,
173
+ truncated: false
174
+ };
165
175
  }
166
- const rowClasses = "flex h-9 items-center gap-2 px-2 -mx-2 text-heading-14 font-medium my-2";
167
- if (trailing) {
168
- return jsxRuntimeExports.jsx("section", { className: "-mx-4 border-t px-4 border-gray-alpha-400", children: jsxRuntimeExports.jsxs("div", { className: cn(rowClasses, summaryClassName), children: [jsxRuntimeExports.jsx("div", { className: "isolate relative shrink-0 w-3.5 h-3.5 text-gray-700", children: jsxRuntimeExports.jsx(ChevronRight, { size: 14, className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" }) }), jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1", children: summary }), jsxRuntimeExports.jsx("div", { className: "shrink-0 pr-1", children: trailing })] }) });
176
+ if (resolvedFullWidth <= availableWidth) {
177
+ return {
178
+ prefixText: fullText,
179
+ prefixGraphemeCount: graphemes.length,
180
+ suffixText: "",
181
+ suffixGraphemeCount: 0,
182
+ text: fullText,
183
+ truncated: false
184
+ };
169
185
  }
170
- if (disabled) {
171
- return jsxRuntimeExports.jsx("section", { className: "-mx-4 border-t px-4 border-gray-alpha-400", children: jsxRuntimeExports.jsx("div", { className: cn(rowClasses, summaryClassName), style: { color: "var(--ds-gray-700)", cursor: "not-allowed" }, children: jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1", children: summary }) }) });
186
+ let lo = 0;
187
+ let hi = graphemes.length - 1;
188
+ let best = -1;
189
+ while (lo <= hi) {
190
+ const mid = lo + hi >>> 1;
191
+ const candidate = buildCandidate(graphemes, mid);
192
+ if (measure(candidate.text) <= availableWidth) {
193
+ best = mid;
194
+ lo = mid + 1;
195
+ } else {
196
+ hi = mid - 1;
197
+ }
172
198
  }
173
- return jsxRuntimeExports.jsx("section", { className: "-mx-4 border-t px-4 border-gray-alpha-400", children: jsxRuntimeExports.jsxs("details", { className: "group", open, onToggle: handleToggle, children: [jsxRuntimeExports.jsxs("summary", { className: cn("group/trigger list-none cursor-pointer rounded hover:bg-gray-alpha-100 [&::-webkit-details-marker]:hidden", rowClasses, summaryClassName), children: [jsxRuntimeExports.jsxs("div", { className: "isolate relative shrink-0 text-gray-700 group-hover/trigger:text-gray-1000 w-3.5 h-3.5", children: [jsxRuntimeExports.jsx(ChevronRight, { size: 14, className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-100 group-open:opacity-0" }), jsxRuntimeExports.jsx(ChevronDown, { size: 14, className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-0 group-open:opacity-100" })] }), jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1", children: summary })] }), jsxRuntimeExports.jsx("div", { className: cn("mb-3", contentClassName), children })] }) });
174
- }
175
- const isReservedAttributeKey = (key) => key.startsWith(RESERVED_ATTRIBUTE_KEY_PREFIX);
176
- function ReservedBadge() {
177
- return jsxRuntimeExports.jsx("span", { className: "shrink-0 rounded border px-1 py-px text-[10px] font-medium leading-3", style: {
178
- borderColor: "var(--ds-gray-alpha-400)",
179
- backgroundColor: "var(--ds-gray-100)",
180
- color: "var(--ds-gray-700)"
181
- }, title: `Keys prefixed with "${RESERVED_ATTRIBUTE_KEY_PREFIX}" are reserved for framework and library code`, children: "Reserved" });
182
- }
183
- function AttributeRow({ attributeKey, value, removed = false }) {
184
- const reserved = isReservedAttributeKey(attributeKey);
185
- return jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-3 py-0.5", children: [jsxRuntimeExports.jsxs("span", { className: "flex min-w-0 items-center gap-1.5 text-label-13 text-gray-900", style: reserved ? { color: "var(--ds-gray-700)" } : void 0, children: [jsxRuntimeExports.jsx("span", { className: "truncate", children: attributeKey }), reserved && jsxRuntimeExports.jsx(ReservedBadge, {})] }), removed ? jsxRuntimeExports.jsx("span", { className: "shrink-0 text-copy-13 italic text-gray-700", children: "removed" }) : jsxRuntimeExports.jsx("span", { className: "max-w-[60%] truncate text-copy-13 text-gray-1000", title: value, children: value })] });
186
- }
187
- function sortAttributeKeys(keys) {
188
- return [...keys].sort((a, b) => {
189
- const aReserved = isReservedAttributeKey(a);
190
- const bReserved = isReservedAttributeKey(b);
191
- if (aReserved !== bReserved)
192
- return aReserved ? 1 : -1;
193
- return a.localeCompare(b);
194
- });
199
+ if (best === -1) {
200
+ return {
201
+ prefixText: "",
202
+ prefixGraphemeCount: 0,
203
+ suffixText: "",
204
+ suffixGraphemeCount: 0,
205
+ text: "",
206
+ truncated: true
207
+ };
208
+ }
209
+ return buildCandidate(graphemes, best);
195
210
  }
196
- function RunAttributesCard({ attributes }) {
197
- const keys = sortAttributeKeys(Object.keys(attributes));
198
- if (keys.length === 0)
211
+ function getMiddleTruncateCopyText({ prefixText, selectionEnd, selectionStart, suffixText, value }) {
212
+ const visibleText = prefixText + ELLIPSIS + suffixText;
213
+ if (selectionStart < 0 || selectionEnd > visibleText.length || selectionStart >= selectionEnd) {
199
214
  return null;
200
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Attributes", defaultOpen: true, contentClassName: "mb-4", children: jsxRuntimeExports.jsx("div", { className: "flex flex-col", children: keys.map((key) => jsxRuntimeExports.jsx(AttributeRow, { attributeKey: key, value: attributes[key] }, key)) }) });
201
- }
202
- function isAttrSetEventData(data) {
203
- if (data === null || typeof data !== "object")
204
- return false;
205
- const record = data;
206
- return Array.isArray(record.changes) && record.changes.every((c) => c !== null && typeof c === "object" && typeof c.key === "string");
207
- }
208
- function describeWriter(writer) {
209
- if (!writer)
215
+ }
216
+ if (selectionStart === 0 && selectionEnd === visibleText.length) {
217
+ return value;
218
+ }
219
+ const ellipsisStart = prefixText.length;
220
+ const ellipsisEnd = ellipsisStart + ELLIPSIS.length;
221
+ if (selectionStart > ellipsisStart || selectionEnd < ellipsisEnd) {
210
222
  return null;
211
- if (writer.type === "workflow")
212
- return "Set by workflow";
213
- if (writer.type === "step") {
214
- return `Set by step ${writer.stepId} (attempt ${writer.attempt})`;
215
223
  }
216
- return null;
224
+ const originalGraphemes = toGraphemes(value);
225
+ const selectedPrefixGraphemeCount = toGraphemes(visibleText.slice(0, selectionStart)).length;
226
+ const selectedSuffixGraphemeCount = toGraphemes(visibleText.slice(ellipsisEnd, selectionEnd)).length;
227
+ const suffixStart = originalGraphemes.length - toGraphemes(suffixText).length;
228
+ return originalGraphemes.slice(selectedPrefixGraphemeCount, suffixStart + selectedSuffixGraphemeCount).join("");
217
229
  }
218
- function AttrSetEventBlock({ data }) {
219
- if (!isAttrSetEventData(data)) {
220
- return jsxRuntimeExports.jsx(CopyableDataBlock, { data });
230
+ function getMiddleTruncateCopyTextFromSelectionText({ prefixText, selectionText, suffixText, value }) {
231
+ const visibleText = prefixText + ELLIPSIS + suffixText;
232
+ const trimmedSelectionText = selectionText.trim();
233
+ if (!trimmedSelectionText) {
234
+ return null;
221
235
  }
222
- const writerLabel = describeWriter(data.writer);
223
- return jsxRuntimeExports.jsxs("div", { className: "flex flex-col px-3 py-1", children: [jsxRuntimeExports.jsx("div", { className: "flex flex-col", children: data.changes.map((change, index) => jsxRuntimeExports.jsx(AttributeRow, { attributeKey: change.key, removed: change.value === null, value: change.value ?? void 0 }, `${change.key}:${index}`)) }), writerLabel && jsxRuntimeExports.jsx("div", { className: "border-t py-1.5 text-label-12", style: {
224
- borderColor: "var(--ds-gray-alpha-400)",
225
- color: "var(--ds-gray-700)"
226
- }, children: writerLabel })] });
227
- }
228
- 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}`;
229
- function DecryptButton({ decrypted = false, loading = false, onClick }) {
230
- 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"] })] });
231
- }
232
- function isStructuredError(value) {
233
- return value != null && typeof value === "object" && (typeof value.message === "string" || typeof value.stack === "string");
234
- }
235
- function deriveTitle(message) {
236
- const firstLine = message.split("\n").find((line) => line.trim().length > 0) ?? message;
237
- return firstLine.trim();
238
- }
239
- function ErrorStackBlock({ value }) {
240
- const stack = typeof value.stack === "string" ? value.stack : void 0;
241
- const message = typeof value.message === "string" ? value.message : void 0;
242
- const body = stack ?? message ?? "";
243
- const title = message ? deriveTitle(message) : deriveTitle(body);
244
- const copyText = message && stack && !stack.includes(message) ? `${message}
245
-
246
- ${stack}` : body;
247
- return jsxRuntimeExports.jsxs("div", { className: "relative overflow-hidden rounded-md border", style: {
248
- borderColor: "var(--ds-red-400)",
249
- background: "var(--ds-red-100)"
250
- }, children: [jsxRuntimeExports.jsx(CopyButton, { copyText, ariaLabel: "Copy error", className: "absolute right-2 top-2 flex h-6 w-6 items-center justify-center rounded-md border border-red-400 bg-red-100 p-0 text-red-900 transition-transform transition-colors duration-100 hover:bg-red-200 active:scale-95" }), title && jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 px-3 py-2.5 pr-10", style: {
251
- color: "var(--ds-red-900)",
252
- borderBottom: "1px solid var(--ds-red-400)"
253
- }, children: [jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4 shrink-0" }), jsxRuntimeExports.jsx("p", {
254
- className: "text-xs font-semibold m-0 truncate",
255
- // The full message or stack is in the body below; the header just
256
- // shows the first line, single-line, with overflow
257
- // ellipsised so a long title doesn't push the copy button or
258
- // wrap into the framed hint/docs lines.
259
- title: message,
260
- children: title
261
- })] }), body && jsxRuntimeExports.jsx("pre", { className: "px-3 py-2.5 text-xs font-mono whitespace-pre-wrap break-words overflow-auto m-0", style: {
262
- color: "var(--ds-red-900)",
263
- background: "var(--ds-red-200)"
264
- }, children: body })] });
236
+ const leading = selectionText.slice(0, selectionText.length - selectionText.trimStart().length);
237
+ const trailing = selectionText.slice(selectionText.trimEnd().length);
238
+ if (trimmedSelectionText === visibleText) {
239
+ return leading + value + trailing;
240
+ }
241
+ if (!trimmedSelectionText.includes(ELLIPSIS)) {
242
+ return null;
243
+ }
244
+ const selectionStart = visibleText.indexOf(trimmedSelectionText);
245
+ if (selectionStart === -1) {
246
+ return null;
247
+ }
248
+ const selectionEnd = selectionStart + trimmedSelectionText.length;
249
+ const mappedText = getMiddleTruncateCopyText({
250
+ prefixText,
251
+ selectionEnd,
252
+ selectionStart,
253
+ suffixText,
254
+ value
255
+ });
256
+ return mappedText === null ? null : leading + mappedText + trailing;
265
257
  }
266
- const STYLES$1 = `.wf-load-more{appearance:none;-webkit-appearance:none;border:none;display:inline-flex;align-items:center;justify-content:center;height:32px;padding:0 12px;border-radius:6px;font-size:13px;font-weight:500;line-height:20px;color:var(--ds-gray-1000);background:var(--ds-background-100);box-shadow:0 0 0 1px var(--ds-gray-400);cursor:pointer;white-space:nowrap;gap:6px;transition:background 150ms}.wf-load-more:hover{background:var(--ds-gray-alpha-200)}.wf-load-more:disabled{opacity:.6;cursor:default}.wf-load-more:disabled:hover{background:var(--ds-background-100)}`;
267
- function LoadMoreButton({ loading = false, onClick, label = "Load more", loadingLabel = "Loading..." }) {
268
- return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("style", { dangerouslySetInnerHTML: { __html: STYLES$1 } }), jsxRuntimeExports.jsxs("button", { type: "button", onClick, disabled: loading, className: "wf-load-more", children: [loading && jsxRuntimeExports.jsx(Spinner, { size: 14 }), loading ? loadingLabel : label] })] });
258
+ const useIsomorphicLayoutEffect = typeof window === "undefined" ? reactExports.useEffect : reactExports.useLayoutEffect;
259
+ function createFullState(value, graphemes) {
260
+ return {
261
+ displayText: value,
262
+ isTruncated: false,
263
+ prefixGraphemeCount: graphemes.length,
264
+ prefixText: value,
265
+ suffixGraphemeCount: 0,
266
+ suffixText: ""
267
+ };
269
268
  }
270
- const STYLES = `.wf-menu-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;color:var(--ds-gray-1000);background:var(--ds-background-100);box-shadow:0 0 0 1px var(--ds-gray-400);cursor:pointer;white-space:nowrap;transition:background 150ms}.wf-menu-btn:hover{background:var(--ds-gray-alpha-200)}.wf-menu-item{appearance:none;-webkit-appearance:none;border:none;display:flex;align-items:center;width:100%;height:40px;padding:0 8px;border-radius:6px;font-size:14px;color:var(--ds-gray-1000);background:transparent;cursor:pointer;transition:background 150ms}.wf-menu-item:hover{background:var(--ds-gray-alpha-100)}`;
271
- function MenuDropdown({ options, value, onChange }) {
272
- var _a, _b;
273
- const [open, setOpen] = reactExports.useState(false);
269
+ function useMiddleTruncate(value) {
270
+ const graphemes = reactExports.useMemo(() => toGraphemes(value), [value]);
271
+ const fullState = reactExports.useMemo(() => createFullState(value, graphemes), [graphemes, value]);
274
272
  const ref = reactExports.useRef(null);
275
- const label = ((_a = options.find((o) => o.value === value)) == null ? void 0 : _a.label) ?? ((_b = options[0]) == null ? void 0 : _b.label) ?? "";
276
- reactExports.useEffect(() => {
277
- if (!open)
278
- return;
279
- function handleClickOutside(e) {
280
- if (ref.current && !ref.current.contains(e.target)) {
281
- setOpen(false);
273
+ const measureRef = reactExports.useRef(null);
274
+ const [state, setState] = reactExports.useState(() => fullState);
275
+ const rafRef = reactExports.useRef(0);
276
+ const updateState = reactExports.useCallback((nextState) => {
277
+ setState((currentState) => {
278
+ if (currentState.displayText === nextState.displayText && currentState.isTruncated === nextState.isTruncated && currentState.prefixText === nextState.prefixText && currentState.prefixGraphemeCount === nextState.prefixGraphemeCount && currentState.suffixText === nextState.suffixText && currentState.suffixGraphemeCount === nextState.suffixGraphemeCount) {
279
+ return currentState;
282
280
  }
283
- }
284
- document.addEventListener("mousedown", handleClickOutside);
285
- return () => document.removeEventListener("mousedown", handleClickOutside);
286
- }, [open]);
287
- return jsxRuntimeExports.jsxs("div", { ref, style: { position: "relative", flexShrink: 0 }, children: [jsxRuntimeExports.jsx("style", { dangerouslySetInnerHTML: { __html: STYLES } }), jsxRuntimeExports.jsxs("button", { type: "button", className: "wf-menu-btn", onClick: () => setOpen(!open), children: [jsxRuntimeExports.jsx("span", { children: label }), jsxRuntimeExports.jsx("svg", { width: 16, height: 16, viewBox: "0 0 16 16", fill: "none", style: {
288
- marginLeft: 16,
289
- marginRight: -4,
290
- color: "var(--ds-gray-900)"
291
- }, children: jsxRuntimeExports.jsx("path", { d: "M4.5 6L8 9.5L11.5 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })] }), open && jsxRuntimeExports.jsx("div", { style: {
292
- position: "absolute",
293
- right: 0,
294
- top: "100%",
295
- marginTop: 4,
296
- minWidth: 140,
297
- padding: 4,
298
- borderRadius: 12,
299
- background: "var(--ds-background-100)",
300
- boxShadow: "var(--ds-shadow-menu, var(--ds-shadow-medium))",
301
- zIndex: 2001
302
- }, role: "menu", children: options.map((option) => jsxRuntimeExports.jsx("button", { type: "button", role: "menuitem", className: "wf-menu-item", style: {
303
- fontWeight: option.value === value ? 500 : 400
304
- }, onClick: () => {
305
- onChange(option.value);
306
- setOpen(false);
307
- }, children: option.label }, option.value)) })] });
308
- }
309
- const ERROR_EVENT_TYPES$1 = /* @__PURE__ */ new Set([
310
- "step_failed",
311
- "step_retrying",
312
- "run_failed",
313
- "workflow_failed"
314
- ]);
315
- const BUTTON_RESET_STYLE = {
316
- appearance: "none",
317
- WebkitAppearance: "none",
318
- border: "none",
319
- background: "transparent"
320
- };
321
- const DOT_PULSE_ANIMATION = "workflow-dot-pulse 1.25s cubic-bezier(0, 0, 0.2, 1) infinite";
322
- function formatEventTime(date) {
323
- return date.toLocaleTimeString("en-US", {
324
- hour: "2-digit",
325
- minute: "2-digit",
326
- second: "2-digit",
327
- hour12: false
328
- }) + "." + date.getMilliseconds().toString().padStart(3, "0");
281
+ return nextState;
282
+ });
283
+ }, []);
284
+ const recalculate = reactExports.useCallback(() => {
285
+ const el = ref.current;
286
+ const measureEl = measureRef.current;
287
+ if (!el || !measureEl)
288
+ return;
289
+ const available = el.clientWidth;
290
+ if (available <= 0) {
291
+ updateState(fullState);
292
+ return;
293
+ }
294
+ const measure = (text) => {
295
+ measureEl.textContent = text;
296
+ return measureEl.scrollWidth;
297
+ };
298
+ const fullWidth = measure(value);
299
+ if (fullWidth <= available) {
300
+ updateState(fullState);
301
+ return;
302
+ }
303
+ const result = middleTruncate(graphemes, available, measure, fullWidth);
304
+ updateState({
305
+ displayText: result.text,
306
+ isTruncated: result.truncated,
307
+ prefixGraphemeCount: result.prefixGraphemeCount,
308
+ prefixText: result.prefixText,
309
+ suffixGraphemeCount: result.suffixGraphemeCount,
310
+ suffixText: result.suffixText
311
+ });
312
+ }, [fullState, graphemes, updateState, value]);
313
+ useIsomorphicLayoutEffect(() => {
314
+ recalculate();
315
+ }, [recalculate]);
316
+ reactExports.useEffect(() => {
317
+ var _a;
318
+ const el = ref.current;
319
+ if (!el)
320
+ return;
321
+ const debouncedRecalc = () => {
322
+ cancelAnimationFrame(rafRef.current);
323
+ rafRef.current = requestAnimationFrame(recalculate);
324
+ };
325
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(debouncedRecalc) : null;
326
+ ro == null ? void 0 : ro.observe(el);
327
+ window.addEventListener("resize", debouncedRecalc);
328
+ const onFontsLoaded = () => {
329
+ debouncedRecalc();
330
+ };
331
+ const fontSet = "fonts" in document ? document.fonts : null;
332
+ (_a = fontSet == null ? void 0 : fontSet.addEventListener) == null ? void 0 : _a.call(fontSet, "loadingdone", onFontsLoaded);
333
+ return () => {
334
+ var _a2;
335
+ ro == null ? void 0 : ro.disconnect();
336
+ window.removeEventListener("resize", debouncedRecalc);
337
+ cancelAnimationFrame(rafRef.current);
338
+ (_a2 = fontSet == null ? void 0 : fontSet.removeEventListener) == null ? void 0 : _a2.call(fontSet, "loadingdone", onFontsLoaded);
339
+ };
340
+ }, [recalculate]);
341
+ return {
342
+ ref,
343
+ measureRef,
344
+ displayText: state.displayText,
345
+ isTruncated: state.isTruncated,
346
+ prefixGraphemeCount: state.prefixGraphemeCount,
347
+ prefixText: state.prefixText,
348
+ suffixGraphemeCount: state.suffixGraphemeCount,
349
+ suffixText: state.suffixText
350
+ };
329
351
  }
330
- function parseEventDate(value) {
331
- if (value == null)
352
+ function getRangeOffsets(container, range) {
353
+ if (!container.contains(range.startContainer) || !container.contains(range.endContainer)) {
332
354
  return null;
333
- const date = value instanceof Date ? value : new Date(String(value));
334
- return Number.isNaN(date.getTime()) ? null : date;
355
+ }
356
+ const startRange = document.createRange();
357
+ startRange.selectNodeContents(container);
358
+ startRange.setEnd(range.startContainer, range.startOffset);
359
+ const endRange = document.createRange();
360
+ endRange.selectNodeContents(container);
361
+ endRange.setEnd(range.endContainer, range.endOffset);
362
+ return {
363
+ end: endRange.toString().length,
364
+ start: startRange.toString().length
365
+ };
335
366
  }
336
- function getEffectiveEventDate$1(event) {
337
- return parseEventDate(event.occurredAt) ?? new Date(event.createdAt);
367
+ function MiddleTruncate({ value, className, onCopy: onCopyProp, ...props }) {
368
+ const { ref, measureRef, displayText, isTruncated, prefixText, suffixText } = useMiddleTruncate(value);
369
+ const visibleRef = reactExports.useRef(null);
370
+ const handleCopy = reactExports.useCallback((e) => {
371
+ onCopyProp == null ? void 0 : onCopyProp(e);
372
+ if (e.defaultPrevented || !isTruncated)
373
+ return;
374
+ const selection = window.getSelection();
375
+ if (!selection || selection.rangeCount === 0)
376
+ return;
377
+ const selectionText = selection.toString();
378
+ if (!selectionText)
379
+ return;
380
+ const range = selection.getRangeAt(0);
381
+ const visibleEl = visibleRef.current;
382
+ let copyText = null;
383
+ if (e.currentTarget.contains(range.startContainer) && e.currentTarget.contains(range.endContainer) && visibleEl) {
384
+ const offsets = getRangeOffsets(visibleEl, range);
385
+ if (offsets) {
386
+ copyText = getMiddleTruncateCopyText({
387
+ prefixText,
388
+ selectionEnd: offsets.end,
389
+ selectionStart: offsets.start,
390
+ suffixText,
391
+ value
392
+ });
393
+ }
394
+ }
395
+ copyText ?? (copyText = getMiddleTruncateCopyTextFromSelectionText({
396
+ prefixText,
397
+ selectionText,
398
+ suffixText,
399
+ value
400
+ }));
401
+ if (copyText === null)
402
+ return;
403
+ e.preventDefault();
404
+ e.clipboardData.setData("text/plain", copyText);
405
+ }, [onCopyProp, isTruncated, prefixText, suffixText, value]);
406
+ return jsxRuntimeExports.jsxs("span", { title: isTruncated ? value : void 0, ...props, ref, className: cn("relative inline-grid min-w-0 max-w-full overflow-hidden whitespace-nowrap", className), onCopy: handleCopy, children: [isTruncated && jsxRuntimeExports.jsx("span", { className: "sr-only select-none", children: value }), jsxRuntimeExports.jsx("span", { "aria-hidden": "true", className: "pointer-events-none col-start-1 row-start-1 invisible select-none whitespace-nowrap", children: value }), jsxRuntimeExports.jsx("span", { "aria-hidden": isTruncated || void 0, className: "col-start-1 row-start-1 min-w-0 overflow-hidden", ref: visibleRef, children: isTruncated ? jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("span", { children: prefixText }), jsxRuntimeExports.jsx("span", { children: ELLIPSIS }), jsxRuntimeExports.jsx("span", { children: suffixText })] }) : displayText }), jsxRuntimeExports.jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute left-0 top-0 inline-block invisible select-none whitespace-nowrap", ref: measureRef })] });
338
407
  }
339
- function getEffectiveEventTime(event) {
340
- return getEffectiveEventDate$1(event).getTime();
408
+ const encryptedPlaceholderPreview = `{
409
+ "input": "[encrypted]",
410
+ "result": "[encrypted]"
411
+ }`;
412
+ function EncryptedDataBlock() {
413
+ const ctx = reactExports.useContext(DecryptClickContext);
414
+ return jsxRuntimeExports.jsxs("div", { className: "relative min-h-20 overflow-hidden rounded-md border border-gray-alpha-400 bg-background-100", children: [jsxRuntimeExports.jsx("pre", { "aria-hidden": "true", className: "pointer-events-none m-0 select-none p-3 font-mono text-label-12 text-gray-900 blur-[4px]", children: encryptedPlaceholderPreview }), jsxRuntimeExports.jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: ctx ? jsxRuntimeExports.jsxs(Button, { onClick: ctx.onDecrypt, disabled: ctx.isDecrypting, size: "xs", children: [ctx.isDecrypting ? jsxRuntimeExports.jsx(Spinner, { size: 10 }) : jsxRuntimeExports.jsx(Lock, { className: "h-3 w-3" }), jsxRuntimeExports.jsx("span", { children: "Decrypt" })] }) : jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1 rounded border border-gray-alpha-400 bg-gray-100 px-1.5 py-0.5 text-button-12 font-medium text-gray-700", children: [jsxRuntimeExports.jsx(Lock, { className: "h-3 w-3" }), "Encrypted"] }) })] });
341
415
  }
342
- function formatEventType(eventType) {
343
- return eventType.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
416
+ const serializeForClipboard = (value) => {
417
+ if (typeof value === "string")
418
+ return value;
419
+ if (typeof value === "number" || typeof value === "boolean" || value === null) {
420
+ return String(value);
421
+ }
422
+ try {
423
+ return JSON.stringify(value, null, 2);
424
+ } catch {
425
+ return String(value);
426
+ }
427
+ };
428
+ function CopyableDataBlock({ data }) {
429
+ return jsxRuntimeExports.jsxs("div", { className: "relative overflow-x-auto rounded-md border border-gray-alpha-400 p-3", children: [jsxRuntimeExports.jsx(CopyButton, { copyText: serializeForClipboard(data), ariaLabel: "Copy data", className: "absolute right-2 top-2 z-10 flex h-6 w-6 items-center justify-center rounded-md border border-gray-alpha-400 !bg-background-100 p-0 text-gray-900 transition-transform transition-colors duration-100 hover:bg-gray-200 active:scale-95 active:bg-gray-300" }), jsxRuntimeExports.jsx(DataInspector, { data })] });
344
430
  }
345
- function getStatusDotColor(eventType) {
346
- if (eventType === "step_failed" || eventType === "run_failed" || eventType === "workflow_failed") {
347
- return "var(--ds-red-700)";
431
+ function isReservedAttributeKey(key) {
432
+ return key.startsWith(RESERVED_ATTRIBUTE_KEY_PREFIX);
433
+ }
434
+ const rowValueVariants = cva("max-w-[60%] truncate text-right text-copy-13 text-gray-1000", {
435
+ variants: {
436
+ variant: {
437
+ default: "",
438
+ mono: "font-mono"
439
+ }
440
+ },
441
+ defaultVariants: {
442
+ variant: "default"
348
443
  }
349
- if (eventType === "run_cancelled") {
350
- return "var(--ds-amber-700)";
444
+ });
445
+ const rowCopyValueVariants = cva("flex min-w-0 max-w-[60%] items-center justify-end gap-1 text-copy-13 text-gray-1000", {
446
+ variants: {
447
+ variant: {
448
+ default: "",
449
+ mono: "font-mono"
450
+ }
451
+ },
452
+ defaultVariants: {
453
+ variant: "default"
351
454
  }
352
- if (eventType === "step_retrying") {
353
- return "var(--ds-amber-700)";
455
+ });
456
+ function DetailKeyValueRowBase({ label, value, copyText, removed = false, variant }) {
457
+ const stringValue = typeof value === "string" ? value : void 0;
458
+ return jsxRuntimeExports.jsxs("div", { className: "px-1.5 hover:bg-gray-100 flex justify-between gap-3 -mx-1.5 py-0.5 rounded items-center", children: [jsxRuntimeExports.jsx("span", { className: "flex min-w-0 items-center gap-1.5 truncate text-label-13 text-gray-900", children: label }), removed ? jsxRuntimeExports.jsx("span", { className: "shrink-0 text-copy-13 italic text-gray-700", children: "removed" }) : copyText ? jsxRuntimeExports.jsxs("div", { className: cn(rowCopyValueVariants({ variant })), title: copyText, children: [jsxRuntimeExports.jsx(MiddleTruncate, { value: copyText, className: cn(rowValueVariants({ variant, className: "text-right" })), style: { gridTemplateColumns: "minmax(0, 1fr)" } }), jsxRuntimeExports.jsx(CopyButton, { copyText, ariaLabel: `Copy ${label}`, className: "shrink-0 -mr-1" })] }) : jsxRuntimeExports.jsx("span", { className: cn(rowValueVariants({ variant })), title: stringValue, children: value })] });
459
+ }
460
+ function DetailKeyValueRow(props) {
461
+ return jsxRuntimeExports.jsx(DetailKeyValueRowBase, { ...props });
462
+ }
463
+ function DetailMonoKeyValueRow(props) {
464
+ return jsxRuntimeExports.jsx(DetailKeyValueRowBase, { ...props, variant: "mono" });
465
+ }
466
+ function AttributeRow({ attributeKey, value, removed = false }) {
467
+ return jsxRuntimeExports.jsx(DetailKeyValueRow, { label: attributeKey, value, removed });
468
+ }
469
+ function sortAttributeKeys(keys) {
470
+ return [...keys].sort((a, b) => {
471
+ const aReserved = isReservedAttributeKey(a);
472
+ const bReserved = isReservedAttributeKey(b);
473
+ if (aReserved !== bReserved)
474
+ return aReserved ? 1 : -1;
475
+ return a.localeCompare(b);
476
+ });
477
+ }
478
+ function RunAttributesCard({ attributes }) {
479
+ const keys = sortAttributeKeys(Object.keys(attributes));
480
+ if (keys.length === 0)
481
+ return null;
482
+ return jsxRuntimeExports.jsxs(CollapsibleRoot, { defaultOpen: true, children: [jsxRuntimeExports.jsx(CollapsibleTrigger, { children: "Attributes" }), jsxRuntimeExports.jsx(CollapsibleContent, { className: "mb-4", children: jsxRuntimeExports.jsx("div", { className: "flex flex-col", children: keys.map((key) => jsxRuntimeExports.jsx(AttributeRow, { attributeKey: key, value: attributes[key] }, key)) }) })] });
483
+ }
484
+ function formatMetadataValue(value) {
485
+ if (value == null) {
486
+ return String(value);
354
487
  }
355
- if (eventType === "attr_set") {
356
- return "var(--ds-teal-900)";
488
+ if (typeof value === "string") {
489
+ return value;
357
490
  }
358
- if (eventType === "step_completed" || eventType === "run_completed" || eventType === "workflow_completed" || eventType === "hook_disposed" || eventType === "wait_completed") {
359
- return "var(--ds-green-700)";
491
+ if (typeof value === "number" || typeof value === "boolean") {
492
+ return String(value);
360
493
  }
361
- if (eventType === "step_started" || eventType === "run_started" || eventType === "workflow_started" || eventType === "hook_received") {
362
- return "var(--ds-blue-700)";
494
+ try {
495
+ return JSON.stringify(value);
496
+ } catch {
497
+ return String(value);
363
498
  }
364
- return "var(--ds-gray-600)";
365
499
  }
366
- function buildNameMaps(events, run) {
367
- var _a, _b;
368
- const correlationNameMap = /* @__PURE__ */ new Map();
369
- if (events) {
370
- for (const event of events) {
371
- if (event.eventType === "step_created" && event.correlationId) {
372
- const stepName = ((_a = event.eventData) == null ? void 0 : _a.stepName) ?? "";
500
+ function isMetadataRecord(value) {
501
+ return value !== null && typeof value === "object" && !Array.isArray(value);
502
+ }
503
+ function RunMetadataCard({ metadata }) {
504
+ if (!isMetadataRecord(metadata)) {
505
+ return jsxRuntimeExports.jsxs(CollapsibleRoot, { defaultOpen: true, children: [jsxRuntimeExports.jsx(CollapsibleTrigger, { children: "Metadata" }), jsxRuntimeExports.jsx(CollapsibleContent, { className: "mb-4", children: jsxRuntimeExports.jsx(CopyableDataBlock, { data: metadata }) })] });
506
+ }
507
+ const keys = Object.keys(metadata).sort((a, b) => a.localeCompare(b));
508
+ if (keys.length === 0)
509
+ return null;
510
+ return jsxRuntimeExports.jsxs(CollapsibleRoot, { defaultOpen: true, children: [jsxRuntimeExports.jsx(CollapsibleTrigger, { children: "Metadata" }), jsxRuntimeExports.jsx(CollapsibleContent, { className: "mb-4", children: jsxRuntimeExports.jsx("div", { className: "flex flex-col", children: keys.map((key) => jsxRuntimeExports.jsx(AttributeRow, { attributeKey: key, value: formatMetadataValue(metadata[key]) }, key)) }) })] });
511
+ }
512
+ function isAttrSetEventData(data) {
513
+ if (data === null || typeof data !== "object")
514
+ return false;
515
+ const record = data;
516
+ return Array.isArray(record.changes) && record.changes.every((c) => c !== null && typeof c === "object" && typeof c.key === "string");
517
+ }
518
+ function describeWriter(writer) {
519
+ if (!writer)
520
+ return null;
521
+ if (writer.type === "workflow")
522
+ return "Set by workflow";
523
+ if (writer.type === "step") {
524
+ return `Set by step ${writer.stepId} (attempt ${writer.attempt})`;
525
+ }
526
+ return null;
527
+ }
528
+ function AttrSetEventBlock({ data }) {
529
+ if (!isAttrSetEventData(data)) {
530
+ return jsxRuntimeExports.jsx(CopyableDataBlock, { data });
531
+ }
532
+ const writerLabel = describeWriter(data.writer);
533
+ return jsxRuntimeExports.jsxs("div", { className: "flex flex-col px-3 py-1", children: [jsxRuntimeExports.jsx("div", { className: "flex flex-col", children: data.changes.map((change, index) => jsxRuntimeExports.jsx(AttributeRow, { attributeKey: change.key, removed: change.value === null, value: change.value ?? void 0 }, `${change.key}:${index}`)) }), writerLabel && jsxRuntimeExports.jsx("div", { className: "border-t py-1.5 text-label-12", style: {
534
+ borderColor: "var(--ds-gray-alpha-400)",
535
+ color: "var(--ds-gray-700)"
536
+ }, children: writerLabel })] });
537
+ }
538
+ 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}`;
539
+ function DecryptButton({ decrypted = false, loading = false, onClick }) {
540
+ 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"] })] });
541
+ }
542
+ function isStructuredError(value) {
543
+ return value != null && typeof value === "object" && (typeof value.message === "string" || typeof value.stack === "string");
544
+ }
545
+ function deriveTitle(message) {
546
+ const firstLine = message.split("\n").find((line) => line.trim().length > 0) ?? message;
547
+ return firstLine.trim();
548
+ }
549
+ function ErrorStackBlock({ value }) {
550
+ const stack = typeof value.stack === "string" ? value.stack : void 0;
551
+ const message = typeof value.message === "string" ? value.message : void 0;
552
+ const body = stack ?? message ?? "";
553
+ const title = message ? deriveTitle(message) : deriveTitle(body);
554
+ const copyText = message && stack && !stack.includes(message) ? `${message}
555
+
556
+ ${stack}` : body;
557
+ return jsxRuntimeExports.jsxs("div", { className: "relative overflow-hidden rounded-md border", style: {
558
+ borderColor: "var(--ds-red-400)",
559
+ background: "var(--ds-red-100)"
560
+ }, children: [jsxRuntimeExports.jsx(CopyButton, { copyText, ariaLabel: "Copy error", className: "absolute right-2 top-2 flex h-6 w-6 items-center justify-center rounded-md border border-red-400 bg-red-100 p-0 text-red-900 transition-transform transition-colors duration-100 hover:bg-red-200 active:scale-95" }), title && jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 px-3 py-2.5 pr-10", style: {
561
+ color: "var(--ds-red-900)",
562
+ borderBottom: "1px solid var(--ds-red-400)"
563
+ }, children: [jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4 shrink-0" }), jsxRuntimeExports.jsx("p", {
564
+ className: "text-xs font-semibold m-0 truncate",
565
+ // The full message or stack is in the body below; the header just
566
+ // shows the first line, single-line, with overflow
567
+ // ellipsised so a long title doesn't push the copy button or
568
+ // wrap into the framed hint/docs lines.
569
+ title: message,
570
+ children: title
571
+ })] }), body && jsxRuntimeExports.jsx("pre", { className: "px-3 py-2.5 text-xs font-mono whitespace-pre-wrap break-words overflow-auto m-0", style: {
572
+ color: "var(--ds-red-900)",
573
+ background: "var(--ds-red-200)"
574
+ }, children: body })] });
575
+ }
576
+ const STYLES$1 = `.wf-load-more{appearance:none;-webkit-appearance:none;border:none;display:inline-flex;align-items:center;justify-content:center;height:32px;padding:0 12px;border-radius:6px;font-size:13px;font-weight:500;line-height:20px;color:var(--ds-gray-1000);background:var(--ds-background-100);box-shadow:0 0 0 1px var(--ds-gray-400);cursor:pointer;white-space:nowrap;gap:6px;transition:background 150ms}.wf-load-more:hover{background:var(--ds-gray-alpha-200)}.wf-load-more:disabled{opacity:.6;cursor:default}.wf-load-more:disabled:hover{background:var(--ds-background-100)}`;
577
+ function LoadMoreButton({ loading = false, onClick, label = "Load more", loadingLabel = "Loading..." }) {
578
+ return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("style", { dangerouslySetInnerHTML: { __html: STYLES$1 } }), jsxRuntimeExports.jsxs("button", { type: "button", onClick, disabled: loading, className: "wf-load-more", children: [loading && jsxRuntimeExports.jsx(Spinner, { size: 14 }), loading ? loadingLabel : label] })] });
579
+ }
580
+ const STYLES = `.wf-menu-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;color:var(--ds-gray-1000);background:var(--ds-background-100);box-shadow:0 0 0 1px var(--ds-gray-400);cursor:pointer;white-space:nowrap;transition:background 150ms}.wf-menu-btn:hover{background:var(--ds-gray-alpha-200)}.wf-menu-item{appearance:none;-webkit-appearance:none;border:none;display:flex;align-items:center;width:100%;height:40px;padding:0 8px;border-radius:6px;font-size:14px;color:var(--ds-gray-1000);background:transparent;cursor:pointer;transition:background 150ms}.wf-menu-item:hover{background:var(--ds-gray-alpha-100)}`;
581
+ function MenuDropdown({ options, value, onChange }) {
582
+ var _a, _b;
583
+ const [open, setOpen] = reactExports.useState(false);
584
+ const ref = reactExports.useRef(null);
585
+ const label = ((_a = options.find((o) => o.value === value)) == null ? void 0 : _a.label) ?? ((_b = options[0]) == null ? void 0 : _b.label) ?? "";
586
+ reactExports.useEffect(() => {
587
+ if (!open)
588
+ return;
589
+ function handleClickOutside(e) {
590
+ if (ref.current && !ref.current.contains(e.target)) {
591
+ setOpen(false);
592
+ }
593
+ }
594
+ document.addEventListener("mousedown", handleClickOutside);
595
+ return () => document.removeEventListener("mousedown", handleClickOutside);
596
+ }, [open]);
597
+ return jsxRuntimeExports.jsxs("div", { ref, style: { position: "relative", flexShrink: 0 }, children: [jsxRuntimeExports.jsx("style", { dangerouslySetInnerHTML: { __html: STYLES } }), jsxRuntimeExports.jsxs("button", { type: "button", className: "wf-menu-btn", onClick: () => setOpen(!open), children: [jsxRuntimeExports.jsx("span", { children: label }), jsxRuntimeExports.jsx("svg", { width: 16, height: 16, viewBox: "0 0 16 16", fill: "none", style: {
598
+ marginLeft: 16,
599
+ marginRight: -4,
600
+ color: "var(--ds-gray-900)"
601
+ }, children: jsxRuntimeExports.jsx("path", { d: "M4.5 6L8 9.5L11.5 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })] }), open && jsxRuntimeExports.jsx("div", { style: {
602
+ position: "absolute",
603
+ right: 0,
604
+ top: "100%",
605
+ marginTop: 4,
606
+ minWidth: 140,
607
+ padding: 4,
608
+ borderRadius: 12,
609
+ background: "var(--ds-background-100)",
610
+ boxShadow: "var(--ds-shadow-menu, var(--ds-shadow-medium))",
611
+ zIndex: 2001
612
+ }, role: "menu", children: options.map((option) => jsxRuntimeExports.jsx("button", { type: "button", role: "menuitem", className: "wf-menu-item", style: {
613
+ fontWeight: option.value === value ? 500 : 400
614
+ }, onClick: () => {
615
+ onChange(option.value);
616
+ setOpen(false);
617
+ }, children: option.label }, option.value)) })] });
618
+ }
619
+ const ERROR_EVENT_TYPES$1 = /* @__PURE__ */ new Set([
620
+ "step_failed",
621
+ "step_retrying",
622
+ "run_failed",
623
+ "workflow_failed"
624
+ ]);
625
+ const BUTTON_RESET_STYLE = {
626
+ appearance: "none",
627
+ WebkitAppearance: "none",
628
+ border: "none",
629
+ background: "transparent"
630
+ };
631
+ const DOT_PULSE_ANIMATION = "workflow-dot-pulse 1.25s cubic-bezier(0, 0, 0.2, 1) infinite";
632
+ function formatEventTime(date) {
633
+ return date.toLocaleTimeString("en-US", {
634
+ hour: "2-digit",
635
+ minute: "2-digit",
636
+ second: "2-digit",
637
+ hour12: false
638
+ }) + "." + date.getMilliseconds().toString().padStart(3, "0");
639
+ }
640
+ function parseEventDate(value) {
641
+ if (value == null)
642
+ return null;
643
+ const date = value instanceof Date ? value : new Date(String(value));
644
+ return Number.isNaN(date.getTime()) ? null : date;
645
+ }
646
+ function getEffectiveEventDate$1(event) {
647
+ return parseEventDate(event.occurredAt) ?? new Date(event.createdAt);
648
+ }
649
+ function getEffectiveEventTime(event) {
650
+ return getEffectiveEventDate$1(event).getTime();
651
+ }
652
+ function formatEventType(eventType) {
653
+ return eventType.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
654
+ }
655
+ function getStatusDotColor(eventType) {
656
+ if (eventType === "step_failed" || eventType === "run_failed" || eventType === "workflow_failed") {
657
+ return "var(--ds-red-700)";
658
+ }
659
+ if (eventType === "run_cancelled") {
660
+ return "var(--ds-amber-700)";
661
+ }
662
+ if (eventType === "step_retrying") {
663
+ return "var(--ds-amber-700)";
664
+ }
665
+ if (eventType === "attr_set") {
666
+ return "var(--ds-teal-900)";
667
+ }
668
+ if (eventType === "step_completed" || eventType === "run_completed" || eventType === "workflow_completed" || eventType === "hook_disposed" || eventType === "wait_completed") {
669
+ return "var(--ds-green-700)";
670
+ }
671
+ if (eventType === "step_started" || eventType === "run_started" || eventType === "workflow_started" || eventType === "hook_received") {
672
+ return "var(--ds-blue-700)";
673
+ }
674
+ return "var(--ds-gray-600)";
675
+ }
676
+ function buildNameMaps(events, run) {
677
+ var _a, _b;
678
+ const correlationNameMap = /* @__PURE__ */ new Map();
679
+ if (events) {
680
+ for (const event of events) {
681
+ if (event.eventType === "step_created" && event.correlationId) {
682
+ const stepName = ((_a = event.eventData) == null ? void 0 : _a.stepName) ?? "";
373
683
  const parsed = parseStepName(String(stepName));
374
684
  correlationNameMap.set(event.correlationId, (parsed == null ? void 0 : parsed.shortName) ?? stepName);
375
685
  }
@@ -1040,7 +1350,13 @@ function EventListViewInner({ events, run, onLoadEventData, hasMoreEvents = fals
1040
1350
  function EventListView(props) {
1041
1351
  return jsxRuntimeExports.jsx(ContextCardProvider, { children: jsxRuntimeExports.jsx(EventListViewInner, { ...props }) });
1042
1352
  }
1043
- const COL_TEMPLATE = "340px 1px minmax(50px, 1fr)";
1353
+ const GUTTER_PX = 1;
1354
+ const MIN_PX = 50;
1355
+ const DEFAULT_START_PX = 340;
1356
+ function paneColTemplate(startPx) {
1357
+ return `${startPx}px ${GUTTER_PX}px minmax(${MIN_PX}px, 1fr)`;
1358
+ }
1359
+ const COL_TEMPLATE = paneColTemplate(DEFAULT_START_PX);
1044
1360
  const ROWS = [
1045
1361
  { id: "r0", name: 62, off: 0, bar: 72 },
1046
1362
  { id: "r1", name: 78, off: 6, bar: 48 },
@@ -1054,7 +1370,11 @@ const ROWS = [
1054
1370
  const HEADER_MARKERS = ["m0", "m1", "m2", "m3"];
1055
1371
  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
1372
  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)) })] })] });
1373
+ 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.jsx("div", { className: "relative h-10 min-h-10 shrink-0 border-b border-gray-alpha-400", children: jsxRuntimeExports.jsx("div", { className: "absolute inset-x-4 top-[6px]", children: ROWS.map((row, index) => jsxRuntimeExports.jsx(Skeleton, { className: "absolute h-[3px] rounded-full", style: {
1374
+ left: `${row.off}%`,
1375
+ width: `${row.bar}%`,
1376
+ top: index * 3.5
1377
+ } }, row.id)) }) }), 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
1378
  }
1059
1379
  function shouldShowVerticalLine(eventType) {
1060
1380
  if (eventType === "hook_created" || eventType === "hook_received" || eventType === "hook_disposed") {
@@ -1438,319 +1758,39 @@ function cascadeSpans(runSpan, spans) {
1438
1758
  runSpan,
1439
1759
  ...spans.slice().sort((a, b) => {
1440
1760
  const aStart = otelTimeToMs(a.startTime);
1441
- const bStart = otelTimeToMs(b.startTime);
1442
- return aStart - bStart;
1443
- })
1444
- ];
1445
- return sortedSpans.map((span, index) => {
1446
- const parentSpanId = index === 0 ? void 0 : String(sortedSpans[index - 1].spanId);
1447
- return {
1448
- ...span,
1449
- parentSpanId
1450
- };
1451
- });
1452
- }
1453
- function buildTrace(run, events, now) {
1454
- const groupedEvents = groupEventsByCorrelation(events);
1455
- const latestKnownTime = computeLatestKnownTime(events, run);
1456
- const { runSpan, spans } = buildSpans(run, groupedEvents, now, latestKnownTime);
1457
- const sortedCascadingSpans = cascadeSpans(runSpan, spans);
1458
- const traceStartMs = otelTimeToMs(runSpan.startTime);
1459
- const knownDurationMs = latestKnownTime.getTime() - traceStartMs;
1460
- return {
1461
- traceId: run.runId,
1462
- rootSpanId: run.runId,
1463
- spans: sortedCascadingSpans,
1464
- resources: [
1465
- {
1466
- name: "workflow",
1467
- attributes: {
1468
- "service.name": WORKFLOW_LIBRARY.name
1469
- }
1470
- }
1471
- ],
1472
- knownDurationMs: Math.max(0, knownDurationMs)
1473
- };
1474
- }
1475
- const ELLIPSIS = "...";
1476
- const MIN_START = 3;
1477
- const MIN_END = 3;
1478
- const MIN_KEPT = MIN_START + MIN_END;
1479
- const graphemeSegmenter = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
1480
- function toGraphemes(text) {
1481
- if (graphemeSegmenter) {
1482
- return [...graphemeSegmenter.segment(text)].map((s) => s.segment);
1483
- }
1484
- return Array.from(text);
1485
- }
1486
- function buildCandidate(graphemes, kept) {
1487
- if (kept <= 0) {
1488
- return {
1489
- prefixText: "",
1490
- prefixGraphemeCount: 0,
1491
- suffixText: "",
1492
- suffixGraphemeCount: 0,
1493
- text: ELLIPSIS,
1494
- truncated: true
1495
- };
1496
- }
1497
- const suffixGraphemeCount = kept >= MIN_KEPT ? Math.max(MIN_END, Math.floor(kept / 2)) : Math.floor(kept / 2);
1498
- const prefixGraphemeCount = kept - suffixGraphemeCount;
1499
- const prefixText = graphemes.slice(0, prefixGraphemeCount).join("");
1500
- const suffixText = suffixGraphemeCount > 0 ? graphemes.slice(-suffixGraphemeCount).join("") : "";
1501
- return {
1502
- prefixText,
1503
- prefixGraphemeCount,
1504
- suffixText,
1505
- suffixGraphemeCount,
1506
- text: prefixText + ELLIPSIS + suffixText,
1507
- truncated: true
1508
- };
1509
- }
1510
- function middleTruncate(graphemes, availableWidth, measure, fullWidth) {
1511
- const fullText = graphemes.join("");
1512
- const resolvedFullWidth = fullWidth ?? measure(fullText);
1513
- if (availableWidth <= 0 || graphemes.length === 0) {
1514
- return {
1515
- prefixText: fullText,
1516
- prefixGraphemeCount: graphemes.length,
1517
- suffixText: "",
1518
- suffixGraphemeCount: 0,
1519
- text: fullText,
1520
- truncated: false
1521
- };
1522
- }
1523
- if (resolvedFullWidth <= availableWidth) {
1524
- return {
1525
- prefixText: fullText,
1526
- prefixGraphemeCount: graphemes.length,
1527
- suffixText: "",
1528
- suffixGraphemeCount: 0,
1529
- text: fullText,
1530
- truncated: false
1531
- };
1532
- }
1533
- let lo = 0;
1534
- let hi = graphemes.length - 1;
1535
- let best = -1;
1536
- while (lo <= hi) {
1537
- const mid = lo + hi >>> 1;
1538
- const candidate = buildCandidate(graphemes, mid);
1539
- if (measure(candidate.text) <= availableWidth) {
1540
- best = mid;
1541
- lo = mid + 1;
1542
- } else {
1543
- hi = mid - 1;
1544
- }
1545
- }
1546
- if (best === -1) {
1547
- return {
1548
- prefixText: "",
1549
- prefixGraphemeCount: 0,
1550
- suffixText: "",
1551
- suffixGraphemeCount: 0,
1552
- text: "",
1553
- truncated: true
1554
- };
1555
- }
1556
- return buildCandidate(graphemes, best);
1557
- }
1558
- function getMiddleTruncateCopyText({ prefixText, selectionEnd, selectionStart, suffixText, value }) {
1559
- const visibleText = prefixText + ELLIPSIS + suffixText;
1560
- if (selectionStart < 0 || selectionEnd > visibleText.length || selectionStart >= selectionEnd) {
1561
- return null;
1562
- }
1563
- if (selectionStart === 0 && selectionEnd === visibleText.length) {
1564
- return value;
1565
- }
1566
- const ellipsisStart = prefixText.length;
1567
- const ellipsisEnd = ellipsisStart + ELLIPSIS.length;
1568
- if (selectionStart > ellipsisStart || selectionEnd < ellipsisEnd) {
1569
- return null;
1570
- }
1571
- const originalGraphemes = toGraphemes(value);
1572
- const selectedPrefixGraphemeCount = toGraphemes(visibleText.slice(0, selectionStart)).length;
1573
- const selectedSuffixGraphemeCount = toGraphemes(visibleText.slice(ellipsisEnd, selectionEnd)).length;
1574
- const suffixStart = originalGraphemes.length - toGraphemes(suffixText).length;
1575
- return originalGraphemes.slice(selectedPrefixGraphemeCount, suffixStart + selectedSuffixGraphemeCount).join("");
1576
- }
1577
- function getMiddleTruncateCopyTextFromSelectionText({ prefixText, selectionText, suffixText, value }) {
1578
- const visibleText = prefixText + ELLIPSIS + suffixText;
1579
- const trimmedSelectionText = selectionText.trim();
1580
- if (!trimmedSelectionText) {
1581
- return null;
1582
- }
1583
- const leading = selectionText.slice(0, selectionText.length - selectionText.trimStart().length);
1584
- const trailing = selectionText.slice(selectionText.trimEnd().length);
1585
- if (trimmedSelectionText === visibleText) {
1586
- return leading + value + trailing;
1587
- }
1588
- if (!trimmedSelectionText.includes(ELLIPSIS)) {
1589
- return null;
1590
- }
1591
- const selectionStart = visibleText.indexOf(trimmedSelectionText);
1592
- if (selectionStart === -1) {
1593
- return null;
1594
- }
1595
- const selectionEnd = selectionStart + trimmedSelectionText.length;
1596
- const mappedText = getMiddleTruncateCopyText({
1597
- prefixText,
1598
- selectionEnd,
1599
- selectionStart,
1600
- suffixText,
1601
- value
1602
- });
1603
- return mappedText === null ? null : leading + mappedText + trailing;
1604
- }
1605
- const useIsomorphicLayoutEffect = typeof window === "undefined" ? reactExports.useEffect : reactExports.useLayoutEffect;
1606
- function createFullState(value, graphemes) {
1607
- return {
1608
- displayText: value,
1609
- isTruncated: false,
1610
- prefixGraphemeCount: graphemes.length,
1611
- prefixText: value,
1612
- suffixGraphemeCount: 0,
1613
- suffixText: ""
1614
- };
1615
- }
1616
- function useMiddleTruncate(value) {
1617
- const graphemes = reactExports.useMemo(() => toGraphemes(value), [value]);
1618
- const fullState = reactExports.useMemo(() => createFullState(value, graphemes), [graphemes, value]);
1619
- const ref = reactExports.useRef(null);
1620
- const measureRef = reactExports.useRef(null);
1621
- const [state, setState] = reactExports.useState(() => fullState);
1622
- const rafRef = reactExports.useRef(0);
1623
- const updateState = reactExports.useCallback((nextState) => {
1624
- setState((currentState) => {
1625
- if (currentState.displayText === nextState.displayText && currentState.isTruncated === nextState.isTruncated && currentState.prefixText === nextState.prefixText && currentState.prefixGraphemeCount === nextState.prefixGraphemeCount && currentState.suffixText === nextState.suffixText && currentState.suffixGraphemeCount === nextState.suffixGraphemeCount) {
1626
- return currentState;
1627
- }
1628
- return nextState;
1629
- });
1630
- }, []);
1631
- const recalculate = reactExports.useCallback(() => {
1632
- const el = ref.current;
1633
- const measureEl = measureRef.current;
1634
- if (!el || !measureEl)
1635
- return;
1636
- const available = el.clientWidth;
1637
- if (available <= 0) {
1638
- updateState(fullState);
1639
- return;
1640
- }
1641
- const measure = (text) => {
1642
- measureEl.textContent = text;
1643
- return measureEl.scrollWidth;
1644
- };
1645
- const fullWidth = measure(value);
1646
- if (fullWidth <= available) {
1647
- updateState(fullState);
1648
- return;
1649
- }
1650
- const result = middleTruncate(graphemes, available, measure, fullWidth);
1651
- updateState({
1652
- displayText: result.text,
1653
- isTruncated: result.truncated,
1654
- prefixGraphemeCount: result.prefixGraphemeCount,
1655
- prefixText: result.prefixText,
1656
- suffixGraphemeCount: result.suffixGraphemeCount,
1657
- suffixText: result.suffixText
1658
- });
1659
- }, [fullState, graphemes, updateState, value]);
1660
- useIsomorphicLayoutEffect(() => {
1661
- recalculate();
1662
- }, [recalculate]);
1663
- reactExports.useEffect(() => {
1664
- var _a;
1665
- const el = ref.current;
1666
- if (!el)
1667
- return;
1668
- const debouncedRecalc = () => {
1669
- cancelAnimationFrame(rafRef.current);
1670
- rafRef.current = requestAnimationFrame(recalculate);
1671
- };
1672
- const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(debouncedRecalc) : null;
1673
- ro == null ? void 0 : ro.observe(el);
1674
- window.addEventListener("resize", debouncedRecalc);
1675
- const onFontsLoaded = () => {
1676
- debouncedRecalc();
1677
- };
1678
- const fontSet = "fonts" in document ? document.fonts : null;
1679
- (_a = fontSet == null ? void 0 : fontSet.addEventListener) == null ? void 0 : _a.call(fontSet, "loadingdone", onFontsLoaded);
1680
- return () => {
1681
- var _a2;
1682
- ro == null ? void 0 : ro.disconnect();
1683
- window.removeEventListener("resize", debouncedRecalc);
1684
- cancelAnimationFrame(rafRef.current);
1685
- (_a2 = fontSet == null ? void 0 : fontSet.removeEventListener) == null ? void 0 : _a2.call(fontSet, "loadingdone", onFontsLoaded);
1686
- };
1687
- }, [recalculate]);
1688
- return {
1689
- ref,
1690
- measureRef,
1691
- displayText: state.displayText,
1692
- isTruncated: state.isTruncated,
1693
- prefixGraphemeCount: state.prefixGraphemeCount,
1694
- prefixText: state.prefixText,
1695
- suffixGraphemeCount: state.suffixGraphemeCount,
1696
- suffixText: state.suffixText
1697
- };
1698
- }
1699
- function getRangeOffsets(container, range) {
1700
- if (!container.contains(range.startContainer) || !container.contains(range.endContainer)) {
1701
- return null;
1702
- }
1703
- const startRange = document.createRange();
1704
- startRange.selectNodeContents(container);
1705
- startRange.setEnd(range.startContainer, range.startOffset);
1706
- const endRange = document.createRange();
1707
- endRange.selectNodeContents(container);
1708
- endRange.setEnd(range.endContainer, range.endOffset);
1709
- return {
1710
- end: endRange.toString().length,
1711
- start: startRange.toString().length
1712
- };
1713
- }
1714
- function MiddleTruncate({ value, className, onCopy: onCopyProp, ...props }) {
1715
- const { ref, measureRef, displayText, isTruncated, prefixText, suffixText } = useMiddleTruncate(value);
1716
- const visibleRef = reactExports.useRef(null);
1717
- const handleCopy = reactExports.useCallback((e) => {
1718
- onCopyProp == null ? void 0 : onCopyProp(e);
1719
- if (e.defaultPrevented || !isTruncated)
1720
- return;
1721
- const selection = window.getSelection();
1722
- if (!selection || selection.rangeCount === 0)
1723
- return;
1724
- const selectionText = selection.toString();
1725
- if (!selectionText)
1726
- return;
1727
- const range = selection.getRangeAt(0);
1728
- const visibleEl = visibleRef.current;
1729
- let copyText = null;
1730
- if (e.currentTarget.contains(range.startContainer) && e.currentTarget.contains(range.endContainer) && visibleEl) {
1731
- const offsets = getRangeOffsets(visibleEl, range);
1732
- if (offsets) {
1733
- copyText = getMiddleTruncateCopyText({
1734
- prefixText,
1735
- selectionEnd: offsets.end,
1736
- selectionStart: offsets.start,
1737
- suffixText,
1738
- value
1739
- });
1761
+ const bStart = otelTimeToMs(b.startTime);
1762
+ return aStart - bStart;
1763
+ })
1764
+ ];
1765
+ return sortedSpans.map((span, index) => {
1766
+ const parentSpanId = index === 0 ? void 0 : String(sortedSpans[index - 1].spanId);
1767
+ return {
1768
+ ...span,
1769
+ parentSpanId
1770
+ };
1771
+ });
1772
+ }
1773
+ function buildTrace(run, events, now) {
1774
+ const groupedEvents = groupEventsByCorrelation(events);
1775
+ const latestKnownTime = computeLatestKnownTime(events, run);
1776
+ const { runSpan, spans } = buildSpans(run, groupedEvents, now, latestKnownTime);
1777
+ const sortedCascadingSpans = cascadeSpans(runSpan, spans);
1778
+ const traceStartMs = otelTimeToMs(runSpan.startTime);
1779
+ const knownDurationMs = latestKnownTime.getTime() - traceStartMs;
1780
+ return {
1781
+ traceId: run.runId,
1782
+ rootSpanId: run.runId,
1783
+ spans: sortedCascadingSpans,
1784
+ resources: [
1785
+ {
1786
+ name: "workflow",
1787
+ attributes: {
1788
+ "service.name": WORKFLOW_LIBRARY.name
1789
+ }
1740
1790
  }
1741
- }
1742
- copyText ?? (copyText = getMiddleTruncateCopyTextFromSelectionText({
1743
- prefixText,
1744
- selectionText,
1745
- suffixText,
1746
- value
1747
- }));
1748
- if (copyText === null)
1749
- return;
1750
- e.preventDefault();
1751
- e.clipboardData.setData("text/plain", copyText);
1752
- }, [onCopyProp, isTruncated, prefixText, suffixText, value]);
1753
- return jsxRuntimeExports.jsxs("span", { title: isTruncated ? value : void 0, ...props, ref, className: cn("relative inline-grid min-w-0 max-w-full overflow-hidden whitespace-nowrap", className), onCopy: handleCopy, children: [isTruncated && jsxRuntimeExports.jsx("span", { className: "sr-only select-none", children: value }), jsxRuntimeExports.jsx("span", { "aria-hidden": "true", className: "pointer-events-none col-start-1 row-start-1 invisible select-none whitespace-nowrap", children: value }), jsxRuntimeExports.jsx("span", { "aria-hidden": isTruncated || void 0, className: "col-start-1 row-start-1 min-w-0 overflow-hidden", ref: visibleRef, children: isTruncated ? jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("span", { children: prefixText }), jsxRuntimeExports.jsx("span", { children: ELLIPSIS }), jsxRuntimeExports.jsx("span", { children: suffixText })] }) : displayText }), jsxRuntimeExports.jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute left-0 top-0 inline-block invisible select-none whitespace-nowrap", ref: measureRef })] });
1791
+ ],
1792
+ knownDurationMs: Math.max(0, knownDurationMs)
1793
+ };
1754
1794
  }
1755
1795
  function ConversationView({ messages }) {
1756
1796
  if (messages.length === 0) {
@@ -1897,7 +1937,7 @@ const conversationTabs = [
1897
1937
  ];
1898
1938
  function ConversationWithTabs({ conversation, args }) {
1899
1939
  const [activeTab, setActiveTab] = reactExports.useState("conversation");
1900
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Input", children: jsxRuntimeExports.jsx(TabbedContainer, { tabs: conversationTabs, activeTab, onTabChange: setActiveTab, ariaLabel: "Conversation view", children: activeTab === "conversation" ? jsxRuntimeExports.jsx(ConversationView, { messages: conversation }) : jsxRuntimeExports.jsx("div", { className: "p-3", children: Array.isArray(args) ? args.map((v, i) => jsxRuntimeExports.jsx("div", { className: "mt-2 first:mt-0", children: JsonBlock(v) }, i)) : JsonBlock(args) }) }) });
1940
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Input", children: jsxRuntimeExports.jsx(TabbedContainer, { tabs: conversationTabs, activeTab, onTabChange: setActiveTab, ariaLabel: "Conversation view", children: activeTab === "conversation" ? jsxRuntimeExports.jsx(ConversationView, { messages: conversation }) : jsxRuntimeExports.jsx("div", { className: "p-3", children: Array.isArray(args) ? args.map((v, i) => jsxRuntimeExports.jsx("div", { className: "mt-2 first:mt-0", children: JsonBlock(v) }, i)) : JsonBlock(args) }) }) });
1901
1941
  }
1902
1942
  function EncryptedFieldBlock() {
1903
1943
  return jsxRuntimeExports.jsx(EncryptedDataBlock, {});
@@ -2069,7 +2109,7 @@ const attributeToDisplayFn = {
2069
2109
  environment: (_value) => null,
2070
2110
  executionContext: (_value) => null,
2071
2111
  // Attributes — string-string metadata attached to the run.
2072
- // Rendered as key-value rows in its own collapsible DetailCard;
2112
+ // Rendered as key-value rows in its own collapsible section;
2073
2113
  // if empty/missing, hidden by the hasDisplayContent gate.
2074
2114
  attributes: (value) => {
2075
2115
  if (!hasDisplayContent(value))
@@ -2089,15 +2129,17 @@ const attributeToDisplayFn = {
2089
2129
  metadata: (value) => {
2090
2130
  if (!hasDisplayContent(value))
2091
2131
  return null;
2092
- if (isEncryptedMarker(value))
2093
- return jsxRuntimeExports.jsx(EncryptedDataBlock, {});
2094
- if (isExpiredMarker(value))
2095
- return jsxRuntimeExports.jsx(ExpiredFieldBlock, {});
2096
- return JsonBlock(value);
2132
+ if (isEncryptedMarker(value)) {
2133
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Metadata", children: jsxRuntimeExports.jsx(EncryptedDataBlock, {}) });
2134
+ }
2135
+ if (isExpiredMarker(value)) {
2136
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Metadata", children: jsxRuntimeExports.jsx(ExpiredFieldBlock, {}) });
2137
+ }
2138
+ return jsxRuntimeExports.jsx(RunMetadataCard, { metadata: value });
2097
2139
  },
2098
2140
  input: (value, context) => {
2099
2141
  if (isEncryptedMarker(value)) {
2100
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Input", children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
2142
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Input", children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
2101
2143
  }
2102
2144
  if (isExpiredMarker(value))
2103
2145
  return jsxRuntimeExports.jsx(ExpiredFieldBlock, {});
@@ -2109,51 +2151,51 @@ const attributeToDisplayFn = {
2109
2151
  if ((context == null ? void 0 : context.stepName) && isDoStreamStep(context.stepName)) {
2110
2152
  const conversation = extractConversation(args);
2111
2153
  if (conversation && conversation.length > 0) {
2112
- return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(ConversationWithTabs, { conversation, args }), hasClosureVars && jsxRuntimeExports.jsx(DetailCard, { summary: "Closure Variables", children: JsonBlock(closureVars) }), hasThisVal && jsxRuntimeExports.jsx(DetailCard, { summary: "This Value", children: JsonBlock(thisVal) })] });
2154
+ return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(ConversationWithTabs, { conversation, args }), hasClosureVars && jsxRuntimeExports.jsx(Collapsible, { label: "Closure Variables", children: JsonBlock(closureVars) }), hasThisVal && jsxRuntimeExports.jsx(Collapsible, { label: "This Value", children: JsonBlock(thisVal) })] });
2113
2155
  }
2114
2156
  }
2115
2157
  if (!hasArgs && !hasClosureVars && !hasThisVal) {
2116
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Input (no data)", disabled: true });
2158
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Input (no data)", disabled: true });
2117
2159
  }
2118
- return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(DetailCard, { summary: "Input", children: Array.isArray(args) ? args.map((v, i) => jsxRuntimeExports.jsx("div", { className: "mt-2 first:mt-0", children: JsonBlock(v) }, i)) : JsonBlock(args) }), hasClosureVars && jsxRuntimeExports.jsx(DetailCard, { summary: "Closure Variables", children: JsonBlock(closureVars) }), hasThisVal && jsxRuntimeExports.jsx(DetailCard, { summary: "Context", children: JsonBlock(thisVal) })] });
2160
+ return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(Collapsible, { label: "Input", children: Array.isArray(args) ? args.map((v, i) => jsxRuntimeExports.jsx("div", { className: "mt-2 first:mt-0", children: JsonBlock(v) }, i)) : JsonBlock(args) }), hasClosureVars && jsxRuntimeExports.jsx(Collapsible, { label: "Closure Variables", children: JsonBlock(closureVars) }), hasThisVal && jsxRuntimeExports.jsx(Collapsible, { label: "Context", children: JsonBlock(thisVal) })] });
2119
2161
  }
2120
2162
  if (!hasDisplayContent(value)) {
2121
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Input (no data)", disabled: true });
2163
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Input (no data)", disabled: true });
2122
2164
  }
2123
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Input", children: Array.isArray(value) ? value.map((v, i) => jsxRuntimeExports.jsx("div", { className: "mt-2 first:mt-0", children: JsonBlock(v) }, i)) : JsonBlock(value) });
2165
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Input", children: Array.isArray(value) ? value.map((v, i) => jsxRuntimeExports.jsx("div", { className: "mt-2 first:mt-0", children: JsonBlock(v) }, i)) : JsonBlock(value) });
2124
2166
  },
2125
2167
  output: (value) => {
2126
2168
  if (isEncryptedMarker(value)) {
2127
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Output", children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
2169
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Output", children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
2128
2170
  }
2129
2171
  if (!hasDisplayContent(value))
2130
2172
  return null;
2131
2173
  if (isExpiredMarker(value))
2132
2174
  return jsxRuntimeExports.jsx(ExpiredFieldBlock, {});
2133
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Output", children: JsonBlock(value) });
2175
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Output", children: JsonBlock(value) });
2134
2176
  },
2135
2177
  error: (value) => {
2136
2178
  if (isEncryptedMarker(value)) {
2137
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Error", defaultOpen: true, children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
2179
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Error", defaultOpen: true, children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
2138
2180
  }
2139
2181
  if (isExpiredMarker(value))
2140
2182
  return jsxRuntimeExports.jsx(ExpiredFieldBlock, {});
2141
2183
  if (!hasDisplayContent(value))
2142
2184
  return null;
2143
2185
  if (isStructuredError(value)) {
2144
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Error", defaultOpen: true, children: jsxRuntimeExports.jsx(ErrorStackBlock, { value }) });
2186
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Error", defaultOpen: true, children: jsxRuntimeExports.jsx(ErrorStackBlock, { value }) });
2145
2187
  }
2146
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Error", defaultOpen: true, children: JsonBlock(value) });
2188
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Error", defaultOpen: true, children: JsonBlock(value) });
2147
2189
  },
2148
2190
  eventData: (value) => {
2149
2191
  if (isEncryptedMarker(value)) {
2150
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Event Data", defaultOpen: true, children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
2192
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Event Data", defaultOpen: true, children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
2151
2193
  }
2152
2194
  if (isExpiredMarker(value))
2153
2195
  return jsxRuntimeExports.jsx(ExpiredFieldBlock, {});
2154
2196
  if (!hasDisplayContent(value))
2155
2197
  return null;
2156
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Event Data", defaultOpen: true, children: JsonBlock(value) });
2198
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Event Data", defaultOpen: true, children: JsonBlock(value) });
2157
2199
  },
2158
2200
  errorCode: (value) => {
2159
2201
  if (typeof value !== "string" || value.length === 0)
@@ -2173,6 +2215,7 @@ const selfHeaderedAttributes = /* @__PURE__ */ new Set([
2173
2215
  "input",
2174
2216
  "output",
2175
2217
  "error",
2218
+ "metadata",
2176
2219
  "attributes",
2177
2220
  "eventData"
2178
2221
  ]);
@@ -2194,9 +2237,9 @@ const AttributeBlock = ({ attribute, value, isLoading, inline = false, context }
2194
2237
  if (isLoading && isExpandableLoadingTarget && !hasDisplayContent(value)) {
2195
2238
  const label = attribute === "eventData" ? "Event Data" : attribute === "output" ? "Output" : "Input";
2196
2239
  if (decryptCtx == null ? void 0 : decryptCtx.hasEncryptedData) {
2197
- return jsxRuntimeExports.jsx(DetailCard, { summary: label, defaultOpen: attribute === "eventData", children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
2240
+ return jsxRuntimeExports.jsx(Collapsible, { label, defaultOpen: attribute === "eventData", children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
2198
2241
  }
2199
- return jsxRuntimeExports.jsx(DetailCard, { summary: label });
2242
+ return jsxRuntimeExports.jsx(Collapsible, { label });
2200
2243
  }
2201
2244
  const displayFn = attributeToDisplayFn[attribute];
2202
2245
  if (!displayFn) {
@@ -2282,12 +2325,13 @@ const AttributePanel = ({ data, moduleSpecifier, isLoading, error, expiredAt, on
2282
2325
  isDecrypting,
2283
2326
  hasEncryptedData: outerDecryptCtx == null ? void 0 : outerDecryptCtx.hasEncryptedData
2284
2327
  } : outerDecryptCtx;
2285
- return jsxRuntimeExports.jsx(ContextCardProvider, { children: jsxRuntimeExports.jsx(RunClickContext.Provider, { value: onRunClick, children: jsxRuntimeExports.jsx(StreamClickContext.Provider, { value: onStreamClick, children: jsxRuntimeExports.jsxs(DecryptClickContext.Provider, { value: decryptValue, children: [visibleBasicAttributes.length > 0 && jsxRuntimeExports.jsxs("div", { className: "flex flex-col overflow-hidden divide-y divide-gray-alpha-400 mb-3", children: [orderedBasicAttributes.map((attribute) => {
2328
+ return jsxRuntimeExports.jsx(ContextCardProvider, { children: jsxRuntimeExports.jsx(RunClickContext.Provider, { value: onRunClick, children: jsxRuntimeExports.jsx(StreamClickContext.Provider, { value: onStreamClick, children: jsxRuntimeExports.jsxs(DecryptClickContext.Provider, { value: decryptValue, children: [visibleBasicAttributes.length > 0 && jsxRuntimeExports.jsxs(CollapsibleRoot, { defaultOpen: true, children: [jsxRuntimeExports.jsx(CollapsibleTrigger, { children: "Metadata" }), jsxRuntimeExports.jsx(CollapsibleContent, { className: "mt-0 mb-2", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [orderedBasicAttributes.map((attribute) => {
2286
2329
  var _a;
2287
2330
  const displayValue = (_a = attributeToDisplayFn[attribute]) == null ? void 0 : _a.call(attributeToDisplayFn, displayData[attribute]);
2288
2331
  const isCopyableBasicAttribute = copyableBasicAttributes.has(attribute) && typeof displayValue === "string";
2289
- return jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between py-2", children: [jsxRuntimeExports.jsx("span", { className: "text-label-14 text-gray-900", children: getAttributeDisplayName(attribute) }), isCopyableBasicAttribute ? jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 max-w-[70%] items-center justify-end gap-1 text-[13px] font-mono text-gray-1000", title: displayValue, children: [jsxRuntimeExports.jsx(MiddleTruncate, { value: displayValue, className: "text-right", style: { gridTemplateColumns: "minmax(0, 1fr)" } }), jsxRuntimeExports.jsx(CopyButton, { copyText: displayValue, ariaLabel: `Copy ${getAttributeDisplayName(attribute)}`, className: "shrink-0 -mr-1" })] }) : jsxRuntimeExports.jsx("span", { className: "text-right text-label-13 font-mono", children: displayValue })] }, attribute);
2290
- }), isLoading && resource === "sleep" && !displayData.resumeAt && jsxRuntimeExports.jsx("div", { className: "py-1", children: jsxRuntimeExports.jsxs("div", { className: "flex min-h-[32px] items-center justify-between gap-4 rounded-sm px-2.5 py-1", children: [jsxRuntimeExports.jsx("span", { className: "text-[14px] first-letter:uppercase", style: { color: "var(--ds-gray-700)" }, children: "resumeAt" }), jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-[55%]" })] }) })] }), error ? jsxRuntimeExports.jsx(ErrorCard, { title: "Failed to load resource details", details: error.message, className: "my-4" }) : hasExpired ? jsxRuntimeExports.jsx(ExpiredDataMessage, {}) : resolvedAttributes.length > 0 ? jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: resolvedAttributes.map((attribute) => jsxRuntimeExports.jsx(AttributeBlock, { isLoading, attribute, value: displayData[attribute], context: displayContext }, attribute)) }) : null] }) }) }) });
2332
+ const label = getAttributeDisplayName(attribute);
2333
+ return jsxRuntimeExports.jsx(DetailMonoKeyValueRow, { label, value: displayValue, copyText: isCopyableBasicAttribute ? displayValue : void 0 }, attribute);
2334
+ }), isLoading && resource === "sleep" && !displayData.resumeAt && jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-3 py-0.5", children: [jsxRuntimeExports.jsx("span", { className: "text-label-13 text-gray-900", children: "Resume" }), jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-[55%]" })] })] }) })] }), error ? jsxRuntimeExports.jsx(ErrorCard, { title: "Failed to load resource details", details: error.message, className: "my-4" }) : hasExpired ? jsxRuntimeExports.jsx(ExpiredDataMessage, {}) : resolvedAttributes.length > 0 ? resolvedAttributes.map((attribute) => jsxRuntimeExports.jsx(AttributeBlock, { isLoading, attribute, value: displayData[attribute], context: displayContext }, attribute)) : null] }) }) }) });
2291
2335
  };
2292
2336
  const ERROR_EVENT_TYPES = /* @__PURE__ */ new Set(["step_failed", "step_retrying"]);
2293
2337
  const DATA_EVENT_TYPES = /* @__PURE__ */ new Set([
@@ -2369,17 +2413,17 @@ function EventItem({ event, onLoadEventData, encryptionKey, showSeparateEventOcc
2369
2413
  second: "numeric"
2370
2414
  });
2371
2415
  const displayPayload = isLoading ? loadedData : mergedDisplay;
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) => {
2416
+ return jsxRuntimeExports.jsxs(CollapsibleRoot, { variant: "card", onOpenChange: canHaveData ? (open) => {
2373
2417
  if (open)
2374
2418
  handleExpand();
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 }) })] });
2419
+ } : void 0, children: [jsxRuntimeExports.jsx(CollapsibleTrigger, { className: "px-3 py-2", children: 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 })] }) }), jsxRuntimeExports.jsxs(CollapsibleContent, { 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 }) })] })] });
2376
2420
  }
2377
2421
  function hasOnlyExpiredFields(data, eventType) {
2378
2422
  if (data === null || typeof data !== "object" || Array.isArray(data)) {
2379
2423
  return false;
2380
2424
  }
2381
2425
  const record = data;
2382
- const refKeys = EVENT_DATA_REF_FIELDS[eventType] ?? [];
2426
+ const refKeys = getEventDataRefFields(eventType);
2383
2427
  const presentKeys = refKeys.filter((k) => k in record);
2384
2428
  return presentKeys.length > 0 && presentKeys.every((k) => isExpiredMarker(record[k]));
2385
2429
  }
@@ -2412,9 +2456,9 @@ function EventsList({ events, isLoading = false, error, onLoadEventData, onStrea
2412
2456
  const sortedEvents = reactExports.useMemo(() => [...events].sort((a, b) => getEffectiveEventDate(a).getTime() - getEffectiveEventDate(b).getTime()), [events]);
2413
2457
  const hasEvents = sortedEvents.length > 0 && !error;
2414
2458
  if (!hasEvents && !isLoading) {
2415
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Events", disabled: true });
2459
+ return jsxRuntimeExports.jsx(Collapsible, { label: "Events", disabled: true });
2416
2460
  }
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)) }) }) }) });
2461
+ return jsxRuntimeExports.jsx(RunClickContext.Provider, { value: onRunClick, children: jsxRuntimeExports.jsx(StreamClickContext.Provider, { value: onStreamClick, children: jsxRuntimeExports.jsxs(CollapsibleRoot, { defaultOpen: true, children: [jsxRuntimeExports.jsx(CollapsibleTrigger, { children: "Events" }), jsxRuntimeExports.jsx(CollapsibleContent, { className: "mb-0", 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)) }) })] }) }) });
2418
2462
  }
2419
2463
  const hasField = (value, key) => key in value;
2420
2464
  const RESOURCES_WITH_FETCHED_DETAIL = /* @__PURE__ */ new Set(["run", "step", "sleep"]);
@@ -2781,6 +2825,257 @@ const kbdVariants = cva("inline-flex items-center justify-center rounded px-1 te
2781
2825
  function Kbd({ children, className, variant, size, ...props }) {
2782
2826
  return jsxRuntimeExports.jsx("kbd", { className: cn(kbdVariants({ variant, size, className })), ...props, children });
2783
2827
  }
2828
+ const PANEL_MIN_WIDTH = 280;
2829
+ const PANEL_HARD_MAX_WIDTH = 1300;
2830
+ const PANEL_DEFAULT_WIDTH = 360;
2831
+ const MAIN_MIN_WIDTH = 400;
2832
+ const PANEL_WIDTH_STORAGE_KEY = "workflow-trace-detail-panel-width";
2833
+ function clamp(value, min, max) {
2834
+ return Math.min(Math.max(value, min), max);
2835
+ }
2836
+ function computeMaxPanelWidth(availableWidth) {
2837
+ if (availableWidth <= 0)
2838
+ return PANEL_HARD_MAX_WIDTH;
2839
+ return Math.min(Math.max(availableWidth - MAIN_MIN_WIDTH, 0), PANEL_HARD_MAX_WIDTH);
2840
+ }
2841
+ function clampPanelWidth(width, availableWidth) {
2842
+ return clamp(width, PANEL_MIN_WIDTH, computeMaxPanelWidth(availableWidth));
2843
+ }
2844
+ function readStoredPanelWidth() {
2845
+ if (typeof window === "undefined")
2846
+ return PANEL_DEFAULT_WIDTH;
2847
+ try {
2848
+ const raw = window.localStorage.getItem(PANEL_WIDTH_STORAGE_KEY);
2849
+ const value = raw ? Number(raw) : Number.NaN;
2850
+ if (!Number.isFinite(value))
2851
+ return PANEL_DEFAULT_WIDTH;
2852
+ return clamp(value, PANEL_MIN_WIDTH, PANEL_HARD_MAX_WIDTH);
2853
+ } catch {
2854
+ return PANEL_DEFAULT_WIDTH;
2855
+ }
2856
+ }
2857
+ function writeStoredPanelWidth(width) {
2858
+ if (typeof window === "undefined")
2859
+ return;
2860
+ try {
2861
+ window.localStorage.setItem(PANEL_WIDTH_STORAGE_KEY, String(Math.round(width)));
2862
+ } catch {
2863
+ }
2864
+ }
2865
+ function DraggableBorder({ element, position, onWidthChange, onReset, "aria-label": ariaLabel, "aria-controls": ariaControls, "aria-valuemin": ariaValueMin, "aria-valuemax": ariaValueMax, "aria-valuenow": ariaValueNow }) {
2866
+ const [isDragging, setIsDragging] = reactExports.useState(false);
2867
+ const pointerIdRef = reactExports.useRef(null);
2868
+ const startXRef = reactExports.useRef(0);
2869
+ const startWidthRef = reactExports.useRef(0);
2870
+ const pendingWidthRef = reactExports.useRef(0);
2871
+ const rafRef = reactExports.useRef(null);
2872
+ const movedRef = reactExports.useRef(false);
2873
+ const lastDragEndAtRef = reactExports.useRef(0);
2874
+ reactExports.useEffect(() => {
2875
+ return () => {
2876
+ if (rafRef.current)
2877
+ cancelAnimationFrame(rafRef.current);
2878
+ };
2879
+ }, []);
2880
+ reactExports.useEffect(() => {
2881
+ if (!isDragging)
2882
+ return;
2883
+ const previous = document.body.style.userSelect;
2884
+ document.body.style.userSelect = "none";
2885
+ return () => {
2886
+ document.body.style.userSelect = previous;
2887
+ };
2888
+ }, [isDragging]);
2889
+ const stopDrag = () => {
2890
+ pointerIdRef.current = null;
2891
+ setIsDragging(false);
2892
+ if (rafRef.current) {
2893
+ cancelAnimationFrame(rafRef.current);
2894
+ rafRef.current = null;
2895
+ if (movedRef.current)
2896
+ onWidthChange(pendingWidthRef.current);
2897
+ }
2898
+ if (movedRef.current) {
2899
+ movedRef.current = false;
2900
+ lastDragEndAtRef.current = performance.now();
2901
+ }
2902
+ };
2903
+ const handlePointerDown = (e) => {
2904
+ if (pointerIdRef.current !== null)
2905
+ return;
2906
+ const el = element.current;
2907
+ if (!el)
2908
+ return;
2909
+ if (e.pointerType === "mouse" && e.button !== 0)
2910
+ return;
2911
+ e.currentTarget.setPointerCapture(e.pointerId);
2912
+ pointerIdRef.current = e.pointerId;
2913
+ startXRef.current = e.clientX;
2914
+ startWidthRef.current = el.offsetWidth;
2915
+ movedRef.current = false;
2916
+ setIsDragging(true);
2917
+ };
2918
+ const handlePointerMove = (e) => {
2919
+ if (pointerIdRef.current !== e.pointerId)
2920
+ return;
2921
+ if (Math.abs(e.clientX - startXRef.current) > 4) {
2922
+ movedRef.current = true;
2923
+ }
2924
+ const delta = position === "left" ? startXRef.current - e.clientX : e.clientX - startXRef.current;
2925
+ pendingWidthRef.current = startWidthRef.current + delta;
2926
+ if (!rafRef.current) {
2927
+ rafRef.current = requestAnimationFrame(() => {
2928
+ rafRef.current = null;
2929
+ onWidthChange(pendingWidthRef.current);
2930
+ });
2931
+ }
2932
+ };
2933
+ const handlePointerEnd = (e) => {
2934
+ if (pointerIdRef.current !== e.pointerId)
2935
+ return;
2936
+ stopDrag();
2937
+ };
2938
+ const handleLostPointerCapture = (e) => {
2939
+ if (pointerIdRef.current !== null && e.pointerId !== pointerIdRef.current) {
2940
+ return;
2941
+ }
2942
+ stopDrag();
2943
+ };
2944
+ const handleDoubleClick = () => {
2945
+ if (movedRef.current || performance.now() - lastDragEndAtRef.current < 500) {
2946
+ return;
2947
+ }
2948
+ onReset == null ? void 0 : onReset();
2949
+ };
2950
+ const handleKeyDown = (e) => {
2951
+ const el = element.current;
2952
+ if (!el)
2953
+ return;
2954
+ const step = e.shiftKey ? 64 : 16;
2955
+ const grow = position === "left" ? 1 : -1;
2956
+ let next = null;
2957
+ if (e.key === "ArrowLeft") {
2958
+ next = el.offsetWidth + grow * step;
2959
+ } else if (e.key === "ArrowRight") {
2960
+ next = el.offsetWidth - grow * step;
2961
+ } else if (e.key === "Home" && ariaValueMin !== void 0) {
2962
+ next = ariaValueMin;
2963
+ } else if (e.key === "End" && ariaValueMax !== void 0) {
2964
+ next = ariaValueMax;
2965
+ }
2966
+ if (next === null)
2967
+ return;
2968
+ e.preventDefault();
2969
+ onWidthChange(next);
2970
+ };
2971
+ return jsxRuntimeExports.jsx("div", { role: "separator", "aria-orientation": "vertical", "aria-label": ariaLabel, "aria-controls": ariaControls, "aria-valuemin": ariaValueMin, "aria-valuemax": ariaValueMax, "aria-valuenow": ariaValueNow, tabIndex: 0, className: cn("group absolute inset-y-0 z-10 w-[17px] cursor-col-resize touch-none outline-none", position === "left" ? "-left-2" : "-right-2"), onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerEnd, onPointerCancel: handlePointerEnd, onLostPointerCapture: handleLostPointerCapture, onDoubleClick: handleDoubleClick, onKeyDown: handleKeyDown, children: jsxRuntimeExports.jsx("span", { "aria-hidden": true, className: cn("pointer-events-none absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-transparent transition-colors delay-75 duration-100", "group-hover:bg-gray-500 group-focus-visible:bg-[var(--ds-focus-color)]", isDragging && "bg-gray-500") }) });
2972
+ }
2973
+ function useElementWidth(ref, enabled = true) {
2974
+ const [width, setWidth] = reactExports.useState(0);
2975
+ reactExports.useLayoutEffect(() => {
2976
+ if (!enabled)
2977
+ return;
2978
+ const el = ref.current;
2979
+ if (!el)
2980
+ return;
2981
+ setWidth(Math.round(el.getBoundingClientRect().width));
2982
+ const observer = new ResizeObserver(([entry]) => {
2983
+ setWidth(Math.round((entry == null ? void 0 : entry.contentRect.width) ?? 0));
2984
+ });
2985
+ observer.observe(el);
2986
+ return () => observer.disconnect();
2987
+ }, [ref, enabled]);
2988
+ return width;
2989
+ }
2990
+ const DETAIL_PANEL_ID = "trace-detail-panel";
2991
+ function useSelectedSpanInfo() {
2992
+ const { activeSpan } = useActiveSpan();
2993
+ const sidebar = useSidebarData();
2994
+ return reactExports.useMemo(() => {
2995
+ var _a, _b;
2996
+ if (!activeSpan)
2997
+ return null;
2998
+ const resource = (_a = activeSpan.attributes) == null ? void 0 : _a.resource;
2999
+ const rawEvents = filterSpanRawEvents(sidebar.events, resource, activeSpan.spanId);
3000
+ return {
3001
+ data: (_b = activeSpan.attributes) == null ? void 0 : _b.data,
3002
+ resource,
3003
+ spanId: activeSpan.spanId,
3004
+ rawEvents
3005
+ };
3006
+ }, [activeSpan, sidebar]);
3007
+ }
3008
+ function TraceDetailPanel({ containerRef, onNavigateToSpan, onClose }) {
3009
+ const { activeSpan, activeSpanId, spans } = useActiveSpan();
3010
+ const sidebar = useSidebarData();
3011
+ const selectedSpan = useSelectedSpanInfo();
3012
+ const isOpen = Boolean(activeSpan);
3013
+ const [storedWidth, setStoredWidth] = reactExports.useState(() => readStoredPanelWidth());
3014
+ const containerWidth = useElementWidth(containerRef, isOpen);
3015
+ const asideRef = reactExports.useRef(null);
3016
+ const handleResize = reactExports.useCallback((next) => {
3017
+ const clamped = clampPanelWidth(next, containerWidth);
3018
+ setStoredWidth(clamped);
3019
+ writeStoredPanelWidth(clamped);
3020
+ }, [containerWidth]);
3021
+ const panelWidth = clampPanelWidth(storedWidth, containerWidth);
3022
+ const panelMaxWidth = Math.max(PANEL_MIN_WIDTH, computeMaxPanelWidth(containerWidth));
3023
+ const { prevSpanId, nextSpanId } = reactExports.useMemo(() => {
3024
+ var _a, _b;
3025
+ if (!activeSpanId)
3026
+ return { prevSpanId: null, nextSpanId: null };
3027
+ const i = spans.findIndex((s) => s.spanId === activeSpanId);
3028
+ if (i === -1)
3029
+ return { prevSpanId: null, nextSpanId: null };
3030
+ return {
3031
+ prevSpanId: ((_a = spans[i - 1]) == null ? void 0 : _a.spanId) ?? null,
3032
+ nextSpanId: ((_b = spans[i + 1]) == null ? void 0 : _b.spanId) ?? null
3033
+ };
3034
+ }, [activeSpanId, spans]);
3035
+ const handleSelectPrev = reactExports.useCallback(() => {
3036
+ if (prevSpanId)
3037
+ onNavigateToSpan(prevSpanId);
3038
+ }, [prevSpanId, onNavigateToSpan]);
3039
+ const handleSelectNext = reactExports.useCallback(() => {
3040
+ if (nextSpanId)
3041
+ onNavigateToSpan(nextSpanId);
3042
+ }, [nextSpanId, onNavigateToSpan]);
3043
+ reactExports.useEffect(() => {
3044
+ if (!isOpen)
3045
+ return;
3046
+ const onKeyDown = (e) => {
3047
+ if (e.key !== "j" && e.key !== "k" && e.key !== "ArrowDown" && e.key !== "ArrowUp") {
3048
+ return;
3049
+ }
3050
+ const target = e.target;
3051
+ if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || (target == null ? void 0 : target.isContentEditable)) {
3052
+ return;
3053
+ }
3054
+ const targetId = e.key === "k" || e.key === "ArrowUp" ? prevSpanId : nextSpanId;
3055
+ if (targetId) {
3056
+ e.preventDefault();
3057
+ onNavigateToSpan(targetId);
3058
+ }
3059
+ };
3060
+ window.addEventListener("keydown", onKeyDown);
3061
+ return () => window.removeEventListener("keydown", onKeyDown);
3062
+ }, [isOpen, prevSpanId, nextSpanId, onNavigateToSpan]);
3063
+ const selectedSpanName = reactExports.useMemo(() => {
3064
+ var _a, _b;
3065
+ if (!(selectedSpan == null ? void 0 : selectedSpan.data))
3066
+ return "Details";
3067
+ const data = selectedSpan.data;
3068
+ if (selectedSpan.resource === "hook") {
3069
+ return data.token ?? data.hookId;
3070
+ }
3071
+ const stepName = data.stepName;
3072
+ const workflowName = data.workflowName;
3073
+ return (stepName ? (_a = parseStepName(stepName)) == null ? void 0 : _a.shortName : void 0) ?? (workflowName ? (_b = parseWorkflowName(workflowName)) == null ? void 0 : _b.shortName : void 0) ?? stepName ?? workflowName ?? data.hookId ?? "Details";
3074
+ }, [selectedSpan == null ? void 0 : selectedSpan.data, selectedSpan == null ? void 0 : selectedSpan.resource]);
3075
+ if (!activeSpan)
3076
+ return null;
3077
+ return jsxRuntimeExports.jsxs("aside", { ref: asideRef, id: DETAIL_PANEL_ID, className: "relative flex flex-col h-full max-h-full shrink-0 bg-background-100 border-l border-gray-alpha-400", style: { width: panelWidth }, children: [jsxRuntimeExports.jsx(DraggableBorder, { element: asideRef, position: "left", onWidthChange: handleResize, onReset: () => handleResize(PANEL_DEFAULT_WIDTH), "aria-label": "Resize span details panel", "aria-controls": DETAIL_PANEL_ID, "aria-valuemin": PANEL_MIN_WIDTH, "aria-valuemax": panelMaxWidth, "aria-valuenow": Math.min(Math.max(Math.round(panelWidth), PANEL_MIN_WIDTH), panelMaxWidth) }), jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2 shrink-0 px-4 py-[7.5px]", 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: handleSelectPrev, 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: handleSelectNext, 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: onClose, 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 }) }) })] });
3078
+ }
2784
3079
  const WorkflowIcon = () => {
2785
3080
  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" }) });
2786
3081
  };
@@ -2812,10 +3107,8 @@ function getEventStyle(resource, isErrored) {
2812
3107
  };
2813
3108
  }
2814
3109
  const EventRow = ({ span, isSelected, isDimmed, onSelectSpan }) => {
2815
- var _a;
2816
3110
  const durationMs = getSpanDurationMs(span);
2817
- const workflowStatus = (_a = span.attributes.data) == null ? void 0 : _a.status;
2818
- const isErrored = span.status.code === 2 || workflowStatus === "failed";
3111
+ const isErrored = isSpanErrored(span);
2819
3112
  const { icon: Icon, className: tagClassName } = getEventStyle(span.resource, isErrored);
2820
3113
  return jsxRuntimeExports.jsx("li", { className: cn("relative overflow-clip group transition-opacity", ROW_HEIGHT_CLASS, isDimmed && "opacity-35"), role: "treeitem", "aria-selected": isSelected, "aria-expanded": isSelected, "aria-level": 1, onClick: () => onSelectSpan(span.spanId), children: jsxRuntimeExports.jsx("div", { className: "h-full hover:bg-gray-100 group-aria-selected:bg-gray-100 group-aria-selected:hover:bg-gray-200", children: jsxRuntimeExports.jsxs("div", { className: "flex h-full min-w-0 items-center pl-4 pr-2", children: [jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [jsxRuntimeExports.jsx("span", { className: cn("shrink-0", tagClassName), children: jsxRuntimeExports.jsx(Icon, { className: "w-4 h-4" }) }), jsxRuntimeExports.jsx("span", { className: "min-w-0 text-label-14", children: jsxRuntimeExports.jsx(MiddleTruncate, { value: span.name }) })] }), jsxRuntimeExports.jsx("div", { className: "ml-2 shrink-0", children: jsxRuntimeExports.jsx("span", { className: "text-label-14 text-gray-900 tabular-nums", children: formatDurationPrecise(durationMs) }) })] }) }) });
2821
3114
  };
@@ -2827,22 +3120,20 @@ const EventList = ({ spans, activeSpanId, searchResult, onSelectSpan }) => {
2827
3120
  paddingBottom: (spans.length - end) * ROW_HEIGHT_PX
2828
3121
  }, children: spans.slice(start, end).map((span) => jsxRuntimeExports.jsx(EventRow, { span, isSelected: span.spanId === activeSpanId, isDimmed: isSpanDimmedBySearch(span.spanId, searchResult), onSelectSpan }, span.spanId)) });
2829
3122
  };
2830
- const GUTTER_PX = 1;
2831
- const MIN_PX = 50;
2832
- const DEFAULT_START_PX = 340;
2833
- function SplitPane({ children, className, defaultStartWidth = DEFAULT_START_PX, startHeader, endHeader, scrollContainerRef }) {
3123
+ function SplitPane({ children, className, startHeader, endHeader, scrollContainerRef }) {
2834
3124
  const parts = reactExports.Children.toArray(children);
2835
3125
  if (parts.length !== 2) {
2836
3126
  throw new Error("SplitPane expects exactly two children");
2837
3127
  }
2838
3128
  const [start, end] = parts;
2839
- const [startPx, setStartPx] = reactExports.useState(defaultStartWidth);
3129
+ const [startPx, setStartPx] = reactExports.useState(DEFAULT_START_PX);
2840
3130
  const [isDragging, setIsDragging] = reactExports.useState(false);
2841
3131
  const containerRef = reactExports.useRef(null);
2842
3132
  const gutterRef = reactExports.useRef(null);
2843
3133
  const rafRef = reactExports.useRef(null);
2844
- const pendingPx = reactExports.useRef(defaultStartWidth);
3134
+ const pendingPx = reactExports.useRef(DEFAULT_START_PX);
2845
3135
  const pointerIdRef = reactExports.useRef(null);
3136
+ const containerWidth = useElementWidth(containerRef);
2846
3137
  reactExports.useEffect(() => {
2847
3138
  return () => {
2848
3139
  if (rafRef.current)
@@ -2916,13 +3207,10 @@ function SplitPane({ children, className, defaultStartWidth = DEFAULT_START_PX,
2916
3207
  rafRef.current = null;
2917
3208
  }
2918
3209
  };
2919
- const colTemplate = `${startPx}px ${GUTTER_PX}px minmax(${MIN_PX}px, 1fr)`;
2920
- const hasHeaders = startHeader != null || endHeader != null;
3210
+ const effectiveStartPx = containerWidth > 0 ? Math.max(MIN_PX, Math.min(containerWidth - MIN_PX - GUTTER_PX, startPx)) : startPx;
3211
+ const colTemplate = paneColTemplate(effectiveStartPx);
2921
3212
  const gutter = jsxRuntimeExports.jsx("div", { ref: gutterRef, className: "relative z-20 isolate flex shrink-0 cursor-col-resize justify-center", onPointerDown: handlePointerDown, onLostPointerCapture: handleLostPointerCapture, children: jsxRuntimeExports.jsx("span", { className: "pointer-events-none relative z-10 h-full w-px shrink-0 bg-gray-alpha-400", "aria-hidden": true }) });
2922
- if (hasHeaders) {
2923
- return jsxRuntimeExports.jsxs("div", { className: cn("flex flex-col h-full min-h-0", className), children: [jsxRuntimeExports.jsxs("div", { className: "shrink-0 grid", style: { gridTemplateColumns: colTemplate }, children: [jsxRuntimeExports.jsx("div", { children: startHeader }), jsxRuntimeExports.jsx("div", { className: "flex justify-center", children: jsxRuntimeExports.jsx("span", { className: "h-full w-px bg-gray-alpha-400", "aria-hidden": true }) }), jsxRuntimeExports.jsx("div", { children: endHeader })] }), jsxRuntimeExports.jsxs("div", { ref: setContainerRef, className: cn("grid flex-1 min-h-0 overflow-x-hidden overflow-y-auto", isDragging && "select-none"), style: { gridTemplateColumns: colTemplate }, children: [start, gutter, end] })] });
2924
- }
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] });
3213
+ return jsxRuntimeExports.jsxs("div", { className: cn("flex flex-col h-full min-h-0", className), children: [jsxRuntimeExports.jsxs("div", { className: "shrink-0 grid", style: { gridTemplateColumns: colTemplate }, children: [jsxRuntimeExports.jsx("div", { children: startHeader }), jsxRuntimeExports.jsx("div", { className: "flex justify-center", children: jsxRuntimeExports.jsx("span", { className: "h-full w-px bg-gray-alpha-400", "aria-hidden": true }) }), jsxRuntimeExports.jsx("div", { children: endHeader })] }), jsxRuntimeExports.jsxs("div", { ref: setContainerRef, className: cn("grid flex-1 min-h-0 overflow-x-hidden overflow-y-auto", isDragging && "select-none"), style: { gridTemplateColumns: colTemplate }, children: [start, gutter, end] })] });
2926
3214
  }
2927
3215
  const hint = "_hint_1dmsq_3";
2928
3216
  const styles = {
@@ -3029,33 +3317,15 @@ function useAnimatedViewport(initial) {
3029
3317
  reactExports.useEffect(() => cancel, [cancel]);
3030
3318
  return { viewport, setViewport, animateTo };
3031
3319
  }
3032
- function useSelectedSpanInfo() {
3033
- const { activeSpan } = useActiveSpan();
3034
- const sidebar = useSidebarData();
3035
- return reactExports.useMemo(() => {
3036
- var _a, _b;
3037
- if (!activeSpan)
3038
- return null;
3039
- const resource = (_a = activeSpan.attributes) == null ? void 0 : _a.resource;
3040
- const rawEvents = filterSpanRawEvents(sidebar.events, resource, activeSpan.spanId);
3041
- return {
3042
- data: (_b = activeSpan.attributes) == null ? void 0 : _b.data,
3043
- resource,
3044
- spanId: activeSpan.spanId,
3045
- rawEvents
3046
- };
3047
- }, [activeSpan, sidebar]);
3048
- }
3049
3320
  function NewTraceViewer$1({ trace, onLoadMore, hasMore, isLoadingMore }) {
3050
3321
  return jsxRuntimeExports.jsx(TooltipProvider, { delayDuration: 300, children: jsxRuntimeExports.jsx(ActiveSpanProvider, { spans: trace.spans, children: jsxRuntimeExports.jsx(NewTraceViewerContent, { trace, onLoadMore, hasMore, isLoadingMore }) }) });
3051
3322
  }
3052
3323
  function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
3053
- const { activeSpan, activeSpanId, setActiveSpan, clearActiveSpan } = useActiveSpan();
3054
- const sidebar = useSidebarData();
3055
- const selectedSpan = useSelectedSpanInfo();
3324
+ const { activeSpanId, setActiveSpan, clearActiveSpan } = useActiveSpan();
3056
3325
  const reducedMotion = useReducedMotion();
3057
3326
  const [searchQuery, setSearchQuery] = reactExports.useState("");
3058
3327
  const deferredSearchQuery = reactExports.useDeferredValue(searchQuery);
3328
+ const paneRootRef = reactExports.useRef(null);
3059
3329
  const searchResult = reactExports.useMemo(() => searchSpans(trace.spans, deferredSearchQuery), [trace.spans, deferredSearchQuery]);
3060
3330
  const root = reactExports.useMemo(() => computeRootBounds(trace.spans), [trace.spans]);
3061
3331
  const scrollContainerRef = reactExports.useRef(null);
@@ -3095,47 +3365,30 @@ function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
3095
3365
  const resetZoom = reactExports.useCallback(() => {
3096
3366
  animateTo({ start: root.startTime, end: root.startTime + root.duration });
3097
3367
  }, [animateTo, root.startTime, root.duration]);
3368
+ const clampToRoot = reactExports.useCallback((next) => clampViewportToRoot(next, root.startTime, root.endTime, MIN_VIEWPORT_MS), [root.startTime, root.endTime]);
3098
3369
  const handleRevealTime = reactExports.useCallback((timeMs) => {
3099
- const rootS = root.startTime;
3100
- const rootE = root.startTime + root.duration;
3101
3370
  const { start, end } = viewportRef.current;
3102
3371
  const duration = end - start;
3103
- let newStart = timeMs - duration / 2;
3104
- let newEnd = timeMs + duration / 2;
3105
- if (newStart < rootS) {
3106
- newStart = rootS;
3107
- newEnd = rootS + duration;
3108
- }
3109
- if (newEnd > rootE) {
3110
- newEnd = rootE;
3111
- newStart = Math.max(rootS, rootE - duration);
3112
- }
3113
- animateTo({ start: newStart, end: newEnd });
3114
- }, [animateTo, root.startTime, root.duration]);
3372
+ animateTo(clampToRoot({
3373
+ start: timeMs - duration / 2,
3374
+ end: timeMs + duration / 2
3375
+ }));
3376
+ }, [animateTo, clampToRoot]);
3115
3377
  const ZOOM_FACTOR = 0.5;
3116
3378
  const zoomBy = reactExports.useCallback((factor) => {
3117
- const rootS = root.startTime;
3118
- const rootE = root.startTime + root.duration;
3119
- const rootD = root.duration;
3120
3379
  setViewport((prev) => {
3121
- const prevDuration = prev.end - prev.start;
3122
3380
  const center = (prev.start + prev.end) / 2;
3123
- const newDuration = Math.max(MIN_VIEWPORT_MS, Math.min(rootD, prevDuration * factor));
3124
- let newStart = center - newDuration / 2;
3125
- let newEnd = center + newDuration / 2;
3126
- if (newStart < rootS) {
3127
- newStart = rootS;
3128
- newEnd = rootS + newDuration;
3129
- }
3130
- if (newEnd > rootE) {
3131
- newEnd = rootE;
3132
- newStart = Math.max(rootS, rootE - newDuration);
3133
- }
3134
- return { start: newStart, end: newEnd };
3381
+ const newDuration = Math.max(MIN_VIEWPORT_MS, (prev.end - prev.start) * factor);
3382
+ return clampToRoot({
3383
+ start: center - newDuration / 2,
3384
+ end: center + newDuration / 2
3385
+ });
3135
3386
  });
3136
- }, [setViewport, root.startTime, root.duration]);
3387
+ }, [setViewport, clampToRoot]);
3137
3388
  const zoomIn = reactExports.useCallback(() => zoomBy(ZOOM_FACTOR), [zoomBy]);
3138
3389
  const zoomOut = reactExports.useCallback(() => zoomBy(1 / ZOOM_FACTOR), [zoomBy]);
3390
+ const isAtMinZoom = viewDuration >= root.duration;
3391
+ const isAtMaxZoom = viewDuration <= MIN_VIEWPORT_MS;
3139
3392
  const focusViewportOnSpan = reactExports.useCallback((spanId) => {
3140
3393
  const span = trace.spans.find((s) => s.spanId === spanId);
3141
3394
  if (!span)
@@ -3143,11 +3396,8 @@ function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
3143
3396
  const spanStart = getHighResInMs(span.startTime);
3144
3397
  const spanEnd = getHighResInMs(span.endTime);
3145
3398
  const spanDuration = spanEnd - spanStart;
3146
- const rootS = root.startTime;
3147
- const rootE = root.startTime + root.duration;
3148
- const rootD = root.duration;
3149
- if (spanDuration > rootD * 0.8) {
3150
- animateTo({ start: rootS, end: rootE });
3399
+ if (spanDuration > root.duration * 0.8) {
3400
+ animateTo({ start: root.startTime, end: root.endTime });
3151
3401
  return;
3152
3402
  }
3153
3403
  const padding = Math.max(spanDuration * 0.2, MIN_VIEWPORT_MS / 2);
@@ -3158,18 +3408,15 @@ function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
3158
3408
  newStart = center - MIN_VIEWPORT_MS / 2;
3159
3409
  newEnd = center + MIN_VIEWPORT_MS / 2;
3160
3410
  }
3161
- if (newStart < rootS) {
3162
- const duration = newEnd - newStart;
3163
- newStart = rootS;
3164
- newEnd = Math.min(rootE, rootS + duration);
3165
- }
3166
- if (newEnd > rootE) {
3167
- const duration = newEnd - newStart;
3168
- newEnd = rootE;
3169
- newStart = Math.max(rootS, rootE - duration);
3170
- }
3171
- animateTo({ start: newStart, end: newEnd });
3172
- }, [animateTo, trace.spans, root.startTime, root.duration]);
3411
+ animateTo(clampToRoot({ start: newStart, end: newEnd }));
3412
+ }, [
3413
+ animateTo,
3414
+ trace.spans,
3415
+ root.startTime,
3416
+ root.endTime,
3417
+ root.duration,
3418
+ clampToRoot
3419
+ ]);
3173
3420
  const scrollSpanIntoView = reactExports.useCallback((spanId) => {
3174
3421
  var _a;
3175
3422
  const index = trace.spans.findIndex((s) => s.spanId === spanId);
@@ -3218,24 +3465,11 @@ function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
3218
3465
  }, [setActiveSpan, scrollSpanIntoView, cancelPendingZoom, focusViewportOnSpan]);
3219
3466
  const [altHeld, setAltHeld] = reactExports.useState(false);
3220
3467
  reactExports.useEffect(() => {
3221
- const handleSidebarNavKey = (e) => {
3222
- const target = e.target;
3223
- if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || (target == null ? void 0 : target.isContentEditable)) {
3224
- return;
3225
- }
3226
- const targetId = e.key === "k" ? prevSpanIdRef.current : nextSpanIdRef.current;
3227
- if (targetId) {
3228
- e.preventDefault();
3229
- navigateToSpanRef.current(targetId);
3230
- }
3231
- };
3232
3468
  const onKeyDown = (e) => {
3233
3469
  if (e.key === "Escape") {
3234
3470
  handleClearActiveSpan();
3235
3471
  } else if (e.key === "Alt") {
3236
3472
  setAltHeld(true);
3237
- } else if (e.key === "j" || e.key === "k") {
3238
- handleSidebarNavKey(e);
3239
3473
  }
3240
3474
  };
3241
3475
  const onKeyUp = (e) => {
@@ -3259,7 +3493,7 @@ function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
3259
3493
  return null;
3260
3494
  const absTime = viewport.start + hoverFraction * viewDuration;
3261
3495
  const offset = absTime - root.startTime;
3262
- return { fraction: hoverFraction, label: formatDuration(offset, true) };
3496
+ return { fraction: hoverFraction, label: formatDurationPrecise(offset) };
3263
3497
  }, [hoverFraction, viewport.start, viewDuration, root.startTime]);
3264
3498
  const handleTimelineMouseMove = reactExports.useCallback((e) => {
3265
3499
  const el = timelineRef.current;
@@ -3277,12 +3511,7 @@ function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
3277
3511
  }, []);
3278
3512
  reactExports.useEffect(() => {
3279
3513
  const el = timelineRef.current;
3280
- if (!el)
3281
- return;
3282
- const rootS = root.startTime;
3283
- const rootE = root.startTime + root.duration;
3284
- const rootD = root.duration;
3285
- if (rootD <= 0)
3514
+ if (!el || root.duration <= 0)
3286
3515
  return;
3287
3516
  const onWheel = (e) => {
3288
3517
  const isZoomGesture = e.ctrlKey || e.metaKey;
@@ -3295,97 +3524,38 @@ function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
3295
3524
  if (contentWidth <= 0)
3296
3525
  return;
3297
3526
  if (isZoomGesture) {
3298
- let dy = e.deltaY;
3299
- if (e.deltaMode === 1)
3300
- dy *= 16;
3301
3527
  const cursorFraction = Math.max(0, Math.min(1, (e.clientX - rect.left - TIMELINE_PADDING_PX) / contentWidth));
3302
- const isMouseWheel = e.deltaMode === 1 || Math.abs(e.deltaY) >= 50;
3303
- const scaleFactor = 2 ** (dy / (isMouseWheel ? 200 : 60));
3528
+ const scaleFactor = wheelZoomScaleFactor(e);
3304
3529
  setViewport((prev) => {
3305
3530
  const prevDuration = prev.end - prev.start;
3306
3531
  const cursorTime = prev.start + cursorFraction * prevDuration;
3307
- const newDuration = Math.max(MIN_VIEWPORT_MS, Math.min(rootD, prevDuration * scaleFactor));
3308
- let newStart = cursorTime - cursorFraction * newDuration;
3309
- let newEnd = newStart + newDuration;
3310
- if (newStart < rootS) {
3311
- newStart = rootS;
3312
- newEnd = rootS + newDuration;
3313
- }
3314
- if (newEnd > rootE) {
3315
- newEnd = rootE;
3316
- newStart = Math.max(rootS, rootE - newDuration);
3317
- }
3318
- return { start: newStart, end: newEnd };
3532
+ const newDuration = Math.max(MIN_VIEWPORT_MS, Math.min(root.duration, prevDuration * scaleFactor));
3533
+ return clampToRoot({
3534
+ start: cursorTime - cursorFraction * newDuration,
3535
+ end: cursorTime + (1 - cursorFraction) * newDuration
3536
+ });
3319
3537
  });
3320
3538
  } else {
3321
- let dx = e.deltaX;
3322
- if (e.deltaMode === 1)
3323
- dx *= 16;
3539
+ const dx = wheelDeltaToPixels(e.deltaX, e.deltaMode);
3324
3540
  setViewport((prev) => {
3325
- const prevDuration = prev.end - prev.start;
3326
- const panAmount = dx / contentWidth * prevDuration;
3327
- let newStart = prev.start + panAmount;
3328
- let newEnd = prev.end + panAmount;
3329
- if (newStart < rootS) {
3330
- newStart = rootS;
3331
- newEnd = rootS + prevDuration;
3332
- }
3333
- if (newEnd > rootE) {
3334
- newEnd = rootE;
3335
- newStart = Math.max(rootS, rootE - prevDuration);
3336
- }
3337
- return { start: newStart, end: newEnd };
3541
+ const panAmount = dx / contentWidth * (prev.end - prev.start);
3542
+ return clampToRoot({
3543
+ start: prev.start + panAmount,
3544
+ end: prev.end + panAmount
3545
+ });
3338
3546
  });
3339
3547
  }
3340
3548
  };
3341
3549
  el.addEventListener("wheel", onWheel, { passive: false });
3342
3550
  return () => el.removeEventListener("wheel", onWheel);
3343
- }, [root.startTime, root.duration, setViewport]);
3344
- const selectedSpanName = reactExports.useMemo(() => {
3345
- var _a, _b;
3346
- if (!(selectedSpan == null ? void 0 : selectedSpan.data))
3347
- return "Details";
3348
- const data = selectedSpan.data;
3349
- if (selectedSpan.resource === "hook") {
3350
- return data.token ?? data.hookId;
3351
- }
3352
- const stepName = data.stepName;
3353
- const workflowName = data.workflowName;
3354
- return (stepName ? (_a = parseStepName(stepName)) == null ? void 0 : _a.shortName : void 0) ?? (workflowName ? (_b = parseWorkflowName(workflowName)) == null ? void 0 : _b.shortName : void 0) ?? stepName ?? workflowName ?? data.hookId ?? "Details";
3355
- }, [selectedSpan == null ? void 0 : selectedSpan.data, selectedSpan == null ? void 0 : selectedSpan.resource]);
3356
- const { prevSpanId, nextSpanId } = reactExports.useMemo(() => {
3357
- var _a, _b;
3358
- if (!activeSpanId)
3359
- return { prevSpanId: null, nextSpanId: null };
3360
- const i = trace.spans.findIndex((s) => s.spanId === activeSpanId);
3361
- if (i === -1)
3362
- return { prevSpanId: null, nextSpanId: null };
3363
- return {
3364
- prevSpanId: ((_a = trace.spans[i - 1]) == null ? void 0 : _a.spanId) ?? null,
3365
- nextSpanId: ((_b = trace.spans[i + 1]) == null ? void 0 : _b.spanId) ?? null
3366
- };
3367
- }, [activeSpanId, trace.spans]);
3368
- const handleSelectPrevSpan = reactExports.useCallback(() => {
3369
- if (prevSpanId)
3370
- navigateToSpan(prevSpanId);
3371
- }, [prevSpanId, navigateToSpan]);
3372
- const handleSelectNextSpan = reactExports.useCallback(() => {
3373
- if (nextSpanId)
3374
- navigateToSpan(nextSpanId);
3375
- }, [nextSpanId, navigateToSpan]);
3376
- const prevSpanIdRef = reactExports.useRef(prevSpanId);
3377
- const nextSpanIdRef = reactExports.useRef(nextSpanId);
3378
- const navigateToSpanRef = reactExports.useRef(navigateToSpan);
3379
- prevSpanIdRef.current = prevSpanId;
3380
- nextSpanIdRef.current = nextSpanId;
3381
- navigateToSpanRef.current = navigateToSpan;
3382
- return jsxRuntimeExports.jsxs("div", { "data-pane": "pane-root", "data-has-detail": activeSpan ? "" : void 0, className: "relative grid w-full h-full max-h-full grid-cols-[minmax(100px,1fr)] data-[has-detail]:grid-cols-[minmax(100px,1fr)_clamp(280px,360px,100%)]", children: [jsxRuntimeExports.jsxs("div", { id: "trace-parent", className: "grid grid-rows-[1fr] h-full min-h-0 overflow-hidden relative bg-background-100", children: [jsxRuntimeExports.jsxs(SplitPane, { scrollContainerRef, startHeader: jsxRuntimeExports.jsxs("div", { className: "bg-background-100 border-b border-gray-alpha-400 h-10 min-h-10 flex items-center pl-4 pr-2 gap-1.5", children: [jsxRuntimeExports.jsx(Search, { className: "w-3.5 h-3.5 shrink-0 text-gray-800" }), jsxRuntimeExports.jsx("input", { id: "trace-viewer-search", name: "trace-viewer-search", type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onKeyDown: (e) => {
3551
+ }, [root.duration, setViewport, clampToRoot]);
3552
+ return jsxRuntimeExports.jsxs("div", { ref: paneRootRef, "data-pane": "pane-root", className: "relative flex w-full h-full max-h-full", children: [jsxRuntimeExports.jsxs("div", { id: "trace-parent", className: "flex-1 min-w-0 grid grid-rows-[auto_1fr] h-full min-h-0 overflow-hidden relative bg-background-100", children: [jsxRuntimeExports.jsx(Minimap, { spans: trace.spans, root, viewport, minViewportMs: MIN_VIEWPORT_MS, onViewportChange: setViewport, onAnimateTo: animateTo }), jsxRuntimeExports.jsxs(SplitPane, { scrollContainerRef, startHeader: jsxRuntimeExports.jsxs("div", { className: "bg-background-100 border-b border-gray-alpha-400 h-10 min-h-10 flex items-center pl-4 pr-2 gap-1.5", children: [jsxRuntimeExports.jsx(Search, { className: "w-3.5 h-3.5 shrink-0 text-gray-800" }), jsxRuntimeExports.jsx("input", { id: "trace-viewer-search", name: "trace-viewer-search", type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onKeyDown: (e) => {
3383
3553
  if (e.key === "Escape" && searchQuery) {
3384
3554
  e.preventDefault();
3385
3555
  e.stopPropagation();
3386
3556
  setSearchQuery("");
3387
3557
  }
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 })] });
3558
+ }, 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, id: "trace-timeline", 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, disabled: isAtMinZoom, "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, disabled: isAtMaxZoom, "aria-label": "Zoom in", children: jsxRuntimeExports.jsx(ZoomIn, { className: "w-4 h-4" }) })] })] }), jsxRuntimeExports.jsx(TraceDetailPanel, { containerRef: paneRootRef, onNavigateToSpan: navigateToSpan, onClose: handleClearActiveSpan }), jsxRuntimeExports.jsx(TraceShortcutHelper, { hasMultipleSpans: trace.spans.length > 1, reducedMotion })] });
3389
3559
  }
3390
3560
  const NewTraceViewer = ({ run, events, sidebarData, onLoadMore, hasMore, isLoadingMore, loading = false }) => {
3391
3561
  const trace = reactExports.useMemo(() => {
@@ -3430,7 +3600,7 @@ async function fetchResourceWithCorrelationId(env, resource, resourceId, options
3430
3600
  async function fetchSpanDetailResource(env, selection, options = {}) {
3431
3601
  const { resource, resourceId, runId } = selection;
3432
3602
  const { encryptionKey } = options;
3433
- const hydrate = async (value) => encryptionKey ? hydrateResourceIOWithKey(value, encryptionKey) : hydrateResourceIO(value);
3603
+ const hydrate = async (value) => hydrateResourceIOAsync(value, encryptionKey);
3434
3604
  if (resource === "hook") {
3435
3605
  const result = await unwrapOrThrow(fetchHook(env, resourceId, "all"));
3436
3606
  return hydrate(result);
@@ -3445,11 +3615,8 @@ async function fetchSpanDetailResource(env, selection, options = {}) {
3445
3615
  const result = await unwrapOrThrow(
3446
3616
  fetchEvents(env, runId, { sortOrder: "asc", limit: 1e3, withData: true })
3447
3617
  );
3448
- const allEvents = result.data.map(
3449
- hydrateResourceIO
3450
- );
3451
3618
  const waitEvents = await Promise.all(
3452
- allEvents.filter((e) => e.correlationId === resourceId).map(hydrate)
3619
+ result.data.filter((e) => e.correlationId === resourceId).map(hydrate)
3453
3620
  );
3454
3621
  const data2 = waitEventsToWaitEntity(waitEvents);
3455
3622
  if (data2 === null) {
@@ -4895,14 +5062,8 @@ function useEventsListData(env, runId, options = {}) {
4895
5062
  const encryptionKeyRef = reactExports.useRef(encryptionKey);
4896
5063
  encryptionKeyRef.current = encryptionKey;
4897
5064
  const hydrateEvents = reactExports.useCallback(async (rawEvents) => {
4898
- const hydrated = rawEvents.map(hydrateResourceIO);
4899
5065
  const key = encryptionKeyRef.current;
4900
- if (key) {
4901
- return Promise.all(
4902
- hydrated.map((ev) => hydrateResourceIOWithKey(ev, key))
4903
- );
4904
- }
4905
- return hydrated;
5066
+ return Promise.all(rawEvents.map((ev) => hydrateResourceIOAsync(ev, key)));
4906
5067
  }, []);
4907
5068
  const fetchInitial = reactExports.useCallback(async () => {
4908
5069
  if (isFetchingRef.current) return;
@@ -4940,7 +5101,7 @@ function useEventsListData(env, runId, options = {}) {
4940
5101
  reactExports.useEffect(() => {
4941
5102
  if (!encryptionKey || events.length === 0) return;
4942
5103
  let cancelled = false;
4943
- Promise.all(events.map((ev) => hydrateResourceIOWithKey(ev, encryptionKey))).then((decrypted) => {
5104
+ Promise.all(events.map((ev) => hydrateResourceIOAsync(ev, encryptionKey))).then((decrypted) => {
4944
5105
  if (!cancelled) setEvents(decrypted);
4945
5106
  }).catch(() => {
4946
5107
  });
@@ -5343,7 +5504,6 @@ function LiveStatus({ hasError, errorMessage }) {
5343
5504
  });
5344
5505
  function RunDetailView({
5345
5506
  runId,
5346
- // TODO: This should open the right sidebar within the trace viewer
5347
5507
  selectedId: _selectedId
5348
5508
  }) {
5349
5509
  var _a;
@@ -5421,7 +5581,10 @@ function RunDetailView({
5421
5581
  if (error2) {
5422
5582
  throw error2;
5423
5583
  }
5424
- const fullEvent = encryptionKeyRef.current ? await hydrateResourceIOWithKey(result, encryptionKeyRef.current) : hydrateResourceIO(result);
5584
+ const fullEvent = await hydrateResourceIOAsync(
5585
+ result,
5586
+ encryptionKeyRef.current ?? void 0
5587
+ );
5425
5588
  if ("eventData" in fullEvent) {
5426
5589
  return fullEvent.eventData;
5427
5590
  }
@@ -5437,7 +5600,10 @@ function RunDetailView({
5437
5600
  if (error2) {
5438
5601
  throw error2;
5439
5602
  }
5440
- const fullEvent = encryptionKeyRef.current ? await hydrateResourceIOWithKey(result, encryptionKeyRef.current) : hydrateResourceIO(result);
5603
+ const fullEvent = await hydrateResourceIOAsync(
5604
+ result,
5605
+ encryptionKeyRef.current ?? void 0
5606
+ );
5441
5607
  if ("eventData" in fullEvent) {
5442
5608
  return fullEvent.eventData;
5443
5609
  }
@@ -5586,8 +5752,8 @@ function RunDetailView({
5586
5752
  if (error && !runData) {
5587
5753
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(Alert, { variant: "destructive", className: "m-4", children: [
5588
5754
  /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4" }),
5589
- /* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: "Error loading workflow run" }),
5590
- /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: error.message })
5755
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: getErrorTitle(error, "Error loading workflow run") }),
5756
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: getErrorMessage(error) })
5591
5757
  ] });
5592
5758
  }
5593
5759
  const workflowName = (_a = parseWorkflowName(run.workflowName)) == null ? void 0 : _a.shortName;