@workflow/web 5.0.0-beta.3 → 5.0.0-beta.31
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.
- package/build/client/assets/arrow-up-right-UTJqZa58.js +15 -0
- package/build/client/assets/encryption-CLVP4klT.js +51 -0
- package/build/client/assets/{entry.client-BWsSsWQm.js → entry.client-Q4eUIqMI.js} +25 -25
- package/build/client/assets/{highlighted-body-B3W2YXNL-Be0uLJd8.js → highlighted-body-B3W2YXNL-BJU4jA-M.js} +2 -2
- package/build/client/assets/{home-Ce97yLJ7.js → home-1xisMAzt.js} +1704 -257
- package/build/client/assets/index-HqNj_XIX.js +200 -0
- package/build/client/assets/{index-DQa-BExo.js → index-Q81MFBxC.js} +26 -26
- package/build/client/assets/index-STTN0-2V.js +306 -0
- package/build/client/assets/manifest-37d4814f.js +1 -0
- package/build/client/assets/{mermaid-3ZIDBTTL-BSJR0c5A.js → mermaid-3ZIDBTTL-BxUZpfmG.js} +4914 -3226
- package/build/client/assets/mermaid-3ZIDBTTL-DDxQhcP4.css +1 -0
- package/build/client/assets/root-CQggqXow.css +1 -0
- package/build/client/assets/{root-DdOfCnSG.js → root-mjlqO83r.js} +5 -15
- package/build/client/assets/run-detail-CWoGxu_0.css +1 -0
- package/build/client/assets/{run-detail-JQ32aJru.js → run-detail-ysogMwZA.js} +1811 -1014
- package/build/client/assets/server-build-C5ehvmav.css +1 -0
- package/build/client/assets/{workflow-graph-viewer-DYhMo9jl.js → workflow-graph-viewer-DpvUticH.js} +5093 -5076
- package/build/client/assets/zstd-B5R2yJjB.wasm +0 -0
- package/build/client/assets/zstd-browser-decoder-BFS0fmpR.js +27 -0
- package/build/server/assets/{app-Bh_7yjpl.js → app-BgN_e9S7.js} +48 -44
- package/build/server/assets/{highlighted-body-B3W2YXNL-Cdb-ypB4.js → highlighted-body-B3W2YXNL-CsR2wqX2.js} +10 -7
- package/build/server/assets/index-BbpsBsGO.js +132 -0
- package/build/server/assets/index-BfLBLRRi.js +204 -0
- package/build/server/assets/index-DIXsjgfZ.js +1121 -0
- package/build/server/assets/{index-meg9qk8y.js → index-Dq5jTBN4.js} +4 -0
- package/build/server/assets/{mermaid-3ZIDBTTL-CE8Volk5.js → mermaid-3ZIDBTTL-B-ddv9lk.js} +10 -7
- package/build/server/assets/{server-build-DztRAoMd.js → server-build-CQLvkWL5.js} +55524 -47343
- package/build/server/assets/{token-DMEdoEUo.js → token-Batv2rdg.js} +6 -2
- package/build/server/assets/{token-util-DsMisyo3.js → token-util-C03rrkmJ.js} +6 -2
- package/build/server/assets/zstd-browser-decoder-vLGtEQW6.js +68 -0
- package/build/server/index.js +5 -1
- package/package.json +14 -11
- package/build/client/assets/encryption-80GMP4r0.js +0 -26
- package/build/client/assets/manifest-923d96a0.js +0 -1
- package/build/client/assets/mermaid-3ZIDBTTL-DKxHcEOp.css +0 -1
- package/build/client/assets/root-DXDFWibD.css +0 -1
- package/build/client/assets/server-build-pZ5ucXET.css +0 -1
- package/build/server/assets/index-CNvEtg5c.js +0 -82
|
@@ -1,26 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { c as createLucideIcon,
|
|
4
|
-
import {
|
|
1
|
+
import { r as reactExports, j as jsxRuntimeExports, p as reactDomExports, G as ReactDOM, d as useNavigate, e as useSearchParams, c as Link, w as withComponentProps, H as useParams } from "./index-Q81MFBxC.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-DpvUticH.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 isHookLifecycleEventType, ac as isTerminalStepEventType, ad as isWaitEventType, ae as isStepEventType, af as _r, ag as RunClickContext, ah as StreamClickContext, ai as Collapsible, aj as isExpiredMarker, ak as isDoStreamStep, al as extractConversation, am as getEventDataRefFields, an as hasEncryptedFields, ao as useSidebarDataOptional, ap as isTerminalWorkflowRunStatus, aq as clsx, ar as useActiveSpan, as as useSidebarData, at as Tooltip, au as TooltipTrigger, av as IconButton, aw as TooltipContent, H as ChevronDown, ax as useRowWindow, ay as isSpanDimmedBySearch, az as ROW_HEIGHT_PX, aA as getSpanDurationMs, aB as isSpanErrored, aC as formatDurationPrecise, aD as TooltipProvider, aE as ActiveSpanProvider, aF as useReducedMotion, aG as searchSpans, aH as computeRootBounds, aI as computeTimeMarkers, aJ as clampViewportToRoot, aK as getHighResInMs, aL as scrollRowIntoView, aM as TIMELINE_PADDING_PX, aN as Minimap, aO as Timeline, aP as TimelineHeader, aQ as wheelZoomScaleFactor, aR as wheelDeltaToPixels, aS as SidebarDataProvider, aT as fetchHook, l as fetchEvents, aU as hydrateResourceIOAsync, J as fetchRun, aV as fetchStep, aW as hydrateResourceIO, aX as fetchStreams, aY as Slot, I as useComposedRefs, aZ as Slottable, e as cn$1, a_ as buttonVariants, a$ as fetchEvent, b0 as fetchEventsByCorrelationId, b1 as isEncryptedData, b2 as hydrateData, b3 as getWebRevivers, T as Tooltip$1, a as TooltipTrigger$1, b as TooltipContent$1, b4 as LIVE_UPDATE_INTERVAL_MS$1, u as useServerConfig, b5 as getEncryptionKeyForRun, t as toast, L as LoaderCircle, b6 as StreamViewer } from "./mermaid-3ZIDBTTL-BxUZpfmG.js";
|
|
4
|
+
import { A as ArrowUpRight } from "./arrow-up-right-UTJqZa58.js";
|
|
5
|
+
import { decrypt, importKey } from "./encryption-CLVP4klT.js";
|
|
6
|
+
import "./index-STTN0-2V.js";
|
|
5
7
|
/**
|
|
6
8
|
* @license lucide-react v0.575.0 - ISC
|
|
7
9
|
*
|
|
8
10
|
* This source code is licensed under the ISC license.
|
|
9
11
|
* See the LICENSE file in the root directory of this source tree.
|
|
10
12
|
*/
|
|
11
|
-
const __iconNode$
|
|
13
|
+
const __iconNode$5 = [
|
|
12
14
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
13
15
|
["path", { d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3", key: "1u773s" }],
|
|
14
16
|
["path", { d: "M12 17h.01", key: "p32p05" }]
|
|
15
17
|
];
|
|
16
|
-
const CircleQuestionMark = createLucideIcon("circle-question-mark", __iconNode$
|
|
18
|
+
const CircleQuestionMark = createLucideIcon("circle-question-mark", __iconNode$5);
|
|
17
19
|
/**
|
|
18
20
|
* @license lucide-react v0.575.0 - ISC
|
|
19
21
|
*
|
|
20
22
|
* This source code is licensed under the ISC license.
|
|
21
23
|
* See the LICENSE file in the root directory of this source tree.
|
|
22
24
|
*/
|
|
23
|
-
const __iconNode$
|
|
25
|
+
const __iconNode$4 = [
|
|
24
26
|
["path", { d: "M3 5h.01", key: "18ugdj" }],
|
|
25
27
|
["path", { d: "M3 12h.01", key: "nlz23k" }],
|
|
26
28
|
["path", { d: "M3 19h.01", key: "noohij" }],
|
|
@@ -28,52 +30,549 @@ const __iconNode$1 = [
|
|
|
28
30
|
["path", { d: "M8 12h13", key: "1za7za" }],
|
|
29
31
|
["path", { d: "M8 19h13", key: "m83p4d" }]
|
|
30
32
|
];
|
|
31
|
-
const List = createLucideIcon("list", __iconNode$
|
|
33
|
+
const List = createLucideIcon("list", __iconNode$4);
|
|
32
34
|
/**
|
|
33
35
|
* @license lucide-react v0.575.0 - ISC
|
|
34
36
|
*
|
|
35
37
|
* This source code is licensed under the ISC license.
|
|
36
38
|
* See the LICENSE file in the root directory of this source tree.
|
|
37
39
|
*/
|
|
38
|
-
const __iconNode = [
|
|
40
|
+
const __iconNode$3 = [
|
|
41
|
+
["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "1357e3" }],
|
|
42
|
+
["path", { d: "M3 3v5h5", key: "1xhq8a" }]
|
|
43
|
+
];
|
|
44
|
+
const RotateCcw = createLucideIcon("rotate-ccw", __iconNode$3);
|
|
45
|
+
/**
|
|
46
|
+
* @license lucide-react v0.575.0 - ISC
|
|
47
|
+
*
|
|
48
|
+
* This source code is licensed under the ISC license.
|
|
49
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
50
|
+
*/
|
|
51
|
+
const __iconNode$2 = [
|
|
39
52
|
["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
|
|
40
53
|
["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
|
|
41
54
|
];
|
|
42
|
-
const Search = createLucideIcon("search", __iconNode);
|
|
55
|
+
const Search = createLucideIcon("search", __iconNode$2);
|
|
56
|
+
/**
|
|
57
|
+
* @license lucide-react v0.575.0 - ISC
|
|
58
|
+
*
|
|
59
|
+
* This source code is licensed under the ISC license.
|
|
60
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
61
|
+
*/
|
|
62
|
+
const __iconNode$1 = [
|
|
63
|
+
["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }],
|
|
64
|
+
["line", { x1: "21", x2: "16.65", y1: "21", y2: "16.65", key: "13gj7c" }],
|
|
65
|
+
["line", { x1: "11", x2: "11", y1: "8", y2: "14", key: "1vmskp" }],
|
|
66
|
+
["line", { x1: "8", x2: "14", y1: "11", y2: "11", key: "durymu" }]
|
|
67
|
+
];
|
|
68
|
+
const ZoomIn = createLucideIcon("zoom-in", __iconNode$1);
|
|
69
|
+
/**
|
|
70
|
+
* @license lucide-react v0.575.0 - ISC
|
|
71
|
+
*
|
|
72
|
+
* This source code is licensed under the ISC license.
|
|
73
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
74
|
+
*/
|
|
75
|
+
const __iconNode = [
|
|
76
|
+
["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }],
|
|
77
|
+
["line", { x1: "21", x2: "16.65", y1: "21", y2: "16.65", key: "13gj7c" }],
|
|
78
|
+
["line", { x1: "8", x2: "14", y1: "11", y2: "11", key: "durymu" }]
|
|
79
|
+
];
|
|
80
|
+
const ZoomOut = createLucideIcon("zoom-out", __iconNode);
|
|
81
|
+
const WORKFLOW_ULID_BODY = "[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}";
|
|
82
|
+
const STEP_ID_PATTERN = new RegExp(`^step_(${WORKFLOW_ULID_BODY})$`, "i");
|
|
83
|
+
const WAIT_ID_PATTERN = new RegExp(`^wait_(${WORKFLOW_ULID_BODY})$`, "i");
|
|
84
|
+
const HOOK_ID_PATTERN = new RegExp(`^hook_(${WORKFLOW_ULID_BODY})$`, "i");
|
|
85
|
+
const EVENT_ID_PATTERN = new RegExp(`^evnt_(${WORKFLOW_ULID_BODY})$`, "i");
|
|
86
|
+
const WORKFLOW_ID_PREFIX_PATTERN = /^(step_|wait_|hook_|evnt_|wrun_)/i;
|
|
87
|
+
function matchPrefixedId(pattern, prefix, kind, query) {
|
|
88
|
+
const match = query.match(pattern);
|
|
89
|
+
if (!match) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
return { kind, id: `${prefix}_${match[1].toUpperCase()}` };
|
|
93
|
+
}
|
|
94
|
+
function parseExactWorkflowSearchId(query) {
|
|
95
|
+
const trimmed = query.trim();
|
|
96
|
+
if (!trimmed) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return matchPrefixedId(STEP_ID_PATTERN, "step", "step", trimmed) ?? matchPrefixedId(WAIT_ID_PATTERN, "wait", "wait", trimmed) ?? matchPrefixedId(HOOK_ID_PATTERN, "hook", "hook", trimmed) ?? matchPrefixedId(EVENT_ID_PATTERN, "evnt", "event", trimmed);
|
|
100
|
+
}
|
|
101
|
+
function looksLikeWorkflowIdSearchInput(query) {
|
|
102
|
+
const trimmed = query.trim();
|
|
103
|
+
if (!WORKFLOW_ID_PREFIX_PATTERN.test(trimmed)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
return /\d/.test(trimmed);
|
|
107
|
+
}
|
|
108
|
+
function CopyButton({ copyText, ariaLabel, className }) {
|
|
109
|
+
const [copied, setCopied] = reactExports.useState(false);
|
|
110
|
+
const timeoutRef = reactExports.useRef(null);
|
|
111
|
+
reactExports.useEffect(() => {
|
|
112
|
+
return () => {
|
|
113
|
+
if (timeoutRef.current) {
|
|
114
|
+
clearTimeout(timeoutRef.current);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}, []);
|
|
118
|
+
return jsxRuntimeExports.jsx("button", { type: "button", "aria-label": ariaLabel, className: cn("cursor-pointer text-gray-800 hover:text-gray-1000 bg-transparent border-0 p-1 m-0", className), onClick: (e) => {
|
|
119
|
+
e.stopPropagation();
|
|
120
|
+
if (timeoutRef.current) {
|
|
121
|
+
clearTimeout(timeoutRef.current);
|
|
122
|
+
}
|
|
123
|
+
void navigator.clipboard.writeText(copyText).then(() => {
|
|
124
|
+
setCopied(true);
|
|
125
|
+
timeoutRef.current = setTimeout(() => setCopied(false), 1e3);
|
|
126
|
+
});
|
|
127
|
+
}, 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" }) })] }) });
|
|
128
|
+
}
|
|
129
|
+
const ELLIPSIS = "…";
|
|
130
|
+
const MIN_START = 3;
|
|
131
|
+
const MIN_END = 3;
|
|
132
|
+
const MIN_KEPT = MIN_START + MIN_END;
|
|
133
|
+
const graphemeSegmenter = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
|
|
134
|
+
function toGraphemes(text) {
|
|
135
|
+
if (graphemeSegmenter) {
|
|
136
|
+
return [...graphemeSegmenter.segment(text)].map((s) => s.segment);
|
|
137
|
+
}
|
|
138
|
+
return Array.from(text);
|
|
139
|
+
}
|
|
140
|
+
function buildCandidate(graphemes, kept) {
|
|
141
|
+
if (kept <= 0) {
|
|
142
|
+
return {
|
|
143
|
+
prefixText: "",
|
|
144
|
+
prefixGraphemeCount: 0,
|
|
145
|
+
suffixText: "",
|
|
146
|
+
suffixGraphemeCount: 0,
|
|
147
|
+
text: ELLIPSIS,
|
|
148
|
+
truncated: true
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const suffixGraphemeCount = kept >= MIN_KEPT ? Math.max(MIN_END, Math.floor(kept / 2)) : Math.floor(kept / 2);
|
|
152
|
+
const prefixGraphemeCount = kept - suffixGraphemeCount;
|
|
153
|
+
const prefixText = graphemes.slice(0, prefixGraphemeCount).join("");
|
|
154
|
+
const suffixText = suffixGraphemeCount > 0 ? graphemes.slice(-suffixGraphemeCount).join("") : "";
|
|
155
|
+
return {
|
|
156
|
+
prefixText,
|
|
157
|
+
prefixGraphemeCount,
|
|
158
|
+
suffixText,
|
|
159
|
+
suffixGraphemeCount,
|
|
160
|
+
text: prefixText + ELLIPSIS + suffixText,
|
|
161
|
+
truncated: true
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function middleTruncate(graphemes, availableWidth, measure, fullWidth) {
|
|
165
|
+
const fullText = graphemes.join("");
|
|
166
|
+
const resolvedFullWidth = fullWidth ?? measure(fullText);
|
|
167
|
+
if (availableWidth <= 0 || graphemes.length === 0) {
|
|
168
|
+
return {
|
|
169
|
+
prefixText: fullText,
|
|
170
|
+
prefixGraphemeCount: graphemes.length,
|
|
171
|
+
suffixText: "",
|
|
172
|
+
suffixGraphemeCount: 0,
|
|
173
|
+
text: fullText,
|
|
174
|
+
truncated: false
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
if (resolvedFullWidth <= availableWidth) {
|
|
178
|
+
return {
|
|
179
|
+
prefixText: fullText,
|
|
180
|
+
prefixGraphemeCount: graphemes.length,
|
|
181
|
+
suffixText: "",
|
|
182
|
+
suffixGraphemeCount: 0,
|
|
183
|
+
text: fullText,
|
|
184
|
+
truncated: false
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
let lo = 0;
|
|
188
|
+
let hi = graphemes.length - 1;
|
|
189
|
+
let best = -1;
|
|
190
|
+
while (lo <= hi) {
|
|
191
|
+
const mid = lo + hi >>> 1;
|
|
192
|
+
const candidate = buildCandidate(graphemes, mid);
|
|
193
|
+
if (measure(candidate.text) <= availableWidth) {
|
|
194
|
+
best = mid;
|
|
195
|
+
lo = mid + 1;
|
|
196
|
+
} else {
|
|
197
|
+
hi = mid - 1;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (best === -1) {
|
|
201
|
+
return {
|
|
202
|
+
prefixText: "",
|
|
203
|
+
prefixGraphemeCount: 0,
|
|
204
|
+
suffixText: "",
|
|
205
|
+
suffixGraphemeCount: 0,
|
|
206
|
+
text: "",
|
|
207
|
+
truncated: true
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
return buildCandidate(graphemes, best);
|
|
211
|
+
}
|
|
212
|
+
function getMiddleTruncateCopyText({ prefixText, selectionEnd, selectionStart, suffixText, value }) {
|
|
213
|
+
const visibleText = prefixText + ELLIPSIS + suffixText;
|
|
214
|
+
if (selectionStart < 0 || selectionEnd > visibleText.length || selectionStart >= selectionEnd) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
if (selectionStart === 0 && selectionEnd === visibleText.length) {
|
|
218
|
+
return value;
|
|
219
|
+
}
|
|
220
|
+
const ellipsisStart = prefixText.length;
|
|
221
|
+
const ellipsisEnd = ellipsisStart + ELLIPSIS.length;
|
|
222
|
+
if (selectionStart > ellipsisStart || selectionEnd < ellipsisEnd) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
const originalGraphemes = toGraphemes(value);
|
|
226
|
+
const selectedPrefixGraphemeCount = toGraphemes(visibleText.slice(0, selectionStart)).length;
|
|
227
|
+
const selectedSuffixGraphemeCount = toGraphemes(visibleText.slice(ellipsisEnd, selectionEnd)).length;
|
|
228
|
+
const suffixStart = originalGraphemes.length - toGraphemes(suffixText).length;
|
|
229
|
+
return originalGraphemes.slice(selectedPrefixGraphemeCount, suffixStart + selectedSuffixGraphemeCount).join("");
|
|
230
|
+
}
|
|
231
|
+
function getMiddleTruncateCopyTextFromSelectionText({ prefixText, selectionText, suffixText, value }) {
|
|
232
|
+
const visibleText = prefixText + ELLIPSIS + suffixText;
|
|
233
|
+
const trimmedSelectionText = selectionText.trim();
|
|
234
|
+
if (!trimmedSelectionText) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
const leading = selectionText.slice(0, selectionText.length - selectionText.trimStart().length);
|
|
238
|
+
const trailing = selectionText.slice(selectionText.trimEnd().length);
|
|
239
|
+
if (trimmedSelectionText === visibleText) {
|
|
240
|
+
return leading + value + trailing;
|
|
241
|
+
}
|
|
242
|
+
if (!trimmedSelectionText.includes(ELLIPSIS)) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
const selectionStart = visibleText.indexOf(trimmedSelectionText);
|
|
246
|
+
if (selectionStart === -1) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
const selectionEnd = selectionStart + trimmedSelectionText.length;
|
|
250
|
+
const mappedText = getMiddleTruncateCopyText({
|
|
251
|
+
prefixText,
|
|
252
|
+
selectionEnd,
|
|
253
|
+
selectionStart,
|
|
254
|
+
suffixText,
|
|
255
|
+
value
|
|
256
|
+
});
|
|
257
|
+
return mappedText === null ? null : leading + mappedText + trailing;
|
|
258
|
+
}
|
|
259
|
+
const useIsomorphicLayoutEffect = typeof window === "undefined" ? reactExports.useEffect : reactExports.useLayoutEffect;
|
|
260
|
+
function createFullState(value, graphemes) {
|
|
261
|
+
return {
|
|
262
|
+
displayText: value,
|
|
263
|
+
isTruncated: false,
|
|
264
|
+
prefixGraphemeCount: graphemes.length,
|
|
265
|
+
prefixText: value,
|
|
266
|
+
suffixGraphemeCount: 0,
|
|
267
|
+
suffixText: ""
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function useMiddleTruncate(value) {
|
|
271
|
+
const graphemes = reactExports.useMemo(() => toGraphemes(value), [value]);
|
|
272
|
+
const fullState = reactExports.useMemo(() => createFullState(value, graphemes), [graphemes, value]);
|
|
273
|
+
const ref = reactExports.useRef(null);
|
|
274
|
+
const measureRef = reactExports.useRef(null);
|
|
275
|
+
const [state, setState] = reactExports.useState(() => fullState);
|
|
276
|
+
const rafRef = reactExports.useRef(0);
|
|
277
|
+
const updateState = reactExports.useCallback((nextState) => {
|
|
278
|
+
setState((currentState) => {
|
|
279
|
+
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) {
|
|
280
|
+
return currentState;
|
|
281
|
+
}
|
|
282
|
+
return nextState;
|
|
283
|
+
});
|
|
284
|
+
}, []);
|
|
285
|
+
const recalculate = reactExports.useCallback(() => {
|
|
286
|
+
const el = ref.current;
|
|
287
|
+
const measureEl = measureRef.current;
|
|
288
|
+
if (!el || !measureEl)
|
|
289
|
+
return;
|
|
290
|
+
const available = el.clientWidth;
|
|
291
|
+
if (available <= 0) {
|
|
292
|
+
updateState(fullState);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const measure = (text) => {
|
|
296
|
+
measureEl.textContent = text;
|
|
297
|
+
return measureEl.scrollWidth;
|
|
298
|
+
};
|
|
299
|
+
const fullWidth = measure(value);
|
|
300
|
+
if (fullWidth <= available) {
|
|
301
|
+
updateState(fullState);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const result = middleTruncate(graphemes, available, measure, fullWidth);
|
|
305
|
+
updateState({
|
|
306
|
+
displayText: result.text,
|
|
307
|
+
isTruncated: result.truncated,
|
|
308
|
+
prefixGraphemeCount: result.prefixGraphemeCount,
|
|
309
|
+
prefixText: result.prefixText,
|
|
310
|
+
suffixGraphemeCount: result.suffixGraphemeCount,
|
|
311
|
+
suffixText: result.suffixText
|
|
312
|
+
});
|
|
313
|
+
}, [fullState, graphemes, updateState, value]);
|
|
314
|
+
useIsomorphicLayoutEffect(() => {
|
|
315
|
+
recalculate();
|
|
316
|
+
}, [recalculate]);
|
|
317
|
+
reactExports.useEffect(() => {
|
|
318
|
+
var _a;
|
|
319
|
+
const el = ref.current;
|
|
320
|
+
if (!el)
|
|
321
|
+
return;
|
|
322
|
+
const debouncedRecalc = () => {
|
|
323
|
+
cancelAnimationFrame(rafRef.current);
|
|
324
|
+
rafRef.current = requestAnimationFrame(recalculate);
|
|
325
|
+
};
|
|
326
|
+
const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(debouncedRecalc) : null;
|
|
327
|
+
ro == null ? void 0 : ro.observe(el);
|
|
328
|
+
window.addEventListener("resize", debouncedRecalc);
|
|
329
|
+
const onFontsLoaded = () => {
|
|
330
|
+
debouncedRecalc();
|
|
331
|
+
};
|
|
332
|
+
const fontSet = "fonts" in document ? document.fonts : null;
|
|
333
|
+
(_a = fontSet == null ? void 0 : fontSet.addEventListener) == null ? void 0 : _a.call(fontSet, "loadingdone", onFontsLoaded);
|
|
334
|
+
return () => {
|
|
335
|
+
var _a2;
|
|
336
|
+
ro == null ? void 0 : ro.disconnect();
|
|
337
|
+
window.removeEventListener("resize", debouncedRecalc);
|
|
338
|
+
cancelAnimationFrame(rafRef.current);
|
|
339
|
+
(_a2 = fontSet == null ? void 0 : fontSet.removeEventListener) == null ? void 0 : _a2.call(fontSet, "loadingdone", onFontsLoaded);
|
|
340
|
+
};
|
|
341
|
+
}, [recalculate]);
|
|
342
|
+
return {
|
|
343
|
+
ref,
|
|
344
|
+
measureRef,
|
|
345
|
+
displayText: state.displayText,
|
|
346
|
+
isTruncated: state.isTruncated,
|
|
347
|
+
prefixGraphemeCount: state.prefixGraphemeCount,
|
|
348
|
+
prefixText: state.prefixText,
|
|
349
|
+
suffixGraphemeCount: state.suffixGraphemeCount,
|
|
350
|
+
suffixText: state.suffixText
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function getRangeOffsets(container, range) {
|
|
354
|
+
if (!container.contains(range.startContainer) || !container.contains(range.endContainer)) {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
const startRange = document.createRange();
|
|
358
|
+
startRange.selectNodeContents(container);
|
|
359
|
+
startRange.setEnd(range.startContainer, range.startOffset);
|
|
360
|
+
const endRange = document.createRange();
|
|
361
|
+
endRange.selectNodeContents(container);
|
|
362
|
+
endRange.setEnd(range.endContainer, range.endOffset);
|
|
363
|
+
return {
|
|
364
|
+
end: endRange.toString().length,
|
|
365
|
+
start: startRange.toString().length
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function MiddleTruncate({ value, className, onCopy: onCopyProp, ...props }) {
|
|
369
|
+
const { ref, measureRef, displayText, isTruncated, prefixText, suffixText } = useMiddleTruncate(value);
|
|
370
|
+
const visibleRef = reactExports.useRef(null);
|
|
371
|
+
const handleCopy = reactExports.useCallback((e) => {
|
|
372
|
+
onCopyProp == null ? void 0 : onCopyProp(e);
|
|
373
|
+
if (e.defaultPrevented || !isTruncated)
|
|
374
|
+
return;
|
|
375
|
+
const selection = window.getSelection();
|
|
376
|
+
if (!selection || selection.rangeCount === 0)
|
|
377
|
+
return;
|
|
378
|
+
const selectionText = selection.toString();
|
|
379
|
+
if (!selectionText)
|
|
380
|
+
return;
|
|
381
|
+
const range = selection.getRangeAt(0);
|
|
382
|
+
const visibleEl = visibleRef.current;
|
|
383
|
+
let copyText = null;
|
|
384
|
+
if (e.currentTarget.contains(range.startContainer) && e.currentTarget.contains(range.endContainer) && visibleEl) {
|
|
385
|
+
const offsets = getRangeOffsets(visibleEl, range);
|
|
386
|
+
if (offsets) {
|
|
387
|
+
copyText = getMiddleTruncateCopyText({
|
|
388
|
+
prefixText,
|
|
389
|
+
selectionEnd: offsets.end,
|
|
390
|
+
selectionStart: offsets.start,
|
|
391
|
+
suffixText,
|
|
392
|
+
value
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
copyText ?? (copyText = getMiddleTruncateCopyTextFromSelectionText({
|
|
397
|
+
prefixText,
|
|
398
|
+
selectionText,
|
|
399
|
+
suffixText,
|
|
400
|
+
value
|
|
401
|
+
}));
|
|
402
|
+
if (copyText === null)
|
|
403
|
+
return;
|
|
404
|
+
e.preventDefault();
|
|
405
|
+
e.clipboardData.setData("text/plain", copyText);
|
|
406
|
+
}, [onCopyProp, isTruncated, prefixText, suffixText, value]);
|
|
407
|
+
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 })] });
|
|
408
|
+
}
|
|
409
|
+
const encryptedPlaceholderPreview = `{
|
|
410
|
+
"input": "[encrypted]",
|
|
411
|
+
"result": "[encrypted]"
|
|
412
|
+
}`;
|
|
413
|
+
function EncryptedDataBlock() {
|
|
414
|
+
const ctx = reactExports.useContext(DecryptClickContext);
|
|
415
|
+
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"] }) })] });
|
|
416
|
+
}
|
|
417
|
+
const serializeForClipboard = (value) => {
|
|
418
|
+
if (typeof value === "string")
|
|
419
|
+
return value;
|
|
420
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null) {
|
|
421
|
+
return String(value);
|
|
422
|
+
}
|
|
423
|
+
try {
|
|
424
|
+
return JSON.stringify(value, null, 2);
|
|
425
|
+
} catch {
|
|
426
|
+
return String(value);
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
function CopyableDataBlock({ data }) {
|
|
430
|
+
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 })] });
|
|
431
|
+
}
|
|
432
|
+
function isReservedAttributeKey(key) {
|
|
433
|
+
return key.startsWith(RESERVED_ATTRIBUTE_KEY_PREFIX);
|
|
434
|
+
}
|
|
435
|
+
const rowValueVariants = cva("min-w-0 flex-1 truncate text-right text-copy-13 text-gray-1000", {
|
|
436
|
+
variants: {
|
|
437
|
+
variant: {
|
|
438
|
+
default: "",
|
|
439
|
+
mono: "font-mono"
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
defaultVariants: {
|
|
443
|
+
variant: "default"
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
const rowCopyValueVariants = cva("flex min-w-0 items-center justify-end gap-1 text-copy-13 text-gray-1000", {
|
|
447
|
+
variants: {
|
|
448
|
+
variant: {
|
|
449
|
+
default: "",
|
|
450
|
+
mono: "font-mono"
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
defaultVariants: {
|
|
454
|
+
variant: "default"
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
function DetailKeyValueRowBase({ label, value, copyText, href, removed = false, variant }) {
|
|
458
|
+
const stringValue = typeof value === "string" ? value : void 0;
|
|
459
|
+
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: [href ? jsxRuntimeExports.jsxs("a", { href, target: "_blank", rel: "noreferrer", className: cn(rowValueVariants({ variant }), "flex min-w-0 items-center gap-0.5 hover:underline"), children: [jsxRuntimeExports.jsx(MiddleTruncate, { value: copyText, className: "min-w-0 text-right", style: { gridTemplateColumns: "minmax(0, 1fr)" } }), jsxRuntimeExports.jsx(ArrowUpRight, { "aria-hidden": true, className: "h-3 w-3 shrink-0" })] }) : 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: href ? jsxRuntimeExports.jsx("a", { href, target: "_blank", rel: "noreferrer", className: "hover:underline", children: value }) : value })] });
|
|
460
|
+
}
|
|
461
|
+
function DetailKeyValueRow(props) {
|
|
462
|
+
return jsxRuntimeExports.jsx(DetailKeyValueRowBase, { ...props });
|
|
463
|
+
}
|
|
464
|
+
function DetailMonoKeyValueRow(props) {
|
|
465
|
+
return jsxRuntimeExports.jsx(DetailKeyValueRowBase, { ...props, variant: "mono" });
|
|
466
|
+
}
|
|
467
|
+
function AttributeRow({ attributeKey, value, removed = false }) {
|
|
468
|
+
return jsxRuntimeExports.jsx(DetailKeyValueRow, { label: attributeKey, value, removed });
|
|
469
|
+
}
|
|
470
|
+
function sortAttributeKeys(keys) {
|
|
471
|
+
return [...keys].sort((a, b) => {
|
|
472
|
+
const aReserved = isReservedAttributeKey(a);
|
|
473
|
+
const bReserved = isReservedAttributeKey(b);
|
|
474
|
+
if (aReserved !== bReserved)
|
|
475
|
+
return aReserved ? 1 : -1;
|
|
476
|
+
return a.localeCompare(b);
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
function RunAttributesCard({ attributes }) {
|
|
480
|
+
const keys = sortAttributeKeys(Object.keys(attributes));
|
|
481
|
+
if (keys.length === 0)
|
|
482
|
+
return null;
|
|
483
|
+
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)) }) })] });
|
|
484
|
+
}
|
|
485
|
+
function formatMetadataValue(value) {
|
|
486
|
+
if (value == null) {
|
|
487
|
+
return String(value);
|
|
488
|
+
}
|
|
489
|
+
if (typeof value === "string") {
|
|
490
|
+
return value;
|
|
491
|
+
}
|
|
492
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
493
|
+
return String(value);
|
|
494
|
+
}
|
|
495
|
+
try {
|
|
496
|
+
return JSON.stringify(value);
|
|
497
|
+
} catch {
|
|
498
|
+
return String(value);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
function isMetadataRecord(value) {
|
|
502
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
503
|
+
}
|
|
504
|
+
function RunMetadataCard({ metadata }) {
|
|
505
|
+
if (!isMetadataRecord(metadata)) {
|
|
506
|
+
return jsxRuntimeExports.jsxs(CollapsibleRoot, { defaultOpen: true, children: [jsxRuntimeExports.jsx(CollapsibleTrigger, { children: "Metadata" }), jsxRuntimeExports.jsx(CollapsibleContent, { className: "mb-4", children: jsxRuntimeExports.jsx(CopyableDataBlock, { data: metadata }) })] });
|
|
507
|
+
}
|
|
508
|
+
const keys = Object.keys(metadata).sort((a, b) => a.localeCompare(b));
|
|
509
|
+
if (keys.length === 0)
|
|
510
|
+
return null;
|
|
511
|
+
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)) }) })] });
|
|
512
|
+
}
|
|
513
|
+
function isAttrSetEventData(data) {
|
|
514
|
+
if (data === null || typeof data !== "object")
|
|
515
|
+
return false;
|
|
516
|
+
const record = data;
|
|
517
|
+
return Array.isArray(record.changes) && record.changes.every((c) => c !== null && typeof c === "object" && typeof c.key === "string");
|
|
518
|
+
}
|
|
519
|
+
function describeWriter(writer) {
|
|
520
|
+
if (!writer)
|
|
521
|
+
return null;
|
|
522
|
+
if (writer.type === "workflow")
|
|
523
|
+
return "Set by workflow";
|
|
524
|
+
if (writer.type === "step") {
|
|
525
|
+
return `Set by step ${writer.stepId} (attempt ${writer.attempt})`;
|
|
526
|
+
}
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
function AttrSetEventBlock({ data }) {
|
|
530
|
+
if (!isAttrSetEventData(data)) {
|
|
531
|
+
return jsxRuntimeExports.jsx(CopyableDataBlock, { data });
|
|
532
|
+
}
|
|
533
|
+
const writerLabel = describeWriter(data.writer);
|
|
534
|
+
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: {
|
|
535
|
+
borderColor: "var(--ds-gray-alpha-400)",
|
|
536
|
+
color: "var(--ds-gray-700)"
|
|
537
|
+
}, children: writerLabel })] });
|
|
538
|
+
}
|
|
43
539
|
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}`;
|
|
44
540
|
function DecryptButton({ decrypted = false, loading = false, onClick }) {
|
|
45
541
|
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"] })] });
|
|
46
542
|
}
|
|
47
|
-
function
|
|
48
|
-
return value != null && typeof value === "object" && "
|
|
543
|
+
function isStructuredError(value) {
|
|
544
|
+
return value != null && typeof value === "object" && (typeof value.message === "string" || typeof value.stack === "string");
|
|
545
|
+
}
|
|
546
|
+
function deriveTitle(message) {
|
|
547
|
+
const firstLine = message.split("\n").find((line) => line.trim().length > 0) ?? message;
|
|
548
|
+
return firstLine.trim();
|
|
49
549
|
}
|
|
50
550
|
function ErrorStackBlock({ value }) {
|
|
51
|
-
const
|
|
52
|
-
const stack = value.stack;
|
|
551
|
+
const stack = typeof value.stack === "string" ? value.stack : void 0;
|
|
53
552
|
const message = typeof value.message === "string" ? value.message : void 0;
|
|
54
|
-
const
|
|
553
|
+
const body = stack ?? message ?? "";
|
|
554
|
+
const title = message ? deriveTitle(message) : deriveTitle(body);
|
|
555
|
+
const copyText = message && stack && !stack.includes(message) ? `${message}
|
|
55
556
|
|
|
56
|
-
${stack}` :
|
|
557
|
+
${stack}` : body;
|
|
57
558
|
return jsxRuntimeExports.jsxs("div", { className: "relative overflow-hidden rounded-md border", style: {
|
|
58
559
|
borderColor: "var(--ds-red-400)",
|
|
59
560
|
background: "var(--ds-red-100)"
|
|
60
|
-
}, children: [jsxRuntimeExports.jsx(
|
|
61
|
-
borderColor: "var(--ds-red-400)",
|
|
62
|
-
background: "var(--ds-red-100)",
|
|
63
|
-
color: "var(--ds-red-900)"
|
|
64
|
-
}, onClick: () => {
|
|
65
|
-
navigator.clipboard.writeText(copyText).then(() => {
|
|
66
|
-
toast2.success("Copied to clipboard");
|
|
67
|
-
}).catch(() => {
|
|
68
|
-
toast2.error("Failed to copy");
|
|
69
|
-
});
|
|
70
|
-
}, children: jsxRuntimeExports.jsx(Copy, { size: 12 }) }), message && jsxRuntimeExports.jsxs("div", { className: "flex items-start gap-2 px-3 py-2.5 pr-10", style: {
|
|
561
|
+
}, 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: {
|
|
71
562
|
color: "var(--ds-red-900)",
|
|
72
563
|
borderBottom: "1px solid var(--ds-red-400)"
|
|
73
|
-
}, children: [jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4 shrink-0"
|
|
564
|
+
}, children: [jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4 shrink-0" }), jsxRuntimeExports.jsx("p", {
|
|
565
|
+
className: "text-xs font-semibold m-0 truncate",
|
|
566
|
+
// The full message or stack is in the body below; the header just
|
|
567
|
+
// shows the first line, single-line, with overflow
|
|
568
|
+
// ellipsised so a long title doesn't push the copy button or
|
|
569
|
+
// wrap into the framed hint/docs lines.
|
|
570
|
+
title: message,
|
|
571
|
+
children: title
|
|
572
|
+
})] }), body && jsxRuntimeExports.jsx("pre", { className: "px-3 py-2.5 text-xs font-mono whitespace-pre-wrap break-words overflow-auto m-0", style: {
|
|
74
573
|
color: "var(--ds-red-900)",
|
|
75
574
|
background: "var(--ds-red-200)"
|
|
76
|
-
}, children:
|
|
575
|
+
}, children: body })] });
|
|
77
576
|
}
|
|
78
577
|
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)}`;
|
|
79
578
|
function LoadMoreButton({ loading = false, onClick, label = "Load more", loadingLabel = "Loading..." }) {
|
|
@@ -118,190 +617,7 @@ function MenuDropdown({ options, value, onChange }) {
|
|
|
118
617
|
setOpen(false);
|
|
119
618
|
}, children: option.label }, option.value)) })] });
|
|
120
619
|
}
|
|
121
|
-
const
|
|
122
|
-
{ unit: "year", ms: 31536e6 },
|
|
123
|
-
{ unit: "month", ms: 2628e6 },
|
|
124
|
-
{ unit: "day", ms: 864e5 },
|
|
125
|
-
{ unit: "hour", ms: 36e5 },
|
|
126
|
-
{ unit: "minute", ms: 6e4 },
|
|
127
|
-
{ unit: "second", ms: 1e3 }
|
|
128
|
-
];
|
|
129
|
-
function formatTimeDifference(diff) {
|
|
130
|
-
let remaining = Math.abs(diff);
|
|
131
|
-
const result = [];
|
|
132
|
-
for (const { unit, ms } of TIME_UNITS) {
|
|
133
|
-
const value = Math.floor(remaining / ms);
|
|
134
|
-
if (value > 0 || result.length > 0) {
|
|
135
|
-
result.push(`${value} ${unit}${value !== 1 ? "s" : ""}`);
|
|
136
|
-
remaining %= ms;
|
|
137
|
-
}
|
|
138
|
-
if (result.length === 3)
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
return result.join(", ");
|
|
142
|
-
}
|
|
143
|
-
function useTimeAgo(date) {
|
|
144
|
-
const [timeAgo, setTimeAgo] = reactExports.useState("");
|
|
145
|
-
reactExports.useEffect(() => {
|
|
146
|
-
const update = () => {
|
|
147
|
-
const diff = Date.now() - date;
|
|
148
|
-
const formatted = formatTimeDifference(diff);
|
|
149
|
-
setTimeAgo(formatted ? `${formatted} ago` : "Just now");
|
|
150
|
-
};
|
|
151
|
-
update();
|
|
152
|
-
const timer = setInterval(update, 1e3);
|
|
153
|
-
return () => clearInterval(timer);
|
|
154
|
-
}, [date]);
|
|
155
|
-
return timeAgo;
|
|
156
|
-
}
|
|
157
|
-
function ZoneDateTimeRow({ date, zone }) {
|
|
158
|
-
var _a;
|
|
159
|
-
const dateObj = new Date(date);
|
|
160
|
-
const formattedZone = ((_a = new Intl.DateTimeFormat("en-US", {
|
|
161
|
-
timeZone: zone,
|
|
162
|
-
timeZoneName: "short"
|
|
163
|
-
}).formatToParts(dateObj).find((part) => part.type === "timeZoneName")) == null ? void 0 : _a.value) || zone;
|
|
164
|
-
const formattedDate = dateObj.toLocaleString("en-US", {
|
|
165
|
-
timeZone: zone,
|
|
166
|
-
year: "numeric",
|
|
167
|
-
month: "long",
|
|
168
|
-
day: "numeric"
|
|
169
|
-
});
|
|
170
|
-
const formattedTime = dateObj.toLocaleTimeString("en-US", {
|
|
171
|
-
timeZone: zone,
|
|
172
|
-
hour: "2-digit",
|
|
173
|
-
minute: "2-digit",
|
|
174
|
-
second: "2-digit"
|
|
175
|
-
});
|
|
176
|
-
return jsxRuntimeExports.jsxs("div", { style: {
|
|
177
|
-
display: "flex",
|
|
178
|
-
alignItems: "center",
|
|
179
|
-
justifyContent: "space-between",
|
|
180
|
-
gap: 12
|
|
181
|
-
}, children: [jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [jsxRuntimeExports.jsx("div", { style: {
|
|
182
|
-
display: "inline-flex",
|
|
183
|
-
alignItems: "center",
|
|
184
|
-
justifyContent: "center",
|
|
185
|
-
height: 16,
|
|
186
|
-
padding: "0 6px",
|
|
187
|
-
backgroundColor: "var(--ds-gray-200)",
|
|
188
|
-
borderRadius: 3,
|
|
189
|
-
fontSize: 11,
|
|
190
|
-
fontFamily: "var(--font-mono, monospace)",
|
|
191
|
-
fontWeight: 500,
|
|
192
|
-
color: "var(--ds-gray-900)",
|
|
193
|
-
whiteSpace: "nowrap"
|
|
194
|
-
}, children: formattedZone }), jsxRuntimeExports.jsx("span", { style: {
|
|
195
|
-
fontSize: 13,
|
|
196
|
-
color: "var(--ds-gray-1000)",
|
|
197
|
-
whiteSpace: "nowrap"
|
|
198
|
-
}, children: formattedDate })] }), jsxRuntimeExports.jsx("span", { style: {
|
|
199
|
-
fontSize: 11,
|
|
200
|
-
fontFamily: "var(--font-mono, monospace)",
|
|
201
|
-
fontVariantNumeric: "tabular-nums",
|
|
202
|
-
color: "var(--ds-gray-900)",
|
|
203
|
-
whiteSpace: "nowrap"
|
|
204
|
-
}, children: formattedTime })] });
|
|
205
|
-
}
|
|
206
|
-
function TimestampTooltipContent({ date }) {
|
|
207
|
-
const localTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
208
|
-
const timeAgo = useTimeAgo(date);
|
|
209
|
-
return jsxRuntimeExports.jsxs("div", { style: {
|
|
210
|
-
display: "flex",
|
|
211
|
-
flexDirection: "column",
|
|
212
|
-
gap: 12,
|
|
213
|
-
minWidth: 300,
|
|
214
|
-
padding: "12px 14px"
|
|
215
|
-
}, children: [jsxRuntimeExports.jsx("span", { style: {
|
|
216
|
-
fontSize: 13,
|
|
217
|
-
fontVariantNumeric: "tabular-nums",
|
|
218
|
-
color: "var(--ds-gray-900)"
|
|
219
|
-
}, children: timeAgo }), jsxRuntimeExports.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [jsxRuntimeExports.jsx(ZoneDateTimeRow, { date, zone: "UTC" }), jsxRuntimeExports.jsx(ZoneDateTimeRow, { date, zone: localTimezone })] })] });
|
|
220
|
-
}
|
|
221
|
-
const TOOLTIP_WIDTH = 330;
|
|
222
|
-
const VIEWPORT_PAD = 8;
|
|
223
|
-
function TooltipPortal({ triggerRect, onMouseEnter, onMouseLeave, date }) {
|
|
224
|
-
const tooltipRef = reactExports.useRef(null);
|
|
225
|
-
const [style, setStyle] = reactExports.useState({
|
|
226
|
-
position: "fixed",
|
|
227
|
-
zIndex: 9999,
|
|
228
|
-
visibility: "hidden"
|
|
229
|
-
});
|
|
230
|
-
reactExports.useEffect(() => {
|
|
231
|
-
const placement = triggerRect.top > 240 ? "above" : "below";
|
|
232
|
-
const centerX = triggerRect.left + triggerRect.width / 2;
|
|
233
|
-
const el = tooltipRef.current;
|
|
234
|
-
const w = el ? el.offsetWidth : TOOLTIP_WIDTH;
|
|
235
|
-
const h = el ? el.offsetHeight : 100;
|
|
236
|
-
let left = centerX - w / 2;
|
|
237
|
-
left = Math.max(VIEWPORT_PAD, Math.min(left, window.innerWidth - w - VIEWPORT_PAD));
|
|
238
|
-
let top;
|
|
239
|
-
if (placement === "above") {
|
|
240
|
-
top = triggerRect.top - h - 6;
|
|
241
|
-
if (top < VIEWPORT_PAD) {
|
|
242
|
-
top = triggerRect.bottom + 6;
|
|
243
|
-
}
|
|
244
|
-
} else {
|
|
245
|
-
top = triggerRect.bottom + 6;
|
|
246
|
-
if (top + h > window.innerHeight - VIEWPORT_PAD) {
|
|
247
|
-
top = triggerRect.top - h - 6;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
setStyle({
|
|
251
|
-
position: "fixed",
|
|
252
|
-
left,
|
|
253
|
-
top,
|
|
254
|
-
zIndex: 9999,
|
|
255
|
-
borderRadius: 10,
|
|
256
|
-
border: "1px solid var(--ds-gray-alpha-200)",
|
|
257
|
-
backgroundColor: "var(--ds-background-100)",
|
|
258
|
-
boxShadow: "0 4px 12px rgba(0,0,0,0.08), 0 1px 3px rgba(0,0,0,0.06)",
|
|
259
|
-
visibility: "visible"
|
|
260
|
-
});
|
|
261
|
-
}, [triggerRect]);
|
|
262
|
-
return reactDomExports.createPortal(
|
|
263
|
-
// biome-ignore lint/a11y/noStaticElementInteractions: tooltip hover zone
|
|
264
|
-
jsxRuntimeExports.jsx("div", { ref: tooltipRef, onMouseEnter, onMouseLeave, style, children: jsxRuntimeExports.jsx(TimestampTooltipContent, { date }) }),
|
|
265
|
-
document.body
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
function TimestampTooltip({ date, children }) {
|
|
269
|
-
const [open, setOpen] = reactExports.useState(false);
|
|
270
|
-
const [triggerRect, setTriggerRect] = reactExports.useState(null);
|
|
271
|
-
const triggerRef = reactExports.useRef(null);
|
|
272
|
-
const closeTimer = reactExports.useRef(null);
|
|
273
|
-
reactExports.useEffect(() => {
|
|
274
|
-
return () => {
|
|
275
|
-
if (closeTimer.current)
|
|
276
|
-
clearTimeout(closeTimer.current);
|
|
277
|
-
};
|
|
278
|
-
}, []);
|
|
279
|
-
const ts = date == null ? null : typeof date === "number" ? date : new Date(date).getTime();
|
|
280
|
-
if (ts == null || Number.isNaN(ts))
|
|
281
|
-
return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children });
|
|
282
|
-
const cancelClose = () => {
|
|
283
|
-
if (closeTimer.current) {
|
|
284
|
-
clearTimeout(closeTimer.current);
|
|
285
|
-
closeTimer.current = null;
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
const scheduleClose = () => {
|
|
289
|
-
cancelClose();
|
|
290
|
-
closeTimer.current = setTimeout(() => setOpen(false), 120);
|
|
291
|
-
};
|
|
292
|
-
const handleOpen = () => {
|
|
293
|
-
cancelClose();
|
|
294
|
-
if (triggerRef.current) {
|
|
295
|
-
setTriggerRect(triggerRef.current.getBoundingClientRect());
|
|
296
|
-
}
|
|
297
|
-
setOpen(true);
|
|
298
|
-
};
|
|
299
|
-
return (
|
|
300
|
-
// biome-ignore lint/a11y/noStaticElementInteractions: tooltip trigger
|
|
301
|
-
jsxRuntimeExports.jsxs("span", { ref: triggerRef, onMouseEnter: handleOpen, onMouseLeave: scheduleClose, style: { display: "inline-flex" }, children: [children, open && triggerRect && jsxRuntimeExports.jsx(TooltipPortal, { triggerRect, onMouseEnter: cancelClose, onMouseLeave: scheduleClose, date: ts })] })
|
|
302
|
-
);
|
|
303
|
-
}
|
|
304
|
-
const ERROR_EVENT_TYPES$1 = /* @__PURE__ */ new Set([
|
|
620
|
+
const ERROR_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
305
621
|
"step_failed",
|
|
306
622
|
"step_retrying",
|
|
307
623
|
"run_failed",
|
|
@@ -322,6 +638,18 @@ function formatEventTime(date) {
|
|
|
322
638
|
hour12: false
|
|
323
639
|
}) + "." + date.getMilliseconds().toString().padStart(3, "0");
|
|
324
640
|
}
|
|
641
|
+
function parseEventDate(value) {
|
|
642
|
+
if (value == null)
|
|
643
|
+
return null;
|
|
644
|
+
const date = value instanceof Date ? value : new Date(String(value));
|
|
645
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
646
|
+
}
|
|
647
|
+
function getEffectiveEventDate$1(event) {
|
|
648
|
+
return parseEventDate(event.occurredAt) ?? new Date(event.createdAt);
|
|
649
|
+
}
|
|
650
|
+
function getEffectiveEventTime(event) {
|
|
651
|
+
return getEffectiveEventDate$1(event).getTime();
|
|
652
|
+
}
|
|
325
653
|
function formatEventType(eventType) {
|
|
326
654
|
return eventType.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
327
655
|
}
|
|
@@ -335,6 +663,9 @@ function getStatusDotColor(eventType) {
|
|
|
335
663
|
if (eventType === "step_retrying") {
|
|
336
664
|
return "var(--ds-amber-700)";
|
|
337
665
|
}
|
|
666
|
+
if (eventType === "attr_set") {
|
|
667
|
+
return "var(--ds-teal-900)";
|
|
668
|
+
}
|
|
338
669
|
if (eventType === "step_completed" || eventType === "run_completed" || eventType === "workflow_completed" || eventType === "hook_disposed" || eventType === "wait_completed") {
|
|
339
670
|
return "var(--ds-green-700)";
|
|
340
671
|
}
|
|
@@ -359,27 +690,34 @@ function buildNameMaps(events, run) {
|
|
|
359
690
|
return { correlationNameMap, workflowName };
|
|
360
691
|
}
|
|
361
692
|
function buildDurationMap(events) {
|
|
693
|
+
const chronological = [...events].sort((a, b) => getEffectiveEventTime(a) - getEffectiveEventTime(b));
|
|
362
694
|
const createdTimes = /* @__PURE__ */ new Map();
|
|
695
|
+
const firstStartedTimes = /* @__PURE__ */ new Map();
|
|
363
696
|
const startedTimes = /* @__PURE__ */ new Map();
|
|
364
697
|
const durations = /* @__PURE__ */ new Map();
|
|
365
|
-
for (const event of
|
|
366
|
-
const ts =
|
|
698
|
+
for (const event of chronological) {
|
|
699
|
+
const ts = getEffectiveEventTime(event);
|
|
367
700
|
const key = event.correlationId ?? "__run__";
|
|
368
701
|
const type = event.eventType;
|
|
369
702
|
if (type === "step_created" || type === "run_created") {
|
|
370
|
-
createdTimes.set(key, ts);
|
|
371
|
-
}
|
|
372
|
-
if (type === "step_started" || type === "run_started" || type === "workflow_started") {
|
|
373
|
-
startedTimes.set(key, ts);
|
|
374
703
|
if (!createdTimes.has(key)) {
|
|
375
704
|
createdTimes.set(key, ts);
|
|
376
705
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
706
|
+
}
|
|
707
|
+
if (type === "step_started" || type === "run_started" || type === "workflow_started") {
|
|
708
|
+
startedTimes.set(key, ts);
|
|
709
|
+
if (!firstStartedTimes.has(key)) {
|
|
710
|
+
firstStartedTimes.set(key, ts);
|
|
711
|
+
if (!createdTimes.has(key)) {
|
|
712
|
+
createdTimes.set(key, ts);
|
|
713
|
+
}
|
|
714
|
+
const createdAt = createdTimes.get(key);
|
|
715
|
+
const info = durations.get(key) ?? {};
|
|
716
|
+
if (createdAt !== void 0) {
|
|
717
|
+
info.queued = ts - createdAt;
|
|
718
|
+
}
|
|
719
|
+
durations.set(key, info);
|
|
381
720
|
}
|
|
382
|
-
durations.set(key, info);
|
|
383
721
|
}
|
|
384
722
|
if (type === "step_completed" || type === "step_failed" || type === "run_completed" || type === "run_failed" || type === "run_cancelled" || type === "workflow_completed" || type === "workflow_failed" || type === "wait_completed" || type === "hook_disposed") {
|
|
385
723
|
const startedAt = startedTimes.get(key);
|
|
@@ -402,7 +740,9 @@ function hasEncryptedValues(data) {
|
|
|
402
740
|
return false;
|
|
403
741
|
}
|
|
404
742
|
function isRunLevel(eventType) {
|
|
405
|
-
return eventType === "run_created" || eventType === "run_started" || eventType === "run_completed" || eventType === "run_failed" || eventType === "run_cancelled" || eventType === "workflow_started" || eventType === "workflow_completed" || eventType === "workflow_failed"
|
|
743
|
+
return eventType === "run_created" || eventType === "run_started" || eventType === "run_completed" || eventType === "run_failed" || eventType === "run_cancelled" || eventType === "workflow_started" || eventType === "workflow_completed" || eventType === "workflow_failed" || // attr_set carries a dedup correlationId rather than a child entity ID,
|
|
744
|
+
// so it groups and labels with the run itself.
|
|
745
|
+
eventType === "attr_set";
|
|
406
746
|
}
|
|
407
747
|
const GUTTER_WIDTH = 36;
|
|
408
748
|
const LANE_X = 20;
|
|
@@ -524,14 +864,14 @@ function deepParseJson(value) {
|
|
|
524
864
|
return value;
|
|
525
865
|
}
|
|
526
866
|
function extractStructuredError(data, eventType) {
|
|
527
|
-
if (!eventType || !ERROR_EVENT_TYPES
|
|
867
|
+
if (!eventType || !ERROR_EVENT_TYPES.has(eventType))
|
|
528
868
|
return null;
|
|
529
869
|
if (data == null || typeof data !== "object")
|
|
530
870
|
return null;
|
|
531
871
|
const record = data;
|
|
532
|
-
if (
|
|
872
|
+
if (isStructuredError(record.error))
|
|
533
873
|
return record.error;
|
|
534
|
-
if (
|
|
874
|
+
if (isStructuredError(record))
|
|
535
875
|
return record;
|
|
536
876
|
return null;
|
|
537
877
|
}
|
|
@@ -570,13 +910,22 @@ function PayloadBlock({ data, eventType }) {
|
|
|
570
910
|
if (structuredError) {
|
|
571
911
|
return jsxRuntimeExports.jsx("div", { className: "p-2", children: jsxRuntimeExports.jsx(ErrorStackBlock, { value: structuredError }) });
|
|
572
912
|
}
|
|
913
|
+
if (eventType === "attr_set") {
|
|
914
|
+
return jsxRuntimeExports.jsx(AttrSetEventBlock, { data: cleaned });
|
|
915
|
+
}
|
|
916
|
+
if (eventType === "run_cancelled") {
|
|
917
|
+
const cancelReason = cleaned != null && typeof cleaned === "object" && typeof cleaned.cancelReason === "string" ? cleaned.cancelReason : null;
|
|
918
|
+
if (cancelReason) {
|
|
919
|
+
return jsxRuntimeExports.jsxs("div", { className: "p-2 text-xs", style: { color: "var(--ds-gray-1000)" }, children: [jsxRuntimeExports.jsx("span", { style: { color: "var(--ds-gray-900)" }, children: "Reason: " }), jsxRuntimeExports.jsx("span", { className: "whitespace-pre-wrap break-words", children: cancelReason })] });
|
|
920
|
+
}
|
|
921
|
+
}
|
|
573
922
|
return jsxRuntimeExports.jsxs("div", { className: "relative group/payload", children: [jsxRuntimeExports.jsx("div", { className: "overflow-x-auto p-2 text-[11px]", style: { color: "var(--ds-gray-1000)" }, children: jsxRuntimeExports.jsx(DataInspector, { data: cleaned, expandLevel: 2 }) }), jsxRuntimeExports.jsx("button", { type: "button", onClick: handleCopy, className: "absolute bottom-2 right-2 opacity-0 group-hover/payload:opacity-100 transition-opacity flex items-center gap-1 px-2 py-1 rounded-md text-xs hover:bg-[var(--ds-gray-alpha-200)]", style: { ...BUTTON_RESET_STYLE, color: "var(--ds-gray-700)" }, "aria-label": "Copy payload", children: copied ? jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(Check, { className: "h-3 w-3", style: { color: "var(--ds-green-700)" } }), jsxRuntimeExports.jsx("span", { style: { color: "var(--ds-green-700)" }, children: "Copied" })] }) : jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(Copy, { className: "h-3 w-3" }), jsxRuntimeExports.jsx("span", { children: "Copy" })] }) })] });
|
|
574
923
|
}
|
|
575
924
|
const SORT_OPTIONS = [
|
|
576
925
|
{ value: "desc", label: "Newest" },
|
|
577
926
|
{ value: "asc", label: "Oldest" }
|
|
578
927
|
];
|
|
579
|
-
function RowsSkeleton() {
|
|
928
|
+
function RowsSkeleton({ showSeparateEventOccurrenceTimestamps = false }) {
|
|
580
929
|
return jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-hidden", children: Array.from({ length: 16 }, (_, i) => jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-0", style: { height: 40 }, children: [jsxRuntimeExports.jsxs("div", { className: "relative flex-shrink-0 self-stretch flex items-center", style: { width: GUTTER_WIDTH }, children: [jsxRuntimeExports.jsx("div", { style: {
|
|
581
930
|
position: "absolute",
|
|
582
931
|
left: 8,
|
|
@@ -588,9 +937,9 @@ function RowsSkeleton() {
|
|
|
588
937
|
height: i % 4 === 0 ? 8 : 6,
|
|
589
938
|
borderRadius: "50%",
|
|
590
939
|
marginLeft: i % 4 === 0 ? 5 : 6
|
|
591
|
-
} })] }), jsxRuntimeExports.jsx("div", { className: "w-5 flex-shrink-0 flex items-center justify-center", children: jsxRuntimeExports.jsx(Skeleton, { className: "w-5 h-5", style: { borderRadius: 4 } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "70%" } }) }), jsxRuntimeExports.jsxs("div", { className: "min-w-0 px-4 flex items-center gap-1.5", style: { flex: "2 1 0%" }, children: [jsxRuntimeExports.jsx(Skeleton, { className: "flex-shrink-0", style: { width: 6, height: 6, borderRadius: "50%" } }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "60%" } })] }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "50%" } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "75%" } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "75%" } }) })] }, i)) });
|
|
940
|
+
} })] }), jsxRuntimeExports.jsx("div", { className: "w-5 flex-shrink-0 flex items-center justify-center", children: jsxRuntimeExports.jsx(Skeleton, { className: "w-5 h-5", style: { borderRadius: 4 } }) }), showSeparateEventOccurrenceTimestamps && jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "70%" } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "70%" } }) }), jsxRuntimeExports.jsxs("div", { className: "min-w-0 px-4 flex items-center gap-1.5", style: { flex: "2 1 0%" }, children: [jsxRuntimeExports.jsx(Skeleton, { className: "flex-shrink-0", style: { width: 6, height: 6, borderRadius: "50%" } }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "60%" } })] }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "50%" } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "75%" } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "75%" } }) })] }, i)) });
|
|
592
941
|
}
|
|
593
|
-
function EventRow$1({ event, index, isFirst, isLast, isExpanded, onToggleExpand, activeGroupKey, selectedGroupKey, selectedGroupRange, correlationNameMap, workflowName, durationMap, onSelectGroup, onHoverGroup, onLoadEventData, cachedEventData, onCacheEventData, encryptionKey, onEncryptedDataDetected }) {
|
|
942
|
+
function EventRow$1({ event, index, isFirst, isLast, isExpanded, onToggleExpand, activeGroupKey, selectedGroupKey, selectedGroupRange, correlationNameMap, workflowName, durationMap, onSelectGroup, onHoverGroup, onLoadEventData, cachedEventData, onCacheEventData, encryptionKey, onEncryptedDataDetected, suppressGroupDimming = false, showSeparateEventOccurrenceTimestamps = false }) {
|
|
594
943
|
const [isLoading, setIsLoading] = reactExports.useState(false);
|
|
595
944
|
const [loadedEventData, setLoadedEventData] = reactExports.useState(cachedEventData);
|
|
596
945
|
const [loadError, setLoadError] = reactExports.useState(null);
|
|
@@ -603,6 +952,8 @@ function EventRow$1({ event, index, isFirst, isLast, isExpanded, onToggleExpand,
|
|
|
603
952
|
const rowGroupKey = isRunLevel(event.eventType) ? "__run__" : event.correlationId ?? void 0;
|
|
604
953
|
const statusDotColor = getStatusDotColor(event.eventType);
|
|
605
954
|
const createdAt = new Date(event.createdAt);
|
|
955
|
+
const occurredAt = parseEventDate(event.occurredAt);
|
|
956
|
+
const displayedCreatedAt = showSeparateEventOccurrenceTimestamps ? createdAt : getEffectiveEventDate$1(event);
|
|
606
957
|
const hasExistingEventData = "eventData" in event && event.eventData != null;
|
|
607
958
|
const isRun = isRunLevel(event.eventType);
|
|
608
959
|
const eventName = isRun ? workflowName ?? "-" : event.correlationId ? correlationNameMap.get(event.correlationId) ?? "-" : "-";
|
|
@@ -610,7 +961,7 @@ function EventRow$1({ event, index, isFirst, isLast, isExpanded, onToggleExpand,
|
|
|
610
961
|
const durationInfo = durationKey ? durationMap.get(durationKey) : void 0;
|
|
611
962
|
const hasActive = activeGroupKey !== void 0;
|
|
612
963
|
const isRelated = rowGroupKey !== void 0 && rowGroupKey === activeGroupKey;
|
|
613
|
-
const isDimmed = hasActive && !isRelated;
|
|
964
|
+
const isDimmed = hasActive && !isRelated && !suppressGroupDimming;
|
|
614
965
|
const isPulsing = hasActive && isRelated;
|
|
615
966
|
const showBranch = hasActive && isRelated && !isRun;
|
|
616
967
|
const showLaneLine = selectedGroupRange !== null && index >= selectedGroupRange.first && index <= selectedGroupRange.last;
|
|
@@ -706,7 +1057,7 @@ function EventRow$1({ event, index, isFirst, isLast, isExpanded, onToggleExpand,
|
|
|
706
1057
|
}, children: jsxRuntimeExports.jsx(ChevronRight, { className: "h-3 w-3 transition-transform", style: {
|
|
707
1058
|
color: "var(--ds-gray-900)",
|
|
708
1059
|
transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)"
|
|
709
|
-
} }) }), jsxRuntimeExports.jsx("div", { className: "tabular-nums min-w-0 px-4", style: { color: "var(--ds-gray-900)", flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(TimestampTooltip, { date:
|
|
1060
|
+
} }) }), showSeparateEventOccurrenceTimestamps && jsxRuntimeExports.jsx("div", { className: "tabular-nums min-w-0 px-4", style: { color: "var(--ds-gray-900)", flex: "2 1 0%" }, children: occurredAt ? jsxRuntimeExports.jsx(TimestampTooltip, { date: occurredAt, children: jsxRuntimeExports.jsx("span", { children: formatEventTime(occurredAt) }) }) : "-" }), jsxRuntimeExports.jsx("div", { className: "tabular-nums min-w-0 px-4", style: { color: "var(--ds-gray-900)", flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(TimestampTooltip, { date: displayedCreatedAt, children: jsxRuntimeExports.jsx("span", { children: formatEventTime(displayedCreatedAt) }) }) }), jsxRuntimeExports.jsx("div", { className: "font-medium min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", style: { color: "var(--ds-gray-900)" }, children: [jsxRuntimeExports.jsxs("span", { style: {
|
|
710
1061
|
position: "relative",
|
|
711
1062
|
display: "inline-flex",
|
|
712
1063
|
width: 6,
|
|
@@ -735,7 +1086,8 @@ function EventRow$1({ event, index, isFirst, isLast, isExpanded, onToggleExpand,
|
|
|
735
1086
|
color: "var(--ds-red-900)"
|
|
736
1087
|
}, children: loadError }) : isLoading || loadedEventData === null && !hasAttemptedLoad && event.correlationId ? jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 p-3", children: [jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "75%" } }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "50%" } }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "60%" } })] }) : jsxRuntimeExports.jsx("div", { className: "p-2 text-xs", style: { color: "var(--ds-gray-900)" }, children: "No data" })] })] })] });
|
|
737
1088
|
}
|
|
738
|
-
function
|
|
1089
|
+
function EventListViewInner({ events, run, onLoadEventData, hasMoreEvents = false, isLoadingMoreEvents = false, onLoadMoreEvents, encryptionKey, isLoading = false, sortOrder: sortOrderProp, onSortOrderChange, onDecrypt, isDecrypting = false, hasEncryptedData: hasEncryptedDataProp = false, onExactIdSearch, showSeparateEventOccurrenceTimestamps = false }) {
|
|
1090
|
+
const toast2 = useToast();
|
|
739
1091
|
const [internalSortOrder, setInternalSortOrder] = reactExports.useState("asc");
|
|
740
1092
|
const effectiveSortOrder = sortOrderProp ?? internalSortOrder;
|
|
741
1093
|
const handleSortOrderChange = reactExports.useCallback((order) => {
|
|
@@ -745,28 +1097,40 @@ function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, is
|
|
|
745
1097
|
setInternalSortOrder(order);
|
|
746
1098
|
}
|
|
747
1099
|
}, [onSortOrderChange]);
|
|
1100
|
+
const [searchQuery, setSearchQuery] = reactExports.useState("");
|
|
1101
|
+
const [searchResults, setSearchResults] = reactExports.useState(null);
|
|
1102
|
+
const [searchResultsTruncated, setSearchResultsTruncated] = reactExports.useState(false);
|
|
1103
|
+
const [searchError, setSearchError] = reactExports.useState(null);
|
|
1104
|
+
const [searchLoading, setSearchLoading] = reactExports.useState(false);
|
|
1105
|
+
const [searchNotFound, setSearchNotFound] = reactExports.useState(false);
|
|
1106
|
+
const searchRequestRef = reactExports.useRef(0);
|
|
1107
|
+
const virtuosoRef = reactExports.useRef(null);
|
|
1108
|
+
const parsedSearchId = reactExports.useMemo(() => parseExactWorkflowSearchId(searchQuery), [searchQuery]);
|
|
1109
|
+
const isExactSearchActive = searchResults !== null;
|
|
748
1110
|
const sortedEvents = reactExports.useMemo(() => {
|
|
749
|
-
|
|
1111
|
+
const sourceEvents = isExactSearchActive ? searchResults : events ?? [];
|
|
1112
|
+
if (sourceEvents.length === 0)
|
|
750
1113
|
return [];
|
|
751
1114
|
const dir = effectiveSortOrder === "desc" ? -1 : 1;
|
|
752
|
-
return [...
|
|
753
|
-
}, [events, effectiveSortOrder]);
|
|
1115
|
+
return [...sourceEvents].sort((a, b) => dir * (getEffectiveEventTime(a) - getEffectiveEventTime(b)));
|
|
1116
|
+
}, [events, effectiveSortOrder, isExactSearchActive, searchResults]);
|
|
754
1117
|
const hasEncryptedInlineData = reactExports.useMemo(() => {
|
|
755
|
-
|
|
1118
|
+
const sourceEvents = isExactSearchActive ? searchResults : events;
|
|
1119
|
+
if (!sourceEvents)
|
|
756
1120
|
return false;
|
|
757
|
-
for (const event of
|
|
1121
|
+
for (const event of sourceEvents) {
|
|
758
1122
|
const ed = event.eventData;
|
|
759
1123
|
if (hasEncryptedValues(ed))
|
|
760
1124
|
return true;
|
|
761
1125
|
}
|
|
762
1126
|
return false;
|
|
763
|
-
}, [events]);
|
|
1127
|
+
}, [events, isExactSearchActive, searchResults]);
|
|
764
1128
|
const [foundEncryptedInLazyData, setFoundEncryptedInLazyData] = reactExports.useState(false);
|
|
765
1129
|
const handleEncryptedDataDetected = reactExports.useCallback(() => {
|
|
766
1130
|
setFoundEncryptedInLazyData(true);
|
|
767
1131
|
}, []);
|
|
768
1132
|
const hasEncryptedData = hasEncryptedDataProp || hasEncryptedInlineData || foundEncryptedInLazyData;
|
|
769
|
-
const { correlationNameMap, workflowName } = reactExports.useMemo(() => buildNameMaps(events ?? null, run ?? null), [events, run]);
|
|
1133
|
+
const { correlationNameMap, workflowName } = reactExports.useMemo(() => buildNameMaps(isExactSearchActive ? searchResults : events ?? null, run ?? null), [events, isExactSearchActive, run, searchResults]);
|
|
770
1134
|
const durationMap = reactExports.useMemo(() => buildDurationMap(sortedEvents), [sortedEvents]);
|
|
771
1135
|
const [selectedGroupKey, setSelectedGroupKey] = reactExports.useState(void 0);
|
|
772
1136
|
const [hoveredGroupKey, setHoveredGroupKey] = reactExports.useState(void 0);
|
|
@@ -834,58 +1198,100 @@ function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, is
|
|
|
834
1198
|
}
|
|
835
1199
|
return first >= 0 ? { first, last } : null;
|
|
836
1200
|
}, [activeGroupKey, sortedEvents]);
|
|
837
|
-
const [searchQuery, setSearchQuery] = reactExports.useState("");
|
|
838
|
-
const virtuosoRef = reactExports.useRef(null);
|
|
839
|
-
const searchIndex = reactExports.useMemo(() => {
|
|
840
|
-
const entries = [];
|
|
841
|
-
for (let i = 0; i < sortedEvents.length; i++) {
|
|
842
|
-
const ev = sortedEvents[i];
|
|
843
|
-
const isRun = isRunLevel(ev.eventType);
|
|
844
|
-
const name = isRun ? workflowName ?? "" : ev.correlationId ? correlationNameMap.get(ev.correlationId) ?? "" : "";
|
|
845
|
-
entries.push({
|
|
846
|
-
fields: [
|
|
847
|
-
ev.eventId,
|
|
848
|
-
ev.correlationId ?? "",
|
|
849
|
-
ev.eventType,
|
|
850
|
-
formatEventType(ev.eventType),
|
|
851
|
-
name
|
|
852
|
-
].map((f) => f.toLowerCase()),
|
|
853
|
-
groupKey: ev.correlationId ?? (isRun ? "__run__" : void 0),
|
|
854
|
-
eventId: ev.eventId,
|
|
855
|
-
index: i
|
|
856
|
-
});
|
|
857
|
-
}
|
|
858
|
-
return entries;
|
|
859
|
-
}, [sortedEvents, correlationNameMap, workflowName]);
|
|
860
1201
|
reactExports.useEffect(() => {
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1202
|
+
const trimmed = searchQuery.trim();
|
|
1203
|
+
if (!trimmed) {
|
|
1204
|
+
searchRequestRef.current += 1;
|
|
1205
|
+
setSearchResults(null);
|
|
1206
|
+
setSearchResultsTruncated(false);
|
|
1207
|
+
setSearchError(null);
|
|
1208
|
+
setSearchLoading(false);
|
|
1209
|
+
setSearchNotFound(false);
|
|
864
1210
|
setSelectedGroupKey(void 0);
|
|
865
1211
|
return;
|
|
866
1212
|
}
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1213
|
+
const parsed = parseExactWorkflowSearchId(trimmed);
|
|
1214
|
+
if (!parsed || !onExactIdSearch) {
|
|
1215
|
+
setSearchResults(null);
|
|
1216
|
+
setSearchLoading(false);
|
|
1217
|
+
setSearchNotFound(false);
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
const requestId = ++searchRequestRef.current;
|
|
1221
|
+
setSearchLoading(true);
|
|
1222
|
+
setSearchNotFound(false);
|
|
1223
|
+
setSearchError(null);
|
|
1224
|
+
const abortController = new AbortController();
|
|
1225
|
+
const timer = setTimeout(() => {
|
|
1226
|
+
void (async () => {
|
|
1227
|
+
var _a;
|
|
1228
|
+
try {
|
|
1229
|
+
const results = await onExactIdSearch(parsed.id, parsed.kind, abortController.signal);
|
|
1230
|
+
if (abortController.signal.aborted || searchRequestRef.current !== requestId) {
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1233
|
+
if (results.status === "error") {
|
|
1234
|
+
setSearchResults([]);
|
|
1235
|
+
setSearchResultsTruncated(false);
|
|
1236
|
+
setSearchNotFound(false);
|
|
1237
|
+
setSearchError(results.message);
|
|
1238
|
+
setSelectedGroupKey(void 0);
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
if (results.status === "not_found" || results.status === "ok" && results.events.length === 0) {
|
|
1242
|
+
setSearchResults([]);
|
|
1243
|
+
setSearchResultsTruncated(false);
|
|
1244
|
+
setSearchNotFound(true);
|
|
1245
|
+
setSearchError(null);
|
|
1246
|
+
setSelectedGroupKey(void 0);
|
|
1247
|
+
return;
|
|
1248
|
+
}
|
|
1249
|
+
setSearchResults(results.events);
|
|
1250
|
+
setSearchResultsTruncated(Boolean(results.truncated));
|
|
1251
|
+
setSearchNotFound(false);
|
|
1252
|
+
setSearchError(null);
|
|
1253
|
+
setSelectedGroupKey(parsed.kind === "event" ? (() => {
|
|
1254
|
+
const first = results.events[0];
|
|
1255
|
+
if (!first)
|
|
1256
|
+
return void 0;
|
|
1257
|
+
return isRunLevel(first.eventType) ? "__run__" : first.correlationId ?? void 0;
|
|
1258
|
+
})() : parsed.id);
|
|
1259
|
+
(_a = virtuosoRef.current) == null ? void 0 : _a.scrollToIndex({
|
|
1260
|
+
index: 0,
|
|
1261
|
+
align: "start",
|
|
1262
|
+
behavior: "smooth"
|
|
1263
|
+
});
|
|
1264
|
+
} catch {
|
|
1265
|
+
if (abortController.signal.aborted || searchRequestRef.current !== requestId) {
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
setSearchResults([]);
|
|
1269
|
+
setSearchResultsTruncated(false);
|
|
1270
|
+
setSearchNotFound(false);
|
|
1271
|
+
setSearchError("Failed to search events. Try again.");
|
|
1272
|
+
setSelectedGroupKey(void 0);
|
|
1273
|
+
} finally {
|
|
1274
|
+
if (searchRequestRef.current === requestId && !abortController.signal.aborted) {
|
|
1275
|
+
setSearchLoading(false);
|
|
876
1276
|
}
|
|
877
1277
|
}
|
|
878
|
-
}
|
|
1278
|
+
})();
|
|
1279
|
+
}, 300);
|
|
1280
|
+
return () => {
|
|
1281
|
+
clearTimeout(timer);
|
|
1282
|
+
abortController.abort();
|
|
1283
|
+
};
|
|
1284
|
+
}, [searchQuery, onExactIdSearch]);
|
|
1285
|
+
const handleSearchKeyDown = reactExports.useCallback((event) => {
|
|
1286
|
+
if (event.key !== "Enter") {
|
|
1287
|
+
return;
|
|
879
1288
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
index: bestMatch.index,
|
|
884
|
-
align: "center",
|
|
885
|
-
behavior: "smooth"
|
|
886
|
-
});
|
|
1289
|
+
const trimmed = searchQuery.trim();
|
|
1290
|
+
if (!trimmed || parseExactWorkflowSearchId(trimmed) || !onExactIdSearch || !looksLikeWorkflowIdSearchInput(trimmed)) {
|
|
1291
|
+
return;
|
|
887
1292
|
}
|
|
888
|
-
|
|
1293
|
+
toast2.info("Enter a full step ID, wait ID, hook ID, or event ID");
|
|
1294
|
+
}, [searchQuery, onExactIdSearch, toast2]);
|
|
889
1295
|
const hasHadEventsRef = reactExports.useRef(false);
|
|
890
1296
|
if (sortedEvents.length > 0) {
|
|
891
1297
|
hasHadEventsRef.current = true;
|
|
@@ -895,9 +1301,6 @@ function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, is
|
|
|
895
1301
|
if (isInitialLoad) {
|
|
896
1302
|
return jsxRuntimeExports.jsxs("div", { className: "h-full flex flex-col overflow-hidden", children: [jsxRuntimeExports.jsx("div", { style: { padding: 6 }, children: jsxRuntimeExports.jsx(Skeleton, { style: { height: 40, borderRadius: 6 } }) }), jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-0 h-10 border-b flex-shrink-0", style: { borderColor: "var(--ds-gray-alpha-200)" }, children: [jsxRuntimeExports.jsx("div", { className: "flex-shrink-0", style: { width: GUTTER_WIDTH } }), jsxRuntimeExports.jsx("div", { className: "w-5 flex-shrink-0" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: 40 } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: 72 } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: 44 } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: 92 } }) }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: 60 } }) })] }), jsxRuntimeExports.jsx(RowsSkeleton, {})] });
|
|
897
1303
|
}
|
|
898
|
-
if (!isLoading && (!events || events.length === 0)) {
|
|
899
|
-
return jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-full text-sm", style: { color: "var(--ds-gray-700)" }, children: "No events found" });
|
|
900
|
-
}
|
|
901
1304
|
return jsxRuntimeExports.jsx(DecryptClickContext.Provider, { value: onDecrypt ? { onDecrypt, isDecrypting } : void 0, children: jsxRuntimeExports.jsxs("div", { className: "h-full flex flex-col overflow-hidden", children: [jsxRuntimeExports.jsx("style", { children: `@keyframes workflow-dot-pulse{0%{transform:scale(1);opacity:.7}70%,100%{transform:scale(2.2);opacity:0}}` }), jsxRuntimeExports.jsxs("div", { style: {
|
|
902
1305
|
padding: 6,
|
|
903
1306
|
backgroundColor: "var(--ds-background-100)",
|
|
@@ -921,7 +1324,7 @@ function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, is
|
|
|
921
1324
|
justifyContent: "center",
|
|
922
1325
|
color: "var(--ds-gray-800)",
|
|
923
1326
|
flexShrink: 0
|
|
924
|
-
}, children: jsxRuntimeExports.jsxs("svg", { width: 16, height: 16, viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", focusable: "false", children: [jsxRuntimeExports.jsx("circle", { cx: "7", cy: "7", r: "4.5", stroke: "currentColor", strokeWidth: "1.5" }), jsxRuntimeExports.jsx("path", { d: "M11.5 11.5L14 14", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })] }) }), jsxRuntimeExports.jsx("input", { type: "search", placeholder: "Search by
|
|
1327
|
+
}, children: jsxRuntimeExports.jsxs("svg", { width: 16, height: 16, viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", focusable: "false", children: [jsxRuntimeExports.jsx("circle", { cx: "7", cy: "7", r: "4.5", stroke: "currentColor", strokeWidth: "1.5" }), jsxRuntimeExports.jsx("path", { d: "M11.5 11.5L14 14", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })] }) }), jsxRuntimeExports.jsx("input", { type: "search", placeholder: "Search by step ID, wait ID, hook ID, or event ID…", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onKeyDown: handleSearchKeyDown, disabled: !onExactIdSearch, title: onExactIdSearch ? void 0 : "Exact ID search is unavailable in this view.", style: {
|
|
925
1328
|
marginLeft: -16,
|
|
926
1329
|
paddingInline: 12,
|
|
927
1330
|
fontFamily: "inherit",
|
|
@@ -930,27 +1333,58 @@ function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, is
|
|
|
930
1333
|
border: "none",
|
|
931
1334
|
outline: "none",
|
|
932
1335
|
height: 40,
|
|
933
|
-
width: "100%"
|
|
1336
|
+
width: "100%",
|
|
1337
|
+
opacity: onExactIdSearch ? 1 : 0.5,
|
|
1338
|
+
cursor: onExactIdSearch ? "text" : "not-allowed"
|
|
934
1339
|
} })] }), jsxRuntimeExports.jsx(MenuDropdown, { options: SORT_OPTIONS, value: effectiveSortOrder, onChange: handleSortOrderChange }), (hasEncryptedData || encryptionKey) && onDecrypt && jsxRuntimeExports.jsx(DecryptButton, { decrypted: !!encryptionKey, loading: isDecrypting, onClick: onDecrypt })] }), jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-0 text-[13px] font-medium h-10 border-b flex-shrink-0", style: {
|
|
935
1340
|
borderColor: "var(--ds-gray-alpha-200)",
|
|
936
1341
|
color: "var(--ds-gray-900)",
|
|
937
1342
|
backgroundColor: "var(--ds-background-100)"
|
|
938
|
-
}, children: [jsxRuntimeExports.jsx("div", { className: "flex-shrink-0", style: { width: GUTTER_WIDTH } }), jsxRuntimeExports.jsx("div", { className: "w-5 flex-shrink-0" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: "
|
|
939
|
-
if (!hasMoreEvents || isLoadingMoreEvents) {
|
|
1343
|
+
}, children: [jsxRuntimeExports.jsx("div", { className: "flex-shrink-0", style: { width: GUTTER_WIDTH } }), jsxRuntimeExports.jsx("div", { className: "w-5 flex-shrink-0" }), showSeparateEventOccurrenceTimestamps && jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: "Occurred" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: "Created" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: "Event Type" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "2 1 0%" }, children: "Name" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: "Correlation ID" }), jsxRuntimeExports.jsx("div", { className: "min-w-0 px-4", style: { flex: "3 1 0%" }, children: "Event ID" })] }), isRefetching || searchLoading ? jsxRuntimeExports.jsx(RowsSkeleton, { showSeparateEventOccurrenceTimestamps }) : sortedEvents.length === 0 ? jsxRuntimeExports.jsx("div", { className: "flex flex-1 items-center justify-center px-6 text-center text-sm", style: { color: "var(--ds-gray-700)" }, children: searchNotFound && searchQuery.trim() ? `No events found for ${searchQuery.trim()}` : searchError ? searchError : parsedSearchId && searchQuery.trim() && !onExactIdSearch ? "Exact ID search is unavailable in this view." : "No events found" }) : jsxRuntimeExports.jsx(Yr, { ref: virtuosoRef, totalCount: sortedEvents.length, overscan: 20, defaultItemHeight: 40, endReached: () => {
|
|
1344
|
+
if (isExactSearchActive || !hasMoreEvents || isLoadingMoreEvents) {
|
|
940
1345
|
return;
|
|
941
1346
|
}
|
|
942
1347
|
void (onLoadMoreEvents == null ? void 0 : onLoadMoreEvents());
|
|
943
1348
|
}, itemContent: (index) => {
|
|
944
1349
|
const ev = sortedEvents[index];
|
|
945
|
-
return jsxRuntimeExports.jsx(EventRow$1, { event: ev, index, isFirst: index === 0, isLast: index === sortedEvents.length - 1, isExpanded: expandedEventIds.has(ev.eventId), onToggleExpand: toggleEventExpanded, activeGroupKey, selectedGroupKey, selectedGroupRange, correlationNameMap, workflowName, durationMap, onSelectGroup, onHoverGroup, onLoadEventData, cachedEventData: eventDataCacheRef.current.get(ev.eventId) ?? null, onCacheEventData: cacheEventData, encryptionKey, onEncryptedDataDetected: handleEncryptedDataDetected });
|
|
1350
|
+
return jsxRuntimeExports.jsx(EventRow$1, { event: ev, index, isFirst: index === 0, isLast: index === sortedEvents.length - 1, isExpanded: expandedEventIds.has(ev.eventId), onToggleExpand: toggleEventExpanded, activeGroupKey, selectedGroupKey, selectedGroupRange, correlationNameMap, workflowName, durationMap, onSelectGroup, onHoverGroup, onLoadEventData, cachedEventData: eventDataCacheRef.current.get(ev.eventId) ?? null, onCacheEventData: cacheEventData, encryptionKey, onEncryptedDataDetected: handleEncryptedDataDetected, suppressGroupDimming: isExactSearchActive, showSeparateEventOccurrenceTimestamps });
|
|
946
1351
|
}, style: { flex: 1, minHeight: 0 } }), jsxRuntimeExports.jsxs("div", { className: "relative flex-shrink-0 flex items-center h-10 border-t px-4 text-xs", style: {
|
|
947
1352
|
borderColor: "var(--ds-gray-alpha-200)",
|
|
948
1353
|
color: "var(--ds-gray-900)",
|
|
949
1354
|
backgroundColor: "var(--ds-background-100)"
|
|
950
|
-
}, children: [jsxRuntimeExports.
|
|
1355
|
+
}, children: [jsxRuntimeExports.jsx("span", { children: isExactSearchActive ? searchError ? searchError : searchNotFound ? `No events found for ${searchQuery.trim()}` : `${sortedEvents.length} event${sortedEvents.length !== 1 ? "s" : ""} for ${searchQuery.trim()}${searchResultsTruncated ? " (results may be truncated)" : ""}` : `${sortedEvents.length} event${sortedEvents.length !== 1 ? "s" : ""} loaded` }), !isExactSearchActive && hasMoreEvents && jsxRuntimeExports.jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: jsxRuntimeExports.jsx("div", { className: "pointer-events-auto", children: jsxRuntimeExports.jsx(LoadMoreButton, { loading: isLoadingMoreEvents, onClick: () => void (onLoadMoreEvents == null ? void 0 : onLoadMoreEvents()) }) }) })] })] }) });
|
|
1356
|
+
}
|
|
1357
|
+
function EventListView(props) {
|
|
1358
|
+
return jsxRuntimeExports.jsx(ContextCardProvider, { children: jsxRuntimeExports.jsx(EventListViewInner, { ...props }) });
|
|
1359
|
+
}
|
|
1360
|
+
const GUTTER_PX = 1;
|
|
1361
|
+
const MIN_PX = 50;
|
|
1362
|
+
const DEFAULT_START_PX = 340;
|
|
1363
|
+
function paneColTemplate(startPx) {
|
|
1364
|
+
return `${startPx}px ${GUTTER_PX}px minmax(${MIN_PX}px, 1fr)`;
|
|
1365
|
+
}
|
|
1366
|
+
const COL_TEMPLATE = paneColTemplate(DEFAULT_START_PX);
|
|
1367
|
+
const ROWS = [
|
|
1368
|
+
{ id: "r0", name: 62, off: 0, bar: 72 },
|
|
1369
|
+
{ id: "r1", name: 78, off: 6, bar: 48 },
|
|
1370
|
+
{ id: "r2", name: 50, off: 10, bar: 55 },
|
|
1371
|
+
{ id: "r3", name: 84, off: 18, bar: 30 },
|
|
1372
|
+
{ id: "r4", name: 45, off: 18, bar: 42 },
|
|
1373
|
+
{ id: "r5", name: 66, off: 34, bar: 38 },
|
|
1374
|
+
{ id: "r6", name: 55, off: 41, bar: 25 },
|
|
1375
|
+
{ id: "r7", name: 40, off: 50, bar: 30 }
|
|
1376
|
+
];
|
|
1377
|
+
const HEADER_MARKERS = ["m0", "m1", "m2", "m3"];
|
|
1378
|
+
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" }) });
|
|
1379
|
+
function TraceViewerSkeleton() {
|
|
1380
|
+
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: {
|
|
1381
|
+
left: `${row.off}%`,
|
|
1382
|
+
width: `${row.bar}%`,
|
|
1383
|
+
top: index * 3.5
|
|
1384
|
+
} }, 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)) })] })] });
|
|
951
1385
|
}
|
|
952
1386
|
function shouldShowVerticalLine(eventType) {
|
|
953
|
-
if (eventType
|
|
1387
|
+
if (isHookLifecycleEventType(eventType)) {
|
|
954
1388
|
return true;
|
|
955
1389
|
}
|
|
956
1390
|
return false;
|
|
@@ -1001,12 +1435,20 @@ const MARKER_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
|
1001
1435
|
"step_failed",
|
|
1002
1436
|
"run_failed",
|
|
1003
1437
|
"wait_created",
|
|
1004
|
-
"wait_completed"
|
|
1438
|
+
"wait_completed",
|
|
1439
|
+
"attr_set"
|
|
1005
1440
|
]);
|
|
1006
|
-
|
|
1441
|
+
const getEventTimestamp = (event) => {
|
|
1442
|
+
const value = (event == null ? void 0 : event.occurredAt) ?? (event == null ? void 0 : event.createdAt);
|
|
1443
|
+
if (!value)
|
|
1444
|
+
return void 0;
|
|
1445
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
1446
|
+
return Number.isNaN(date.getTime()) ? void 0 : date;
|
|
1447
|
+
};
|
|
1448
|
+
function convertEventsToSpanEvents(events, filterTypes = true, options = {}) {
|
|
1007
1449
|
return events.filter((event) => filterTypes ? MARKER_EVENT_TYPES.has(event.eventType) : true).map((event) => ({
|
|
1008
1450
|
name: event.eventType,
|
|
1009
|
-
timestamp: dateToOtelTime(event.createdAt),
|
|
1451
|
+
timestamp: dateToOtelTime(options.preferOccurredAt ? getEventTimestamp(event) ?? event.createdAt : event.createdAt),
|
|
1010
1452
|
attributes: {
|
|
1011
1453
|
eventId: event.eventId,
|
|
1012
1454
|
correlationId: event.correlationId,
|
|
@@ -1026,18 +1468,23 @@ const waitEventsToWaitEntity = (events) => {
|
|
|
1026
1468
|
return {
|
|
1027
1469
|
waitId: startEvent.correlationId,
|
|
1028
1470
|
runId: startEvent.runId,
|
|
1029
|
-
createdAt: startEvent.createdAt,
|
|
1030
|
-
resumeAt: (_a = startEvent.eventData) == null ? void 0 : _a.resumeAt,
|
|
1031
|
-
completedAt: completedEvent
|
|
1471
|
+
createdAt: getEventTimestamp(startEvent) ?? startEvent.createdAt,
|
|
1472
|
+
resumeAt: ((_a = startEvent.eventData) == null ? void 0 : _a.resumeAt) ? new Date(startEvent.eventData.resumeAt) : void 0,
|
|
1473
|
+
completedAt: getEventTimestamp(completedEvent)
|
|
1032
1474
|
};
|
|
1033
1475
|
};
|
|
1034
|
-
function waitToSpan(events, maxEndTime) {
|
|
1476
|
+
function waitToSpan(events, maxEndTime, fallbackEndTime = maxEndTime) {
|
|
1035
1477
|
const wait = waitEventsToWaitEntity(events);
|
|
1036
1478
|
if (!wait) {
|
|
1037
1479
|
return null;
|
|
1038
1480
|
}
|
|
1039
1481
|
const startTime = wait.createdAt;
|
|
1040
|
-
const
|
|
1482
|
+
const startMs = startTime.getTime();
|
|
1483
|
+
let endTime = wait.completedAt;
|
|
1484
|
+
if (!endTime) {
|
|
1485
|
+
const fallbackCap = wait.resumeAt && wait.resumeAt.getTime() < fallbackEndTime.getTime() ? wait.resumeAt : fallbackEndTime;
|
|
1486
|
+
endTime = maxEndTime.getTime() > startMs && maxEndTime.getTime() < fallbackCap.getTime() ? maxEndTime : fallbackCap;
|
|
1487
|
+
}
|
|
1041
1488
|
const start = dateToOtelTime(startTime);
|
|
1042
1489
|
const end = dateToOtelTime(endTime);
|
|
1043
1490
|
const duration = calculateDuration(startTime, endTime);
|
|
@@ -1080,16 +1527,16 @@ const stepEventsToStepEntity = (events) => {
|
|
|
1080
1527
|
status = "running";
|
|
1081
1528
|
attempt += 1;
|
|
1082
1529
|
if (!startedAt)
|
|
1083
|
-
startedAt = e.createdAt;
|
|
1530
|
+
startedAt = getEventTimestamp(e) ?? e.createdAt;
|
|
1084
1531
|
completedAt = void 0;
|
|
1085
1532
|
break;
|
|
1086
1533
|
case "step_completed":
|
|
1087
1534
|
status = "completed";
|
|
1088
|
-
completedAt = e.createdAt;
|
|
1535
|
+
completedAt = getEventTimestamp(e) ?? e.createdAt;
|
|
1089
1536
|
break;
|
|
1090
1537
|
case "step_failed":
|
|
1091
1538
|
status = "failed";
|
|
1092
|
-
completedAt = e.createdAt;
|
|
1539
|
+
completedAt = getEventTimestamp(e) ?? e.createdAt;
|
|
1093
1540
|
break;
|
|
1094
1541
|
case "step_retrying":
|
|
1095
1542
|
status = "pending";
|
|
@@ -1106,8 +1553,8 @@ const stepEventsToStepEntity = (events) => {
|
|
|
1106
1553
|
stepName: ((_a = createdEvent == null ? void 0 : createdEvent.eventData) == null ? void 0 : _a.stepName) ?? "",
|
|
1107
1554
|
status,
|
|
1108
1555
|
attempt,
|
|
1109
|
-
createdAt: anchorEvent.createdAt,
|
|
1110
|
-
updatedAt: (lastEvent == null ? void 0 : lastEvent.createdAt) ?? anchorEvent.createdAt,
|
|
1556
|
+
createdAt: getEventTimestamp(anchorEvent) ?? anchorEvent.createdAt,
|
|
1557
|
+
updatedAt: getEventTimestamp(lastEvent) ?? (lastEvent == null ? void 0 : lastEvent.createdAt) ?? anchorEvent.createdAt,
|
|
1111
1558
|
startedAt,
|
|
1112
1559
|
completedAt,
|
|
1113
1560
|
specVersion: anchorEvent.specVersion
|
|
@@ -1124,13 +1571,20 @@ function stepToSpan(stepEvents, maxEndTime) {
|
|
|
1124
1571
|
data: step
|
|
1125
1572
|
};
|
|
1126
1573
|
const resource = "step";
|
|
1127
|
-
const
|
|
1128
|
-
|
|
1129
|
-
|
|
1574
|
+
const events = convertEventsToSpanEvents(stepEvents, false, {
|
|
1575
|
+
preferOccurredAt: true
|
|
1576
|
+
});
|
|
1577
|
+
const spanStartEvent = stepEvents.find((event) => event.eventType === "step_created") ?? stepEvents[0];
|
|
1578
|
+
const spanStartTime = getEventTimestamp(spanStartEvent) ?? new Date(step.createdAt);
|
|
1130
1579
|
let activeStartTime = step.startedAt ? new Date(step.startedAt) : void 0;
|
|
1131
1580
|
const firstStartEvent = stepEvents.find((event) => event.eventType === "step_started");
|
|
1132
1581
|
if (firstStartEvent) {
|
|
1133
|
-
activeStartTime = new Date(firstStartEvent.createdAt);
|
|
1582
|
+
activeStartTime = getEventTimestamp(firstStartEvent) ?? new Date(firstStartEvent.createdAt);
|
|
1583
|
+
}
|
|
1584
|
+
let endTime = new Date(maxEndTime);
|
|
1585
|
+
if (step.completedAt) {
|
|
1586
|
+
const completedEvent = stepEvents.slice().reverse().find((event) => isTerminalStepEventType(event.eventType));
|
|
1587
|
+
endTime = getEventTimestamp(completedEvent) ?? new Date(step.completedAt);
|
|
1134
1588
|
}
|
|
1135
1589
|
return {
|
|
1136
1590
|
spanId: String(step.stepId),
|
|
@@ -1152,7 +1606,7 @@ function stepToSpan(stepEvents, maxEndTime) {
|
|
|
1152
1606
|
};
|
|
1153
1607
|
}
|
|
1154
1608
|
const hookEventsToHookEntity = (events) => {
|
|
1155
|
-
var _a
|
|
1609
|
+
var _a;
|
|
1156
1610
|
const createdEvent = events.find((event) => event.eventType === "hook_created");
|
|
1157
1611
|
if (!createdEvent) {
|
|
1158
1612
|
return null;
|
|
@@ -1164,10 +1618,10 @@ const hookEventsToHookEntity = (events) => {
|
|
|
1164
1618
|
hookId: createdEvent.correlationId,
|
|
1165
1619
|
runId: createdEvent.runId,
|
|
1166
1620
|
token: (_a = createdEvent.eventData) == null ? void 0 : _a.token,
|
|
1167
|
-
createdAt: createdEvent.createdAt,
|
|
1621
|
+
createdAt: getEventTimestamp(createdEvent) ?? createdEvent.createdAt,
|
|
1168
1622
|
receivedCount: receivedEvents.length,
|
|
1169
|
-
lastReceivedAt: (lastReceivedEvent
|
|
1170
|
-
disposedAt: (
|
|
1623
|
+
lastReceivedAt: getEventTimestamp(lastReceivedEvent),
|
|
1624
|
+
disposedAt: getEventTimestamp(disposedEvents.at(-1))
|
|
1171
1625
|
};
|
|
1172
1626
|
};
|
|
1173
1627
|
function hookToSpan(hookEvents, maxEndTime) {
|
|
@@ -1179,7 +1633,7 @@ function hookToSpan(hookEvents, maxEndTime) {
|
|
|
1179
1633
|
const endTime = hook.disposedAt || maxEndTime;
|
|
1180
1634
|
return {
|
|
1181
1635
|
spanId: String(hook.hookId),
|
|
1182
|
-
name: String(hook.hookId),
|
|
1636
|
+
name: hook.token ?? String(hook.hookId),
|
|
1183
1637
|
kind: 1,
|
|
1184
1638
|
// INTERNAL span kind
|
|
1185
1639
|
resource: "hook",
|
|
@@ -1200,15 +1654,26 @@ function hookToSpan(hookEvents, maxEndTime) {
|
|
|
1200
1654
|
function runToSpan(run, runEvents, nowTime) {
|
|
1201
1655
|
var _a;
|
|
1202
1656
|
const now = nowTime ?? /* @__PURE__ */ new Date();
|
|
1657
|
+
const runCreatedEvent = runEvents.find((event) => event.eventType === "run_created");
|
|
1658
|
+
const runStartedEvent = runEvents.find((event) => event.eventType === "run_started");
|
|
1659
|
+
const terminalEvent = runEvents.slice().reverse().find((event) => event.eventType === "run_completed" || event.eventType === "run_failed" || event.eventType === "run_cancelled");
|
|
1660
|
+
const spanStartTime = getEventTimestamp(runCreatedEvent) ?? new Date(run.createdAt);
|
|
1661
|
+
const activeStartTime = getEventTimestamp(runStartedEvent) ?? (run.startedAt ? new Date(run.startedAt) : void 0);
|
|
1662
|
+
const completedAt = getEventTimestamp(terminalEvent) ?? run.completedAt ?? void 0;
|
|
1663
|
+
const endTime = completedAt ?? now;
|
|
1203
1664
|
const { input: _i, output: _o, error: _e, ...runIdentity } = run;
|
|
1204
1665
|
const attributes = {
|
|
1205
1666
|
resource: "run",
|
|
1206
|
-
data:
|
|
1667
|
+
data: {
|
|
1668
|
+
...runIdentity,
|
|
1669
|
+
createdAt: spanStartTime,
|
|
1670
|
+
startedAt: activeStartTime,
|
|
1671
|
+
completedAt
|
|
1672
|
+
}
|
|
1207
1673
|
};
|
|
1208
|
-
const
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
const events = convertEventsToSpanEvents(runEvents, false);
|
|
1674
|
+
const events = convertEventsToSpanEvents(runEvents, false, {
|
|
1675
|
+
preferOccurredAt: true
|
|
1676
|
+
});
|
|
1212
1677
|
return {
|
|
1213
1678
|
spanId: String(run.runId),
|
|
1214
1679
|
name: String(((_a = parseWorkflowName(run.workflowName)) == null ? void 0 : _a.shortName) ?? "?"),
|
|
@@ -1228,9 +1693,15 @@ function runToSpan(run, runEvents, nowTime) {
|
|
|
1228
1693
|
activeStartTime: activeStartTime && activeStartTime.getTime() > spanStartTime.getTime() ? dateToOtelTime(activeStartTime) : void 0
|
|
1229
1694
|
};
|
|
1230
1695
|
}
|
|
1231
|
-
const
|
|
1232
|
-
|
|
1233
|
-
|
|
1696
|
+
const isRunLevelEvent = (event) => !event.correlationId || !isWaitEventType(event.eventType) && !isHookLifecycleEventType(event.eventType) && !isStepEventType(event.eventType);
|
|
1697
|
+
function filterSpanRawEvents(events, resource, spanId) {
|
|
1698
|
+
if (resource === "run") {
|
|
1699
|
+
return events.filter(isRunLevelEvent);
|
|
1700
|
+
}
|
|
1701
|
+
if (!spanId)
|
|
1702
|
+
return [];
|
|
1703
|
+
return events.filter((e) => e.correlationId === spanId);
|
|
1704
|
+
}
|
|
1234
1705
|
function pushEvent(map, correlationId, event) {
|
|
1235
1706
|
const existing = map.get(correlationId);
|
|
1236
1707
|
if (existing) {
|
|
@@ -1250,15 +1721,15 @@ function groupEventsByCorrelation(events) {
|
|
|
1250
1721
|
runLevelEvents.push(event);
|
|
1251
1722
|
continue;
|
|
1252
1723
|
}
|
|
1253
|
-
if (
|
|
1724
|
+
if (isWaitEventType(event.eventType)) {
|
|
1254
1725
|
pushEvent(timerEvents, correlationId, event);
|
|
1255
1726
|
continue;
|
|
1256
1727
|
}
|
|
1257
|
-
if (
|
|
1728
|
+
if (isHookLifecycleEventType(event.eventType)) {
|
|
1258
1729
|
pushEvent(hookEvents, correlationId, event);
|
|
1259
1730
|
continue;
|
|
1260
1731
|
}
|
|
1261
|
-
if (
|
|
1732
|
+
if (isStepEventType(event.eventType)) {
|
|
1262
1733
|
pushEvent(eventsByStepId, correlationId, event);
|
|
1263
1734
|
continue;
|
|
1264
1735
|
}
|
|
@@ -1269,7 +1740,7 @@ function groupEventsByCorrelation(events) {
|
|
|
1269
1740
|
function computeLatestKnownTime(events, run) {
|
|
1270
1741
|
let latest = new Date(run.createdAt).getTime();
|
|
1271
1742
|
for (const event of events) {
|
|
1272
|
-
const t = new Date(event.createdAt).getTime();
|
|
1743
|
+
const t = (getEventTimestamp(event) ?? new Date(event.createdAt)).getTime();
|
|
1273
1744
|
if (t > latest)
|
|
1274
1745
|
latest = t;
|
|
1275
1746
|
}
|
|
@@ -1277,9 +1748,10 @@ function computeLatestKnownTime(events, run) {
|
|
|
1277
1748
|
}
|
|
1278
1749
|
function buildSpans(run, groupedEvents, now, latestKnownTime) {
|
|
1279
1750
|
const childMaxEnd = latestKnownTime;
|
|
1751
|
+
const runMaxEnd = run.completedAt ?? now;
|
|
1280
1752
|
const stepSpans = Array.from(groupedEvents.eventsByStepId.values()).map((events) => stepToSpan(events, childMaxEnd)).filter((span) => span !== null);
|
|
1281
1753
|
const hookSpans = Array.from(groupedEvents.hookEvents.values()).map((events) => hookToSpan(events, childMaxEnd)).filter((span) => span !== null);
|
|
1282
|
-
const waitSpans = Array.from(groupedEvents.timerEvents.values()).map((events) => waitToSpan(events, childMaxEnd)).filter((span) => span !== null);
|
|
1754
|
+
const waitSpans = Array.from(groupedEvents.timerEvents.values()).map((events) => waitToSpan(events, childMaxEnd, runMaxEnd)).filter((span) => span !== null);
|
|
1283
1755
|
return {
|
|
1284
1756
|
runSpan: runToSpan(run, groupedEvents.runLevelEvents, now),
|
|
1285
1757
|
spans: [...stepSpans, ...hookSpans, ...waitSpans]
|
|
@@ -1425,49 +1897,10 @@ function parseContent(content) {
|
|
|
1425
1897
|
output: part.output
|
|
1426
1898
|
};
|
|
1427
1899
|
}
|
|
1428
|
-
return { type: "text", text: "" };
|
|
1429
|
-
});
|
|
1430
|
-
}
|
|
1431
|
-
return [];
|
|
1432
|
-
}
|
|
1433
|
-
const serializeForClipboard = (value) => {
|
|
1434
|
-
if (typeof value === "string")
|
|
1435
|
-
return value;
|
|
1436
|
-
if (typeof value === "number" || typeof value === "boolean" || value === null) {
|
|
1437
|
-
return String(value);
|
|
1438
|
-
}
|
|
1439
|
-
try {
|
|
1440
|
-
return JSON.stringify(value, null, 2);
|
|
1441
|
-
} catch {
|
|
1442
|
-
return String(value);
|
|
1443
|
-
}
|
|
1444
|
-
};
|
|
1445
|
-
function CopyableDataBlock({ data }) {
|
|
1446
|
-
const toast2 = useToast();
|
|
1447
|
-
return jsxRuntimeExports.jsxs("div", { className: "relative overflow-x-auto rounded-md border p-3", style: { borderColor: "var(--ds-gray-300)" }, children: [jsxRuntimeExports.jsx("button", { type: "button", "aria-label": "Copy data", title: "Copy", className: "!absolute !right-2 !top-2 !flex !h-6 !w-6 !items-center !justify-center !rounded-md !border !bg-[var(--ds-background-100)] !text-[var(--ds-gray-800)] transition-transform transition-colors duration-100 hover:!bg-[var(--ds-gray-alpha-200)] active:!scale-95 active:!bg-[var(--ds-gray-alpha-300)]", style: { borderColor: "var(--ds-gray-300)" }, onClick: () => {
|
|
1448
|
-
navigator.clipboard.writeText(serializeForClipboard(data)).then(() => {
|
|
1449
|
-
toast2.success("Copied to clipboard");
|
|
1450
|
-
}).catch(() => {
|
|
1451
|
-
toast2.error("Failed to copy");
|
|
1900
|
+
return { type: "text", text: "" };
|
|
1452
1901
|
});
|
|
1453
|
-
}, children: jsxRuntimeExports.jsx(Copy, { size: 12 }) }), jsxRuntimeExports.jsx(DataInspector, { data })] });
|
|
1454
|
-
}
|
|
1455
|
-
function DetailCard({ summary, children, onToggle, disabled = false, summaryClassName, contentClassName }) {
|
|
1456
|
-
if (disabled) {
|
|
1457
|
-
return jsxRuntimeExports.jsx("div", { className: `rounded-md border px-2.5 py-1.5 text-xs ${summaryClassName ?? ""}`, style: {
|
|
1458
|
-
borderColor: "var(--ds-gray-300)",
|
|
1459
|
-
backgroundColor: "var(--ds-gray-100)",
|
|
1460
|
-
color: "var(--ds-gray-700)",
|
|
1461
|
-
cursor: "not-allowed",
|
|
1462
|
-
opacity: 0.8
|
|
1463
|
-
}, children: summary });
|
|
1464
1902
|
}
|
|
1465
|
-
return
|
|
1466
|
-
borderColor: "var(--ds-gray-300)",
|
|
1467
|
-
backgroundColor: "var(--ds-gray-100)",
|
|
1468
|
-
color: "var(--ds-gray-900)",
|
|
1469
|
-
listStyle: "none"
|
|
1470
|
-
}, children: jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5", children: [jsxRuntimeExports.jsx(ChevronRight, { size: 14, className: "shrink-0 transition-transform group-open:rotate-90" }), summary] }) }), jsxRuntimeExports.jsx("div", { className: `mt-2 ${contentClassName ?? ""}`, children })] });
|
|
1903
|
+
return [];
|
|
1471
1904
|
}
|
|
1472
1905
|
function TabButton({ active, onClick, children }) {
|
|
1473
1906
|
return jsxRuntimeExports.jsx("button", { type: "button", role: "tab", "aria-selected": active, tabIndex: active ? 0 : -1, onClick, className: "px-3 py-1.5 text-[11px] font-medium transition-colors -mb-px", style: {
|
|
@@ -1506,25 +1939,12 @@ const conversationTabs = [
|
|
|
1506
1939
|
{ id: "conversation", label: "Conversation" },
|
|
1507
1940
|
{ id: "json", label: "Raw JSON" }
|
|
1508
1941
|
];
|
|
1509
|
-
function ConversationWithTabs({ conversation, args }) {
|
|
1942
|
+
function ConversationWithTabs({ conversation, args, defaultOpen, onOpenChange }) {
|
|
1510
1943
|
const [activeTab, setActiveTab] = reactExports.useState("conversation");
|
|
1511
|
-
return jsxRuntimeExports.jsx(
|
|
1944
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Input", defaultOpen, onOpenChange, 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) }) }) });
|
|
1512
1945
|
}
|
|
1513
1946
|
function EncryptedFieldBlock() {
|
|
1514
|
-
|
|
1515
|
-
if (ctx) {
|
|
1516
|
-
return jsxRuntimeExports.jsxs("button", { type: "button", onClick: ctx.onDecrypt, disabled: ctx.isDecrypting, className: "flex w-full items-center justify-center gap-1.5 rounded-md border px-3 py-2 text-xs cursor-pointer transition-colors", style: {
|
|
1517
|
-
borderColor: "var(--ds-gray-400)",
|
|
1518
|
-
backgroundColor: "var(--ds-gray-100)",
|
|
1519
|
-
color: "var(--ds-gray-700)",
|
|
1520
|
-
opacity: ctx.isDecrypting ? 0.6 : 1
|
|
1521
|
-
}, title: "Click to decrypt", children: [ctx.isDecrypting ? jsxRuntimeExports.jsx(Spinner, { size: 12 }) : jsxRuntimeExports.jsx(Lock, { className: "h-3 w-3" }), jsxRuntimeExports.jsx("span", { className: "font-medium", children: ctx.isDecrypting ? "Decrypting…" : "Decrypt" })] });
|
|
1522
|
-
}
|
|
1523
|
-
return jsxRuntimeExports.jsxs("div", { className: "flex w-full items-center justify-center gap-1.5 rounded-md border px-3 py-2 text-xs", style: {
|
|
1524
|
-
borderColor: "var(--ds-gray-300)",
|
|
1525
|
-
backgroundColor: "var(--ds-gray-100)",
|
|
1526
|
-
color: "var(--ds-gray-700)"
|
|
1527
|
-
}, children: [jsxRuntimeExports.jsx(Lock, { className: "h-3 w-3" }), jsxRuntimeExports.jsx("span", { className: "font-medium", children: "Encrypted" })] });
|
|
1947
|
+
return jsxRuntimeExports.jsx(EncryptedDataBlock, {});
|
|
1528
1948
|
}
|
|
1529
1949
|
function ExpiredFieldBlock() {
|
|
1530
1950
|
return jsxRuntimeExports.jsx("div", { className: "flex items-center gap-1.5 rounded-md border px-3 py-2 text-xs", style: {
|
|
@@ -1570,6 +1990,7 @@ const attributeOrder = [
|
|
|
1570
1990
|
"projectId",
|
|
1571
1991
|
"environment",
|
|
1572
1992
|
"executionContext",
|
|
1993
|
+
"occurredAt",
|
|
1573
1994
|
"createdAt",
|
|
1574
1995
|
"startedAt",
|
|
1575
1996
|
"updatedAt",
|
|
@@ -1581,6 +2002,7 @@ const attributeOrder = [
|
|
|
1581
2002
|
"eventData",
|
|
1582
2003
|
"input",
|
|
1583
2004
|
"output",
|
|
2005
|
+
"attributes",
|
|
1584
2006
|
"resumeAt"
|
|
1585
2007
|
];
|
|
1586
2008
|
const sortByAttributeOrder = (a, b) => {
|
|
@@ -1597,11 +2019,14 @@ const attributeDisplayNames = {
|
|
|
1597
2019
|
attempt: "Attempts",
|
|
1598
2020
|
eventId: "Event ID",
|
|
1599
2021
|
runId: "Run ID",
|
|
2022
|
+
token: "Token",
|
|
1600
2023
|
eventType: "Event Type",
|
|
2024
|
+
errorCode: "Error Code",
|
|
1601
2025
|
correlationId: "Correlation ID",
|
|
1602
2026
|
deploymentId: "Deployment ID",
|
|
1603
2027
|
specVersion: "Spec Version",
|
|
1604
2028
|
workflowCoreVersion: "@workflow/core version",
|
|
2029
|
+
occurredAt: "Occurred",
|
|
1605
2030
|
createdAt: "Created",
|
|
1606
2031
|
startedAt: "Started",
|
|
1607
2032
|
updatedAt: "Updated",
|
|
@@ -1628,7 +2053,7 @@ const getModuleSpecifierFromName = (value) => {
|
|
|
1628
2053
|
}
|
|
1629
2054
|
return raw;
|
|
1630
2055
|
};
|
|
1631
|
-
const parseDateValue = (value) => {
|
|
2056
|
+
const parseDateValue$1 = (value) => {
|
|
1632
2057
|
if (value == null) {
|
|
1633
2058
|
return null;
|
|
1634
2059
|
}
|
|
@@ -1641,31 +2066,16 @@ const parseDateValue = (value) => {
|
|
|
1641
2066
|
const date = typeof value === "number" ? new Date(value) : new Date(String(value));
|
|
1642
2067
|
return Number.isNaN(date.getTime()) ? null : date;
|
|
1643
2068
|
};
|
|
1644
|
-
const formatLocalMillisecondTime = (date) => date.
|
|
1645
|
-
year: "numeric",
|
|
1646
|
-
month: "numeric",
|
|
1647
|
-
day: "numeric",
|
|
1648
|
-
hour: "numeric",
|
|
1649
|
-
minute: "numeric",
|
|
1650
|
-
second: "numeric",
|
|
1651
|
-
fractionalSecondDigits: 3
|
|
1652
|
-
});
|
|
1653
|
-
const localMillisecondTime = (value) => {
|
|
1654
|
-
const date = parseDateValue(value);
|
|
1655
|
-
if (!date) {
|
|
1656
|
-
return "-";
|
|
1657
|
-
}
|
|
1658
|
-
return formatLocalMillisecondTime(date);
|
|
1659
|
-
};
|
|
2069
|
+
const formatLocalMillisecondTime = (date) => format(date, "MMM dd HH:mm:ss.SS OO").toUpperCase();
|
|
1660
2070
|
const localMillisecondTimeOrNull = (value) => {
|
|
1661
|
-
const date = parseDateValue(value);
|
|
2071
|
+
const date = parseDateValue$1(value);
|
|
1662
2072
|
if (!date) {
|
|
1663
2073
|
return null;
|
|
1664
2074
|
}
|
|
1665
2075
|
return formatLocalMillisecondTime(date);
|
|
1666
2076
|
};
|
|
1667
2077
|
const timestampWithTooltipOrNull = (value) => {
|
|
1668
|
-
const date = parseDateValue(value);
|
|
2078
|
+
const date = parseDateValue$1(value);
|
|
1669
2079
|
if (!date)
|
|
1670
2080
|
return null;
|
|
1671
2081
|
return jsxRuntimeExports.jsx(TimestampTooltip, { date, children: jsxRuntimeExports.jsx("span", { children: formatLocalMillisecondTime(date) }) });
|
|
@@ -1677,7 +2087,7 @@ const attributeToDisplayFn = {
|
|
|
1677
2087
|
stepName: (_value) => null,
|
|
1678
2088
|
// IDs
|
|
1679
2089
|
runId: (_value) => null,
|
|
1680
|
-
stepId: (
|
|
2090
|
+
stepId: (value) => String(value),
|
|
1681
2091
|
hookId: (value) => String(value),
|
|
1682
2092
|
eventId: (value) => String(value),
|
|
1683
2093
|
// Run/step details
|
|
@@ -1686,6 +2096,7 @@ const attributeToDisplayFn = {
|
|
|
1686
2096
|
// Hook details
|
|
1687
2097
|
token: (value) => String(value),
|
|
1688
2098
|
isWebhook: (value) => String(value),
|
|
2099
|
+
isSystem: (value) => String(value),
|
|
1689
2100
|
receivedCount: (value) => String(value),
|
|
1690
2101
|
lastReceivedAt: localMillisecondTimeOrNull,
|
|
1691
2102
|
disposedAt: localMillisecondTimeOrNull,
|
|
@@ -1701,7 +2112,16 @@ const attributeToDisplayFn = {
|
|
|
1701
2112
|
projectId: (_value) => null,
|
|
1702
2113
|
environment: (_value) => null,
|
|
1703
2114
|
executionContext: (_value) => null,
|
|
2115
|
+
// Attributes — string-string metadata attached to the run.
|
|
2116
|
+
// Rendered as key-value rows in its own collapsible section;
|
|
2117
|
+
// if empty/missing, hidden by the hasDisplayContent gate.
|
|
2118
|
+
attributes: (value) => {
|
|
2119
|
+
if (!hasDisplayContent(value))
|
|
2120
|
+
return null;
|
|
2121
|
+
return jsxRuntimeExports.jsx(RunAttributesCard, { attributes: value });
|
|
2122
|
+
},
|
|
1704
2123
|
// Dates — wrapped with TimestampTooltip showing UTC/local + relative time
|
|
2124
|
+
occurredAt: timestampWithTooltipOrNull,
|
|
1705
2125
|
createdAt: timestampWithTooltipOrNull,
|
|
1706
2126
|
startedAt: timestampWithTooltipOrNull,
|
|
1707
2127
|
updatedAt: (_value) => null,
|
|
@@ -1713,71 +2133,78 @@ const attributeToDisplayFn = {
|
|
|
1713
2133
|
metadata: (value) => {
|
|
1714
2134
|
if (!hasDisplayContent(value))
|
|
1715
2135
|
return null;
|
|
1716
|
-
if (isEncryptedMarker(value))
|
|
1717
|
-
return jsxRuntimeExports.jsx(
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
2136
|
+
if (isEncryptedMarker(value)) {
|
|
2137
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Metadata", children: jsxRuntimeExports.jsx(EncryptedDataBlock, {}) });
|
|
2138
|
+
}
|
|
2139
|
+
if (isExpiredMarker(value)) {
|
|
2140
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Metadata", children: jsxRuntimeExports.jsx(ExpiredFieldBlock, {}) });
|
|
2141
|
+
}
|
|
2142
|
+
return jsxRuntimeExports.jsx(RunMetadataCard, { metadata: value });
|
|
1721
2143
|
},
|
|
1722
2144
|
input: (value, context) => {
|
|
1723
|
-
if (isEncryptedMarker(value))
|
|
1724
|
-
return jsxRuntimeExports.jsx(EncryptedFieldBlock, {});
|
|
2145
|
+
if (isEncryptedMarker(value)) {
|
|
2146
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Input", defaultOpen: context == null ? void 0 : context.sectionOpen, onOpenChange: context == null ? void 0 : context.onSectionOpenChange, children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
|
|
2147
|
+
}
|
|
1725
2148
|
if (isExpiredMarker(value))
|
|
1726
2149
|
return jsxRuntimeExports.jsx(ExpiredFieldBlock, {});
|
|
1727
2150
|
if (value && typeof value === "object" && "args" in value) {
|
|
1728
2151
|
const { args, closureVars, thisVal } = value;
|
|
1729
|
-
const argCount2 = Array.isArray(args) ? args.length : 0;
|
|
1730
|
-
const argLabel2 = argCount2 === 1 ? "argument" : "arguments";
|
|
1731
2152
|
const hasClosureVars = hasDisplayContent(closureVars);
|
|
1732
2153
|
const hasThisVal = hasDisplayContent(thisVal);
|
|
1733
2154
|
const hasArgs = hasDisplayContent(args);
|
|
1734
2155
|
if ((context == null ? void 0 : context.stepName) && isDoStreamStep(context.stepName)) {
|
|
1735
2156
|
const conversation = extractConversation(args);
|
|
1736
2157
|
if (conversation && conversation.length > 0) {
|
|
1737
|
-
return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(ConversationWithTabs, { conversation, args }), hasClosureVars && jsxRuntimeExports.jsx(
|
|
2158
|
+
return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(ConversationWithTabs, { conversation, args, defaultOpen: context == null ? void 0 : context.sectionOpen, onOpenChange: context == null ? void 0 : context.onSectionOpenChange }), hasClosureVars && jsxRuntimeExports.jsx(Collapsible, { label: "Closure Variables", children: JsonBlock(closureVars) }), hasThisVal && jsxRuntimeExports.jsx(Collapsible, { label: "This Value", children: JsonBlock(thisVal) })] });
|
|
1738
2159
|
}
|
|
1739
2160
|
}
|
|
1740
2161
|
if (!hasArgs && !hasClosureVars && !hasThisVal) {
|
|
1741
|
-
return jsxRuntimeExports.jsx(
|
|
2162
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Input (no data)", disabled: true });
|
|
1742
2163
|
}
|
|
1743
|
-
return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(
|
|
2164
|
+
return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(Collapsible, { label: "Input", defaultOpen: context == null ? void 0 : context.sectionOpen, onOpenChange: context == null ? void 0 : context.onSectionOpenChange, 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) })] });
|
|
1744
2165
|
}
|
|
1745
|
-
const argCount = Array.isArray(value) ? value.length : 0;
|
|
1746
|
-
const argLabel = argCount === 1 ? "argument" : "arguments";
|
|
1747
2166
|
if (!hasDisplayContent(value)) {
|
|
1748
|
-
return jsxRuntimeExports.jsx(
|
|
2167
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Input (no data)", disabled: true });
|
|
1749
2168
|
}
|
|
1750
|
-
return jsxRuntimeExports.jsx(
|
|
2169
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Input", defaultOpen: context == null ? void 0 : context.sectionOpen, onOpenChange: context == null ? void 0 : context.onSectionOpenChange, children: Array.isArray(value) ? value.map((v, i) => jsxRuntimeExports.jsx("div", { className: "mt-2 first:mt-0", children: JsonBlock(v) }, i)) : JsonBlock(value) });
|
|
1751
2170
|
},
|
|
1752
|
-
output: (value) => {
|
|
2171
|
+
output: (value, context) => {
|
|
2172
|
+
if (isEncryptedMarker(value)) {
|
|
2173
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Output", defaultOpen: context == null ? void 0 : context.sectionOpen, onOpenChange: context == null ? void 0 : context.onSectionOpenChange, children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
|
|
2174
|
+
}
|
|
1753
2175
|
if (!hasDisplayContent(value))
|
|
1754
2176
|
return null;
|
|
1755
|
-
if (isEncryptedMarker(value))
|
|
1756
|
-
return jsxRuntimeExports.jsx(EncryptedFieldBlock, {});
|
|
1757
2177
|
if (isExpiredMarker(value))
|
|
1758
2178
|
return jsxRuntimeExports.jsx(ExpiredFieldBlock, {});
|
|
1759
|
-
return jsxRuntimeExports.jsx(
|
|
2179
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Output", defaultOpen: context == null ? void 0 : context.sectionOpen, onOpenChange: context == null ? void 0 : context.onSectionOpenChange, children: JsonBlock(value) });
|
|
1760
2180
|
},
|
|
1761
2181
|
error: (value) => {
|
|
1762
|
-
if (isEncryptedMarker(value))
|
|
1763
|
-
return jsxRuntimeExports.jsx(EncryptedFieldBlock, {});
|
|
2182
|
+
if (isEncryptedMarker(value)) {
|
|
2183
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Error", defaultOpen: true, children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
|
|
2184
|
+
}
|
|
1764
2185
|
if (isExpiredMarker(value))
|
|
1765
2186
|
return jsxRuntimeExports.jsx(ExpiredFieldBlock, {});
|
|
1766
2187
|
if (!hasDisplayContent(value))
|
|
1767
2188
|
return null;
|
|
1768
|
-
if (
|
|
1769
|
-
return jsxRuntimeExports.jsx(
|
|
2189
|
+
if (isStructuredError(value)) {
|
|
2190
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Error", defaultOpen: true, children: jsxRuntimeExports.jsx(ErrorStackBlock, { value }) });
|
|
1770
2191
|
}
|
|
1771
|
-
return jsxRuntimeExports.jsx(
|
|
2192
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Error", defaultOpen: true, children: JsonBlock(value) });
|
|
1772
2193
|
},
|
|
1773
2194
|
eventData: (value) => {
|
|
1774
|
-
if (isEncryptedMarker(value))
|
|
1775
|
-
return jsxRuntimeExports.jsx(EncryptedFieldBlock, {});
|
|
2195
|
+
if (isEncryptedMarker(value)) {
|
|
2196
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Event Data", defaultOpen: true, children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
|
|
2197
|
+
}
|
|
1776
2198
|
if (isExpiredMarker(value))
|
|
1777
2199
|
return jsxRuntimeExports.jsx(ExpiredFieldBlock, {});
|
|
1778
2200
|
if (!hasDisplayContent(value))
|
|
1779
2201
|
return null;
|
|
1780
|
-
return jsxRuntimeExports.jsx(
|
|
2202
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Event Data", defaultOpen: true, children: JsonBlock(value) });
|
|
2203
|
+
},
|
|
2204
|
+
errorCode: (value) => {
|
|
2205
|
+
if (typeof value !== "string" || value.length === 0)
|
|
2206
|
+
return null;
|
|
2207
|
+
return String(value);
|
|
1781
2208
|
}
|
|
1782
2209
|
};
|
|
1783
2210
|
const resolvableAttributes = [
|
|
@@ -1785,33 +2212,68 @@ const resolvableAttributes = [
|
|
|
1785
2212
|
"output",
|
|
1786
2213
|
"error",
|
|
1787
2214
|
"metadata",
|
|
2215
|
+
"attributes",
|
|
1788
2216
|
"eventData"
|
|
1789
2217
|
];
|
|
2218
|
+
const selfHeaderedAttributes = /* @__PURE__ */ new Set([
|
|
2219
|
+
"input",
|
|
2220
|
+
"output",
|
|
2221
|
+
"error",
|
|
2222
|
+
"metadata",
|
|
2223
|
+
"attributes",
|
|
2224
|
+
"eventData"
|
|
2225
|
+
]);
|
|
1790
2226
|
const ExpiredDataMessage = () => jsxRuntimeExports.jsx("div", { className: "text-copy-12 rounded-md border p-4 my-2", style: {
|
|
1791
2227
|
borderColor: "var(--ds-gray-300)",
|
|
1792
2228
|
backgroundColor: "var(--ds-gray-100)",
|
|
1793
2229
|
color: "var(--ds-gray-700)"
|
|
1794
2230
|
}, children: jsxRuntimeExports.jsx("span", { children: "The data for this run has expired and is no longer available." }) });
|
|
2231
|
+
const copyableBasicAttributes = /* @__PURE__ */ new Set([
|
|
2232
|
+
"stepId",
|
|
2233
|
+
"hookId",
|
|
2234
|
+
"eventId",
|
|
2235
|
+
"deploymentId",
|
|
2236
|
+
"moduleSpecifier"
|
|
2237
|
+
]);
|
|
2238
|
+
const loadingSectionLabels = {
|
|
2239
|
+
input: "Input",
|
|
2240
|
+
output: "Output",
|
|
2241
|
+
eventData: "Event Data"
|
|
2242
|
+
};
|
|
1795
2243
|
const AttributeBlock = ({ attribute, value, isLoading, inline = false, context }) => {
|
|
1796
|
-
const
|
|
1797
|
-
|
|
1798
|
-
|
|
2244
|
+
const decryptCtx = reactExports.useContext(DecryptClickContext);
|
|
2245
|
+
const sectionOpenRef = reactExports.useRef(false);
|
|
2246
|
+
const handleSectionOpenChange = reactExports.useCallback((open) => {
|
|
2247
|
+
sectionOpenRef.current = open;
|
|
2248
|
+
}, []);
|
|
2249
|
+
const label = loadingSectionLabels[attribute];
|
|
2250
|
+
if (isLoading && label && !hasDisplayContent(value)) {
|
|
2251
|
+
if (decryptCtx == null ? void 0 : decryptCtx.hasEncryptedData) {
|
|
2252
|
+
return jsxRuntimeExports.jsx(Collapsible, { label, defaultOpen: attribute === "eventData" || sectionOpenRef.current, onOpenChange: handleSectionOpenChange, children: jsxRuntimeExports.jsx(EncryptedFieldBlock, {}) });
|
|
2253
|
+
}
|
|
2254
|
+
return jsxRuntimeExports.jsx(Collapsible, { label });
|
|
1799
2255
|
}
|
|
1800
2256
|
const displayFn = attributeToDisplayFn[attribute];
|
|
1801
2257
|
if (!displayFn) {
|
|
1802
2258
|
return null;
|
|
1803
2259
|
}
|
|
1804
|
-
const displayValue = displayFn(value,
|
|
2260
|
+
const displayValue = displayFn(value, {
|
|
2261
|
+
...context,
|
|
2262
|
+
sectionOpen: sectionOpenRef.current,
|
|
2263
|
+
onSectionOpenChange: handleSectionOpenChange
|
|
2264
|
+
});
|
|
1805
2265
|
if (!displayValue) {
|
|
1806
2266
|
return null;
|
|
1807
2267
|
}
|
|
1808
2268
|
if (inline) {
|
|
1809
2269
|
return jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [jsxRuntimeExports.jsx("span", { className: "text-[11px] font-medium", style: { color: "var(--ds-gray-700)" }, children: attribute }), jsxRuntimeExports.jsx("span", { className: "text-[11px]", style: { color: "var(--ds-gray-1000)" }, children: displayValue })] });
|
|
1810
2270
|
}
|
|
1811
|
-
|
|
2271
|
+
if (selfHeaderedAttributes.has(attribute)) {
|
|
2272
|
+
return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: displayValue });
|
|
2273
|
+
}
|
|
2274
|
+
return jsxRuntimeExports.jsxs("div", { className: "relative", children: [typeof isLoading === "boolean" && isLoading && jsxRuntimeExports.jsx("div", { className: "absolute top-9 right-4", children: jsxRuntimeExports.jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2", style: { borderColor: "var(--ds-gray-900)" } }) }), jsxRuntimeExports.jsxs("div", { className: "my-2 flex flex-col gap-0", children: [jsxRuntimeExports.jsx("span", { className: "text-label-14 text-gray-1000 font-medium first-letter:uppercase", children: attribute }), jsxRuntimeExports.jsx("span", { className: "text-xs", style: { color: "var(--ds-gray-1000)" }, children: displayValue })] }, attribute)] });
|
|
1812
2275
|
};
|
|
1813
|
-
const AttributePanel = ({ data, moduleSpecifier, isLoading, error, expiredAt, onStreamClick, onRunClick, onDecrypt, isDecrypting = false, resource }) => {
|
|
1814
|
-
const toast2 = useToast();
|
|
2276
|
+
const AttributePanel = ({ data, moduleSpecifier, moduleSourceUrl, isLoading, error, expiredAt, onStreamClick, onRunClick, onDecrypt, isDecrypting = false, resource }) => {
|
|
1815
2277
|
const displayData = reactExports.useMemo(() => {
|
|
1816
2278
|
const result = { ...data };
|
|
1817
2279
|
const execCtx = data.executionContext;
|
|
@@ -1833,14 +2295,16 @@ const AttributePanel = ({ data, moduleSpecifier, isLoading, error, expiredAt, on
|
|
|
1833
2295
|
const present = Object.keys(displayData).filter((key) => resolvableAttributes.includes(key)).sort(sortByAttributeOrder);
|
|
1834
2296
|
if (!isLoading)
|
|
1835
2297
|
return present;
|
|
1836
|
-
|
|
1837
|
-
|
|
2298
|
+
if (resource === "sleep")
|
|
2299
|
+
return present;
|
|
2300
|
+
const loadingPlaceholders = ["input", "output"];
|
|
2301
|
+
for (const key of loadingPlaceholders) {
|
|
1838
2302
|
if (!present.includes(key)) {
|
|
1839
2303
|
present.push(key);
|
|
1840
2304
|
}
|
|
1841
2305
|
}
|
|
1842
2306
|
return present.sort(sortByAttributeOrder);
|
|
1843
|
-
}, [displayData, isLoading]);
|
|
2307
|
+
}, [displayData, isLoading, resource]);
|
|
1844
2308
|
const visibleBasicAttributes = basicAttributes.filter((attribute) => {
|
|
1845
2309
|
const displayFn = attributeToDisplayFn[attribute];
|
|
1846
2310
|
if (!displayFn)
|
|
@@ -1871,46 +2335,37 @@ const AttributePanel = ({ data, moduleSpecifier, isLoading, error, expiredAt, on
|
|
|
1871
2335
|
const displayContext = reactExports.useMemo(() => ({
|
|
1872
2336
|
stepName: displayData.stepName
|
|
1873
2337
|
}), [displayData.stepName]);
|
|
1874
|
-
const
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
}, [
|
|
1881
|
-
return jsxRuntimeExports.jsx(RunClickContext.Provider, { value: onRunClick, children: jsxRuntimeExports.jsx(StreamClickContext.Provider, { value: onStreamClick, children: jsxRuntimeExports.jsx(DecryptClickContext.Provider, { value: onDecrypt ? { onDecrypt, isDecrypting } : void 0, children: jsxRuntimeExports.jsxs("div", { children: [visibleBasicAttributes.length > 0 && jsxRuntimeExports.jsxs("div", { className: "mb-3 flex flex-col overflow-hidden rounded-md border", style: {
|
|
1882
|
-
borderColor: "var(--ds-gray-300)"
|
|
1883
|
-
}, children: [orderedBasicAttributes.map((attribute, index) => {
|
|
2338
|
+
const outerDecryptCtx = reactExports.useContext(DecryptClickContext);
|
|
2339
|
+
const decryptValue = onDecrypt ? {
|
|
2340
|
+
onDecrypt,
|
|
2341
|
+
isDecrypting,
|
|
2342
|
+
hasEncryptedData: outerDecryptCtx == null ? void 0 : outerDecryptCtx.hasEncryptedData
|
|
2343
|
+
} : outerDecryptCtx;
|
|
2344
|
+
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) => {
|
|
1884
2345
|
var _a;
|
|
1885
2346
|
const displayValue = (_a = attributeToDisplayFn[attribute]) == null ? void 0 : _a.call(attributeToDisplayFn, displayData[attribute]);
|
|
1886
|
-
const
|
|
1887
|
-
const
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
const showDivider = index < orderedBasicAttributes.length - 1 || showResumeAtSkeleton;
|
|
1891
|
-
return jsxRuntimeExports.jsxs("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: shouldCapitalizeLabel ? "text-[14px] first-letter:uppercase" : "text-[14px]", style: { color: "var(--ds-gray-700)" }, children: getAttributeDisplayName(attribute) }), isModuleSpecifier ? jsxRuntimeExports.jsx("button", { type: "button", className: "min-w-0 max-w-[70%] truncate text-right text-[13px] font-mono", style: {
|
|
1892
|
-
color: "var(--ds-gray-1000)",
|
|
1893
|
-
background: "transparent",
|
|
1894
|
-
border: "none",
|
|
1895
|
-
padding: 0
|
|
1896
|
-
}, title: moduleSpecifierValue, onClick: () => handleCopyModuleSpecifier(moduleSpecifierValue), children: moduleSpecifierValue }) : jsxRuntimeExports.jsx("span", { className: "min-w-0 max-w-[70%] truncate text-right text-[13px] font-mono", style: { color: "var(--ds-gray-1000)" }, children: displayValue })] }), showDivider ? jsxRuntimeExports.jsx("div", { className: "mx-2.5 border-b", style: { borderColor: "var(--ds-gray-300)" } }) : null] }, attribute);
|
|
1897
|
-
}), 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, {}) : jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: resolvedAttributes.map((attribute) => jsxRuntimeExports.jsx(AttributeBlock, { isLoading, attribute, value: displayData[attribute], context: displayContext }, attribute)) })] }) }) }) });
|
|
2347
|
+
const isCopyableBasicAttribute = copyableBasicAttributes.has(attribute) && typeof displayValue === "string";
|
|
2348
|
+
const label = getAttributeDisplayName(attribute);
|
|
2349
|
+
return jsxRuntimeExports.jsx(DetailMonoKeyValueRow, { label, value: displayValue, copyText: isCopyableBasicAttribute ? displayValue : void 0, href: attribute === "moduleSpecifier" ? moduleSourceUrl : void 0 }, attribute);
|
|
2350
|
+
}), 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] }) }) }) });
|
|
1898
2351
|
};
|
|
1899
|
-
const
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
"
|
|
1908
|
-
"
|
|
1909
|
-
"
|
|
1910
|
-
"
|
|
1911
|
-
"
|
|
1912
|
-
|
|
1913
|
-
|
|
2352
|
+
const parseDateValue = (value) => {
|
|
2353
|
+
if (value == null)
|
|
2354
|
+
return null;
|
|
2355
|
+
const date = value instanceof Date ? value : new Date(String(value));
|
|
2356
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
2357
|
+
};
|
|
2358
|
+
const getEffectiveEventDate = (event) => parseDateValue(event.occurredAt) ?? new Date(event.createdAt);
|
|
2359
|
+
const formatEventTimestamp = (date) => date.toLocaleString(void 0, {
|
|
2360
|
+
month: "short",
|
|
2361
|
+
day: "numeric",
|
|
2362
|
+
hour: "numeric",
|
|
2363
|
+
minute: "numeric",
|
|
2364
|
+
second: "numeric",
|
|
2365
|
+
fractionalSecondDigits: 3,
|
|
2366
|
+
timeZoneName: "short"
|
|
2367
|
+
});
|
|
2368
|
+
function EventItem({ event, onLoadEventData, encryptionKey, showSeparateEventOccurrenceTimestamps = false }) {
|
|
1914
2369
|
const [loadedData, setLoadedData] = reactExports.useState(null);
|
|
1915
2370
|
const [isLoading, setIsLoading] = reactExports.useState(false);
|
|
1916
2371
|
const [loadError, setLoadError] = reactExports.useState(null);
|
|
@@ -1918,17 +2373,17 @@ function EventItem({ event, onLoadEventData, encryptionKey }) {
|
|
|
1918
2373
|
const loadedDataRef = reactExports.useRef(null);
|
|
1919
2374
|
const existingData = "eventData" in event && event.eventData != null ? event.eventData : null;
|
|
1920
2375
|
const mergedDisplay = loadedData ?? existingData;
|
|
1921
|
-
const canHaveData =
|
|
1922
|
-
const loadEventData = reactExports.useCallback(async (
|
|
1923
|
-
if (!onLoadEventData
|
|
2376
|
+
const canHaveData = existingData !== null || getEventDataRefFields(event.eventType).length > 0;
|
|
2377
|
+
const loadEventData = reactExports.useCallback(async (force) => {
|
|
2378
|
+
if (!onLoadEventData)
|
|
1924
2379
|
return;
|
|
1925
|
-
if (!
|
|
2380
|
+
if (!force && loadedDataRef.current !== null) {
|
|
1926
2381
|
return;
|
|
1927
2382
|
}
|
|
1928
2383
|
try {
|
|
1929
2384
|
setIsLoading(true);
|
|
1930
2385
|
setLoadError(null);
|
|
1931
|
-
const data = await onLoadEventData(event
|
|
2386
|
+
const data = await onLoadEventData(event);
|
|
1932
2387
|
loadedDataRef.current = data;
|
|
1933
2388
|
setLoadedData(data);
|
|
1934
2389
|
} catch (err) {
|
|
@@ -1936,38 +2391,40 @@ function EventItem({ event, onLoadEventData, encryptionKey }) {
|
|
|
1936
2391
|
} finally {
|
|
1937
2392
|
setIsLoading(false);
|
|
1938
2393
|
}
|
|
1939
|
-
}, [onLoadEventData, event
|
|
1940
|
-
const handleExpand = reactExports.useCallback(
|
|
2394
|
+
}, [onLoadEventData, event]);
|
|
2395
|
+
const handleExpand = reactExports.useCallback(() => {
|
|
1941
2396
|
if (isLoading)
|
|
1942
2397
|
return;
|
|
1943
2398
|
wasExpandedRef.current = true;
|
|
1944
|
-
|
|
2399
|
+
void loadEventData(false);
|
|
1945
2400
|
}, [isLoading, loadEventData]);
|
|
1946
|
-
reactExports.
|
|
2401
|
+
reactExports.useLayoutEffect(() => {
|
|
1947
2402
|
if (!encryptionKey || !wasExpandedRef.current)
|
|
1948
2403
|
return;
|
|
1949
2404
|
loadedDataRef.current = null;
|
|
1950
2405
|
setLoadedData(null);
|
|
1951
|
-
void loadEventData(
|
|
2406
|
+
void loadEventData(true);
|
|
1952
2407
|
}, [encryptionKey, loadEventData]);
|
|
1953
2408
|
const createdAt = new Date(event.createdAt);
|
|
2409
|
+
const occurredAt = parseDateValue(event.occurredAt);
|
|
2410
|
+
const displayedCreatedAt = showSeparateEventOccurrenceTimestamps ? createdAt : getEffectiveEventDate(event);
|
|
2411
|
+
const displayedCreatedAtTime = displayedCreatedAt.toLocaleTimeString(void 0, {
|
|
2412
|
+
hour: "numeric",
|
|
2413
|
+
minute: "numeric",
|
|
2414
|
+
second: "numeric"
|
|
2415
|
+
});
|
|
1954
2416
|
const displayPayload = isLoading ? loadedData : mergedDisplay;
|
|
1955
|
-
return jsxRuntimeExports.jsxs(
|
|
2417
|
+
return jsxRuntimeExports.jsxs(CollapsibleRoot, { variant: "card", onOpenChange: canHaveData ? (open) => {
|
|
1956
2418
|
if (open)
|
|
1957
2419
|
handleExpand();
|
|
1958
|
-
} : void 0, children: [jsxRuntimeExports.jsxs("div", { className: "flex flex-col
|
|
1959
|
-
borderColor: "var(--ds-gray-300)",
|
|
1960
|
-
backgroundColor: "var(--ds-gray-100)"
|
|
1961
|
-
}, children: [jsxRuntimeExports.jsxs("div", { className: "flex min-h-[32px] items-center justify-between gap-4 px-2.5 py-1.5", style: { borderColor: "var(--ds-gray-300)" }, children: [jsxRuntimeExports.jsx("span", { className: "text-[13px] font-medium", style: { color: "var(--ds-gray-700)" }, children: "Event ID" }), jsxRuntimeExports.jsx("span", { className: "max-w-[70%] truncate text-right text-[13px] font-mono", style: { color: "var(--ds-gray-1000)" }, title: event.eventId, children: event.eventId })] }), event.correlationId && jsxRuntimeExports.jsxs("div", { className: "flex min-h-[32px] items-center justify-between gap-4 px-2.5 py-1.5", style: { borderColor: "var(--ds-gray-300)" }, children: [jsxRuntimeExports.jsx("span", { className: "text-[13px] font-medium", style: { color: "var(--ds-gray-700)" }, children: "Correlation ID" }), jsxRuntimeExports.jsx("span", { className: "max-w-[70%] truncate text-right text-[13px] font-mono", style: { color: "var(--ds-gray-1000)" }, title: event.correlationId, children: event.correlationId })] })] }), isLoading && jsxRuntimeExports.jsxs("div", { className: "mt-2 rounded-md border p-3", style: {
|
|
1962
|
-
borderColor: "var(--ds-gray-300)"
|
|
1963
|
-
}, 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: "mt-2", children: jsxRuntimeExports.jsx(EventDataBlock, { eventType: event.eventType, data: displayPayload }) })] });
|
|
2420
|
+
} : 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 }) })] })] });
|
|
1964
2421
|
}
|
|
1965
2422
|
function hasOnlyExpiredFields(data, eventType) {
|
|
1966
2423
|
if (data === null || typeof data !== "object" || Array.isArray(data)) {
|
|
1967
2424
|
return false;
|
|
1968
2425
|
}
|
|
1969
2426
|
const record = data;
|
|
1970
|
-
const refKeys =
|
|
2427
|
+
const refKeys = getEventDataRefFields(eventType);
|
|
1971
2428
|
const presentKeys = refKeys.filter((k) => k in record);
|
|
1972
2429
|
return presentKeys.length > 0 && presentKeys.every((k) => isExpiredMarker(record[k]));
|
|
1973
2430
|
}
|
|
@@ -1979,79 +2436,199 @@ function EventDataBlock({ eventType, data }) {
|
|
|
1979
2436
|
color: "var(--ds-gray-700)"
|
|
1980
2437
|
}, children: jsxRuntimeExports.jsx("span", { className: "font-medium", children: "Data expired" }) });
|
|
1981
2438
|
}
|
|
1982
|
-
if (
|
|
2439
|
+
if (hasEncryptedFields({ eventType, eventData: data })) {
|
|
2440
|
+
return jsxRuntimeExports.jsx(EncryptedDataBlock, {});
|
|
2441
|
+
}
|
|
2442
|
+
if (eventType === "attr_set") {
|
|
2443
|
+
return jsxRuntimeExports.jsx(AttrSetEventBlock, { data });
|
|
2444
|
+
}
|
|
2445
|
+
if (getEventDataRefFields(eventType).includes("error") && data != null && typeof data === "object") {
|
|
1983
2446
|
const record = data;
|
|
1984
|
-
if (
|
|
2447
|
+
if (isStructuredError(record.error)) {
|
|
1985
2448
|
return jsxRuntimeExports.jsx(ErrorStackBlock, { value: record.error });
|
|
1986
2449
|
}
|
|
1987
|
-
if (
|
|
2450
|
+
if (isStructuredError(record)) {
|
|
1988
2451
|
return jsxRuntimeExports.jsx(ErrorStackBlock, { value: record });
|
|
1989
2452
|
}
|
|
1990
2453
|
}
|
|
1991
2454
|
return jsxRuntimeExports.jsx(CopyableDataBlock, { data });
|
|
1992
2455
|
}
|
|
1993
|
-
function EventsList({ events, isLoading = false, error, onLoadEventData, encryptionKey }) {
|
|
1994
|
-
const sortedEvents = reactExports.useMemo(() => [...events].sort((a, b) =>
|
|
1995
|
-
|
|
2456
|
+
function EventsList({ events, isLoading = false, error, onLoadEventData, onStreamClick, onRunClick, encryptionKey, showSeparateEventOccurrenceTimestamps = false }) {
|
|
2457
|
+
const sortedEvents = reactExports.useMemo(() => [...events].sort((a, b) => getEffectiveEventDate(a).getTime() - getEffectiveEventDate(b).getTime()), [events]);
|
|
2458
|
+
const hasEvents = sortedEvents.length > 0 && !error;
|
|
2459
|
+
if (!hasEvents && !isLoading) {
|
|
2460
|
+
return jsxRuntimeExports.jsx(Collapsible, { label: "Events", disabled: true });
|
|
2461
|
+
}
|
|
2462
|
+
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)) }) })] }) }) });
|
|
2463
|
+
}
|
|
2464
|
+
const hasField = (value, key) => key in value;
|
|
2465
|
+
const RESOURCES_WITH_FETCHED_DETAIL = /* @__PURE__ */ new Set(["run", "step", "sleep"]);
|
|
2466
|
+
function resourceNeedsFetchedDetail(resource) {
|
|
2467
|
+
return resource !== void 0 && RESOURCES_WITH_FETCHED_DETAIL.has(resource);
|
|
2468
|
+
}
|
|
2469
|
+
function deriveSpanDetailView(args) {
|
|
2470
|
+
const { resource, resourceId, inlineData, fetchedDetail, fetchedError } = args;
|
|
2471
|
+
const matchedDetail = spanDetailMatchesSelection(fetchedDetail, resource, resourceId) ? fetchedDetail : null;
|
|
2472
|
+
const displayData = mergeSpanDetail(inlineData, matchedDetail);
|
|
2473
|
+
if (!resource || !resourceId) {
|
|
2474
|
+
return { status: "idle", displayData, detail: null, error: void 0 };
|
|
2475
|
+
}
|
|
2476
|
+
if (fetchedError) {
|
|
2477
|
+
return {
|
|
2478
|
+
status: "error",
|
|
2479
|
+
displayData,
|
|
2480
|
+
detail: matchedDetail,
|
|
2481
|
+
error: fetchedError
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2484
|
+
if (!resourceNeedsFetchedDetail(resource)) {
|
|
2485
|
+
return {
|
|
2486
|
+
status: "ready",
|
|
2487
|
+
displayData,
|
|
2488
|
+
detail: matchedDetail,
|
|
2489
|
+
error: void 0
|
|
2490
|
+
};
|
|
2491
|
+
}
|
|
2492
|
+
if (matchedDetail !== null) {
|
|
2493
|
+
return {
|
|
2494
|
+
status: "ready",
|
|
2495
|
+
displayData,
|
|
2496
|
+
detail: matchedDetail,
|
|
2497
|
+
error: void 0
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2500
|
+
return { status: "loading", displayData, detail: null, error: void 0 };
|
|
2501
|
+
}
|
|
2502
|
+
function spanDetailMatchesSelection(detail, resource, resourceId) {
|
|
2503
|
+
if (!detail || typeof detail !== "object" || !resource || !resourceId) {
|
|
2504
|
+
return false;
|
|
2505
|
+
}
|
|
2506
|
+
switch (resource) {
|
|
2507
|
+
case "step":
|
|
2508
|
+
return hasField(detail, "stepId") && detail.stepId === resourceId;
|
|
2509
|
+
case "hook":
|
|
2510
|
+
return hasField(detail, "hookId") && detail.hookId === resourceId;
|
|
2511
|
+
case "sleep":
|
|
2512
|
+
return hasField(detail, "waitId") && detail.waitId === resourceId;
|
|
2513
|
+
case "run":
|
|
2514
|
+
return hasField(detail, "runId") && !("stepId" in detail) && !("hookId" in detail) && !("waitId" in detail) && detail.runId === resourceId;
|
|
2515
|
+
default:
|
|
2516
|
+
return false;
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
function mergeSpanDetail(spanData, detail) {
|
|
2520
|
+
if (!detail || typeof detail !== "object") {
|
|
2521
|
+
return spanData;
|
|
2522
|
+
}
|
|
2523
|
+
if (!spanData || typeof spanData !== "object") {
|
|
2524
|
+
return detail;
|
|
2525
|
+
}
|
|
2526
|
+
const merged = { ...detail };
|
|
2527
|
+
for (const [key, value] of Object.entries(spanData)) {
|
|
2528
|
+
if (value !== void 0) {
|
|
2529
|
+
merged[key] = value;
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
return merged;
|
|
1996
2533
|
}
|
|
1997
|
-
function
|
|
1998
|
-
|
|
2534
|
+
function deriveSpanSelection(selectedSpan) {
|
|
2535
|
+
if (!selectedSpan)
|
|
2536
|
+
return null;
|
|
2537
|
+
const { resource, data } = selectedSpan;
|
|
2538
|
+
if (resource === "step" && data && typeof data === "object" && "stepId" in data) {
|
|
2539
|
+
const step = data;
|
|
2540
|
+
return { resource: "step", resourceId: step.stepId, runId: step.runId };
|
|
2541
|
+
}
|
|
2542
|
+
if (resource === "run" && data && typeof data === "object" && "runId" in data) {
|
|
2543
|
+
return { resource: "run", resourceId: data.runId };
|
|
2544
|
+
}
|
|
2545
|
+
if (resource === "hook" && data && typeof data === "object" && "hookId" in data) {
|
|
2546
|
+
return { resource: "hook", resourceId: data.hookId };
|
|
2547
|
+
}
|
|
2548
|
+
if (resource === "sleep") {
|
|
2549
|
+
if (!selectedSpan.spanId)
|
|
2550
|
+
return null;
|
|
2551
|
+
const waitData = data;
|
|
2552
|
+
return {
|
|
2553
|
+
resource: "sleep",
|
|
2554
|
+
resourceId: selectedSpan.spanId,
|
|
2555
|
+
runId: waitData == null ? void 0 : waitData.runId
|
|
2556
|
+
};
|
|
2557
|
+
}
|
|
2558
|
+
return null;
|
|
1999
2559
|
}
|
|
2000
|
-
function
|
|
2001
|
-
|
|
2560
|
+
function useSelectedSpanDetail(selectedSpan, fetchSpanDetail) {
|
|
2561
|
+
const selection = reactExports.useMemo(() => deriveSpanSelection(selectedSpan), [selectedSpan]);
|
|
2562
|
+
const resource = selection == null ? void 0 : selection.resource;
|
|
2563
|
+
const resourceId = selection == null ? void 0 : selection.resourceId;
|
|
2564
|
+
const runId = selection == null ? void 0 : selection.runId;
|
|
2565
|
+
const selectionKey = resource && resourceId ? `${resource}:${resourceId}` : null;
|
|
2566
|
+
const needsFetch = resourceNeedsFetchedDetail(resource);
|
|
2567
|
+
const [fetched, setFetched] = reactExports.useState({ detail: null, error: null, errorKey: null });
|
|
2568
|
+
const tokenRef = reactExports.useRef(0);
|
|
2569
|
+
const selectionRef = reactExports.useRef(selection);
|
|
2570
|
+
selectionRef.current = selection;
|
|
2571
|
+
reactExports.useEffect(() => {
|
|
2572
|
+
if (!selectionKey || !needsFetch) {
|
|
2573
|
+
return;
|
|
2574
|
+
}
|
|
2575
|
+
const activeSelection = selectionRef.current;
|
|
2576
|
+
if (!activeSelection) {
|
|
2577
|
+
return;
|
|
2578
|
+
}
|
|
2579
|
+
const token = ++tokenRef.current;
|
|
2580
|
+
fetchSpanDetail(activeSelection).then((detail) => {
|
|
2581
|
+
if (tokenRef.current !== token)
|
|
2582
|
+
return;
|
|
2583
|
+
setFetched({ detail, error: null, errorKey: null });
|
|
2584
|
+
}).catch((err) => {
|
|
2585
|
+
if (tokenRef.current !== token)
|
|
2586
|
+
return;
|
|
2587
|
+
setFetched({
|
|
2588
|
+
detail: null,
|
|
2589
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
2590
|
+
errorKey: selectionKey
|
|
2591
|
+
});
|
|
2592
|
+
});
|
|
2593
|
+
}, [selectionKey, runId, needsFetch, fetchSpanDetail]);
|
|
2594
|
+
const scopedError = fetched.errorKey === selectionKey ? fetched.error : null;
|
|
2595
|
+
const view = reactExports.useMemo(() => deriveSpanDetailView({
|
|
2596
|
+
resource,
|
|
2597
|
+
resourceId,
|
|
2598
|
+
inlineData: selectedSpan == null ? void 0 : selectedSpan.data,
|
|
2599
|
+
fetchedDetail: fetched.detail,
|
|
2600
|
+
fetchedError: scopedError
|
|
2601
|
+
}), [resource, resourceId, selectedSpan == null ? void 0 : selectedSpan.data, fetched.detail, scopedError]);
|
|
2602
|
+
return {
|
|
2603
|
+
status: view.status,
|
|
2604
|
+
resource,
|
|
2605
|
+
resourceId,
|
|
2606
|
+
runId,
|
|
2607
|
+
displayData: view.displayData,
|
|
2608
|
+
detail: view.detail,
|
|
2609
|
+
error: view.error
|
|
2610
|
+
};
|
|
2002
2611
|
}
|
|
2003
2612
|
function isHook(data) {
|
|
2004
2613
|
return data !== null && typeof data === "object" && "hookId" in data;
|
|
2005
2614
|
}
|
|
2006
|
-
function EntityDetailPanel({ run, onStreamClick, onRunClick,
|
|
2615
|
+
function EntityDetailPanel({ run, onStreamClick, onRunClick, fetchSpanDetail, onWakeUpSleep, onLoadEventData, onResolveHook, encryptionKey, onDecrypt, isDecrypting = false, selectedSpan, showSeparateEventOccurrenceTimestamps = false, getModuleSourceUrl }) {
|
|
2007
2616
|
const toast2 = useToast();
|
|
2008
2617
|
const [stoppingSleep, setStoppingSleep] = reactExports.useState(false);
|
|
2009
2618
|
const [showResolveHookModal, setShowResolveHookModal] = reactExports.useState(false);
|
|
2010
2619
|
const [resolvingHook, setResolvingHook] = reactExports.useState(false);
|
|
2011
2620
|
const [resolvedHookIds, setResolvedHookIds] = reactExports.useState(/* @__PURE__ */ new Set());
|
|
2621
|
+
const sidebar = useSidebarDataOptional();
|
|
2622
|
+
const hasEncryptedData = Boolean((sidebar == null ? void 0 : sidebar.hasEncryptedData) && !encryptionKey);
|
|
2012
2623
|
const data = selectedSpan == null ? void 0 : selectedSpan.data;
|
|
2013
2624
|
const rawEvents = selectedSpan == null ? void 0 : selectedSpan.rawEvents;
|
|
2014
2625
|
const rawEventsLength = (rawEvents == null ? void 0 : rawEvents.length) ?? 0;
|
|
2015
|
-
const { resource, resourceId,
|
|
2016
|
-
|
|
2017
|
-
return { resource: void 0, resourceId: void 0, runId: void 0 };
|
|
2018
|
-
}
|
|
2019
|
-
const res = selectedSpan.resource;
|
|
2020
|
-
if (res === "step" && isStep(data)) {
|
|
2021
|
-
return { resource: "step", resourceId: data.stepId, runId: data.runId };
|
|
2022
|
-
}
|
|
2023
|
-
if (res === "run" && isWorkflowRun(data)) {
|
|
2024
|
-
return { resource: "run", resourceId: data.runId, runId: void 0 };
|
|
2025
|
-
}
|
|
2026
|
-
if (res === "hook" && isHook(data)) {
|
|
2027
|
-
return { resource: "hook", resourceId: data.hookId, runId: void 0 };
|
|
2028
|
-
}
|
|
2029
|
-
if (res === "sleep") {
|
|
2030
|
-
const waitData = data;
|
|
2031
|
-
return {
|
|
2032
|
-
resource: "sleep",
|
|
2033
|
-
resourceId: selectedSpan.spanId,
|
|
2034
|
-
runId: waitData == null ? void 0 : waitData.runId
|
|
2035
|
-
};
|
|
2036
|
-
}
|
|
2037
|
-
return { resource: void 0, resourceId: void 0, runId: void 0 };
|
|
2038
|
-
}, [selectedSpan, data]);
|
|
2039
|
-
const onSpanSelectRef = reactExports.useRef(onSpanSelect);
|
|
2040
|
-
onSpanSelectRef.current = onSpanSelect;
|
|
2041
|
-
reactExports.useEffect(() => {
|
|
2042
|
-
if (resource && resourceId && ["run", "step", "hook", "sleep"].includes(resource)) {
|
|
2043
|
-
onSpanSelectRef.current({
|
|
2044
|
-
resource,
|
|
2045
|
-
resourceId,
|
|
2046
|
-
runId
|
|
2047
|
-
});
|
|
2048
|
-
}
|
|
2049
|
-
}, [resource, resourceId, runId]);
|
|
2626
|
+
const { status, resource, resourceId, displayData, detail: matchedSpanDetailData, error } = useSelectedSpanDetail(selectedSpan, fetchSpanDetail);
|
|
2627
|
+
const loading = status === "loading";
|
|
2050
2628
|
const canWakeUp = reactExports.useMemo(() => {
|
|
2051
2629
|
if (resource !== "sleep" || !rawEvents)
|
|
2052
2630
|
return false;
|
|
2053
|
-
|
|
2054
|
-
if (terminalStates.includes(run.status))
|
|
2631
|
+
if (isTerminalWorkflowRunStatus(run.status))
|
|
2055
2632
|
return false;
|
|
2056
2633
|
const hasWaitCreated = rawEvents.some((e) => e.eventType === "wait_created");
|
|
2057
2634
|
if (!hasWaitCreated)
|
|
@@ -2064,8 +2641,7 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
|
|
|
2064
2641
|
return false;
|
|
2065
2642
|
if (resolvedHookIds.has(resourceId))
|
|
2066
2643
|
return false;
|
|
2067
|
-
|
|
2068
|
-
if (terminalStates.includes(run.status))
|
|
2644
|
+
if (isTerminalWorkflowRunStatus(run.status))
|
|
2069
2645
|
return false;
|
|
2070
2646
|
const hasHookDisposed = rawEvents.some((e) => e.eventType === "hook_disposed");
|
|
2071
2647
|
if (hasHookDisposed)
|
|
@@ -2079,19 +2655,17 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
|
|
|
2079
2655
|
run.status,
|
|
2080
2656
|
resolvedHookIds
|
|
2081
2657
|
]);
|
|
2082
|
-
const error = spanDetailError ?? void 0;
|
|
2083
|
-
const loading = spanDetailLoading ?? false;
|
|
2084
2658
|
const hookToken = reactExports.useMemo(() => {
|
|
2085
2659
|
if (resource !== "hook" || !resourceId)
|
|
2086
2660
|
return void 0;
|
|
2087
|
-
if (isHook(
|
|
2088
|
-
return
|
|
2661
|
+
if (isHook(matchedSpanDetailData) && matchedSpanDetailData.token) {
|
|
2662
|
+
return matchedSpanDetailData.token;
|
|
2089
2663
|
}
|
|
2090
2664
|
if (isHook(data) && data.token) {
|
|
2091
2665
|
return data.token;
|
|
2092
2666
|
}
|
|
2093
2667
|
return void 0;
|
|
2094
|
-
}, [resource, resourceId,
|
|
2668
|
+
}, [resource, resourceId, matchedSpanDetailData, data]);
|
|
2095
2669
|
reactExports.useEffect(() => {
|
|
2096
2670
|
if (error && selectedSpan && resource) {
|
|
2097
2671
|
toast2.error(`Failed to load ${resource} details`, {
|
|
@@ -2146,7 +2720,7 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
|
|
|
2146
2720
|
}
|
|
2147
2721
|
try {
|
|
2148
2722
|
setResolvingHook(true);
|
|
2149
|
-
const candidate =
|
|
2723
|
+
const candidate = matchedSpanDetailData ?? data;
|
|
2150
2724
|
const hook = isHook(candidate) ? candidate : void 0;
|
|
2151
2725
|
await onResolveHook(hookToken, payload, hook);
|
|
2152
2726
|
toast2.success("Hook resolved", {
|
|
@@ -2164,8 +2738,7 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
|
|
|
2164
2738
|
} finally {
|
|
2165
2739
|
setResolvingHook(false);
|
|
2166
2740
|
}
|
|
2167
|
-
}, [onResolveHook, hookToken, resolvingHook,
|
|
2168
|
-
const displayData = spanDetailData ?? data;
|
|
2741
|
+
}, [onResolveHook, hookToken, resolvingHook, matchedSpanDetailData, data]);
|
|
2169
2742
|
const moduleSpecifier = reactExports.useMemo(() => {
|
|
2170
2743
|
const displayRecord = displayData;
|
|
2171
2744
|
const displayStepName = displayRecord.stepName;
|
|
@@ -2181,11 +2754,23 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
|
|
|
2181
2754
|
}
|
|
2182
2755
|
return void 0;
|
|
2183
2756
|
}, [displayData, run.workflowName]);
|
|
2757
|
+
const moduleSourceUrl = reactExports.useMemo(() => {
|
|
2758
|
+
if (!getModuleSourceUrl || !moduleSpecifier)
|
|
2759
|
+
return void 0;
|
|
2760
|
+
const parsed = parseStepName(moduleSpecifier) ?? parseWorkflowName(moduleSpecifier);
|
|
2761
|
+
if (!parsed)
|
|
2762
|
+
return void 0;
|
|
2763
|
+
const dataDeploymentId = displayData.deploymentId;
|
|
2764
|
+
return getModuleSourceUrl({
|
|
2765
|
+
moduleSpecifier: parsed.moduleSpecifier,
|
|
2766
|
+
deploymentId: typeof dataDeploymentId === "string" ? dataDeploymentId : run.deploymentId
|
|
2767
|
+
});
|
|
2768
|
+
}, [getModuleSourceUrl, moduleSpecifier, displayData, run.deploymentId]);
|
|
2184
2769
|
if (!selectedSpan || !resource || !resourceId) {
|
|
2185
2770
|
return null;
|
|
2186
2771
|
}
|
|
2187
2772
|
const hasPendingActions = resource === "sleep" && canWakeUp || resource === "hook" && canResolveHook;
|
|
2188
|
-
return jsxRuntimeExports.jsxs("div", { className: "flex h-full flex-col", children: [jsxRuntimeExports.jsx(DecryptClickContext.Provider, { value: onDecrypt ? { onDecrypt, isDecrypting } : void 0, children: jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto px-
|
|
2773
|
+
return jsxRuntimeExports.jsxs("div", { className: "flex h-full flex-col", children: [jsxRuntimeExports.jsx(DecryptClickContext.Provider, { value: onDecrypt ? { onDecrypt, isDecrypting, hasEncryptedData } : void 0, children: jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto px-4 pb-8", children: [hasPendingActions && jsxRuntimeExports.jsxs("div", { className: "mb-4 rounded-lg border p-2", style: {
|
|
2189
2774
|
borderColor: "var(--ds-gray-300)",
|
|
2190
2775
|
backgroundColor: "var(--ds-gray-100)"
|
|
2191
2776
|
}, children: [jsxRuntimeExports.jsx("p", { className: "mb-2 px-1 text-[13px] font-medium uppercase tracking-wide", style: { color: "var(--ds-gray-700)" }, children: "Actions" }), jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [resource === "sleep" && canWakeUp && jsxRuntimeExports.jsxs("button", { type: "button", onClick: handleWakeUp, disabled: stoppingSleep, className: clsx("flex items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium", "disabled:opacity-50 disabled:cursor-not-allowed transition-colors", stoppingSleep ? "opacity-50 cursor-not-allowed" : "cursor-pointer"), style: {
|
|
@@ -2194,125 +2779,319 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
|
|
|
2194
2779
|
}, children: [jsxRuntimeExports.jsx(Zap, { className: "h-4 w-4" }), stoppingSleep ? "Waking up..." : "Wake Up Sleep"] }), resource === "hook" && canResolveHook && jsxRuntimeExports.jsxs("button", { type: "button", onClick: () => setShowResolveHookModal(true), disabled: resolvingHook, className: clsx("flex items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium", "disabled:opacity-50 disabled:cursor-not-allowed transition-colors", resolvingHook ? "opacity-50 cursor-not-allowed" : "cursor-pointer"), style: {
|
|
2195
2780
|
background: "var(--ds-gray-1000)",
|
|
2196
2781
|
color: "var(--ds-background-100)"
|
|
2197
|
-
}, children: [jsxRuntimeExports.jsx(Send, { className: "h-4 w-4" }), "Resolve Hook"] })] })] }), jsxRuntimeExports.
|
|
2782
|
+
}, children: [jsxRuntimeExports.jsx(Send, { className: "h-4 w-4" }), "Resolve Hook"] })] })] }), jsxRuntimeExports.jsx(AttributePanel, { data: displayData, moduleSpecifier, moduleSourceUrl, expiredAt: run.expiredAt, isLoading: loading, error: error ?? void 0, onStreamClick, onRunClick, onDecrypt, isDecrypting, resource }), rawEvents && jsxRuntimeExports.jsx(EventsList, { events: rawEvents, onLoadEventData, onStreamClick, onRunClick, encryptionKey, showSeparateEventOccurrenceTimestamps })] }) }), jsxRuntimeExports.jsx(ResolveHookModal, { isOpen: showResolveHookModal, onClose: () => setShowResolveHookModal(false), onSubmit: handleResolveHook, isSubmitting: resolvingHook })] });
|
|
2198
2783
|
}
|
|
2199
|
-
function
|
|
2200
|
-
const [
|
|
2201
|
-
const
|
|
2784
|
+
function useIntersectionObserver(elementRef, { threshold = 0, rootRef, rootMargin = "0%", freezeOnceVisible = false } = {}) {
|
|
2785
|
+
const [entry, setEntry] = reactExports.useState();
|
|
2786
|
+
const frozen = (entry == null ? void 0 : entry.isIntersecting) && freezeOnceVisible;
|
|
2202
2787
|
reactExports.useEffect(() => {
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2788
|
+
const node = elementRef == null ? void 0 : elementRef.current;
|
|
2789
|
+
const hasIOSupport = !!window.IntersectionObserver;
|
|
2790
|
+
if (!hasIOSupport || frozen || !node)
|
|
2791
|
+
return;
|
|
2792
|
+
const updateEntry = ([entry2]) => {
|
|
2793
|
+
setEntry(entry2);
|
|
2207
2794
|
};
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
clearTimeout(timeoutRef.current);
|
|
2213
|
-
}
|
|
2214
|
-
void navigator.clipboard.writeText(copyText).then(() => {
|
|
2215
|
-
setCopied(true);
|
|
2216
|
-
timeoutRef.current = setTimeout(() => setCopied(false), 1e3);
|
|
2795
|
+
const observer = new IntersectionObserver(updateEntry, {
|
|
2796
|
+
threshold,
|
|
2797
|
+
root: (rootRef == null ? void 0 : rootRef.current) ?? null,
|
|
2798
|
+
rootMargin
|
|
2217
2799
|
});
|
|
2218
|
-
|
|
2800
|
+
observer.observe(node);
|
|
2801
|
+
return () => observer.disconnect();
|
|
2802
|
+
}, [elementRef, threshold, rootRef, rootMargin, frozen]);
|
|
2803
|
+
return entry;
|
|
2219
2804
|
}
|
|
2220
|
-
|
|
2221
|
-
const
|
|
2222
|
-
const
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2805
|
+
function useLoadMoreOnScroll(loadMore, { hasMore, isLoadingMore, rootRef, rootMargin = "400px" }) {
|
|
2806
|
+
const sentinelRef = reactExports.useRef(null);
|
|
2807
|
+
const entry = useIntersectionObserver(sentinelRef, { rootRef, rootMargin });
|
|
2808
|
+
const loadMoreRef = reactExports.useRef(loadMore);
|
|
2809
|
+
reactExports.useEffect(() => {
|
|
2810
|
+
loadMoreRef.current = loadMore;
|
|
2811
|
+
}, [loadMore]);
|
|
2812
|
+
reactExports.useEffect(() => {
|
|
2813
|
+
if ((entry == null ? void 0 : entry.isIntersecting) && hasMore && !isLoadingMore) {
|
|
2814
|
+
loadMoreRef.current();
|
|
2815
|
+
}
|
|
2816
|
+
}, [entry == null ? void 0 : entry.isIntersecting, hasMore, isLoadingMore]);
|
|
2817
|
+
return sentinelRef;
|
|
2818
|
+
}
|
|
2819
|
+
const kbdVariants = cva("inline-flex items-center justify-center rounded px-1 text-center font-sans", {
|
|
2820
|
+
variants: {
|
|
2821
|
+
variant: {
|
|
2822
|
+
subtle: "bg-background-100/20",
|
|
2823
|
+
outline: "border border-gray-alpha-400 bg-background-100 font-medium text-gray-900"
|
|
2824
|
+
},
|
|
2825
|
+
size: {
|
|
2826
|
+
default: "h-5 min-w-5 text-xs leading-none",
|
|
2827
|
+
compact: "h-4 min-h-4 min-w-4 text-[11px] leading-none",
|
|
2828
|
+
search: "h-5 min-h-5 min-w-5 text-[13px] leading-[1.7em]"
|
|
2829
|
+
}
|
|
2830
|
+
},
|
|
2831
|
+
defaultVariants: {
|
|
2832
|
+
variant: "subtle",
|
|
2833
|
+
size: "default"
|
|
2227
2834
|
}
|
|
2228
|
-
|
|
2229
|
-
|
|
2835
|
+
});
|
|
2836
|
+
function Kbd({ children, className, variant, size, ...props }) {
|
|
2837
|
+
return jsxRuntimeExports.jsx("kbd", { className: cn(kbdVariants({ variant, size, className })), ...props, children });
|
|
2838
|
+
}
|
|
2839
|
+
const PANEL_MIN_WIDTH = 280;
|
|
2840
|
+
const PANEL_HARD_MAX_WIDTH = 1300;
|
|
2841
|
+
const PANEL_DEFAULT_WIDTH = 360;
|
|
2842
|
+
const MAIN_MIN_WIDTH = 400;
|
|
2843
|
+
const PANEL_WIDTH_STORAGE_KEY = "workflow-trace-detail-panel-width";
|
|
2844
|
+
function clamp(value, min, max) {
|
|
2845
|
+
return Math.min(Math.max(value, min), max);
|
|
2846
|
+
}
|
|
2847
|
+
function computeMaxPanelWidth(availableWidth) {
|
|
2848
|
+
if (availableWidth <= 0)
|
|
2849
|
+
return PANEL_HARD_MAX_WIDTH;
|
|
2850
|
+
return Math.min(Math.max(availableWidth - MAIN_MIN_WIDTH, 0), PANEL_HARD_MAX_WIDTH);
|
|
2851
|
+
}
|
|
2852
|
+
function clampPanelWidth(width, availableWidth) {
|
|
2853
|
+
return clamp(width, PANEL_MIN_WIDTH, computeMaxPanelWidth(availableWidth));
|
|
2854
|
+
}
|
|
2855
|
+
function readStoredPanelWidth() {
|
|
2856
|
+
if (typeof window === "undefined")
|
|
2857
|
+
return PANEL_DEFAULT_WIDTH;
|
|
2858
|
+
try {
|
|
2859
|
+
const raw = window.localStorage.getItem(PANEL_WIDTH_STORAGE_KEY);
|
|
2860
|
+
const value = raw ? Number(raw) : Number.NaN;
|
|
2861
|
+
if (!Number.isFinite(value))
|
|
2862
|
+
return PANEL_DEFAULT_WIDTH;
|
|
2863
|
+
return clamp(value, PANEL_MIN_WIDTH, PANEL_HARD_MAX_WIDTH);
|
|
2864
|
+
} catch {
|
|
2865
|
+
return PANEL_DEFAULT_WIDTH;
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
function writeStoredPanelWidth(width) {
|
|
2869
|
+
if (typeof window === "undefined")
|
|
2870
|
+
return;
|
|
2871
|
+
try {
|
|
2872
|
+
window.localStorage.setItem(PANEL_WIDTH_STORAGE_KEY, String(Math.round(width)));
|
|
2873
|
+
} catch {
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
function DraggableBorder({ element, position, onWidthChange, onReset, "aria-label": ariaLabel, "aria-controls": ariaControls, "aria-valuemin": ariaValueMin, "aria-valuemax": ariaValueMax, "aria-valuenow": ariaValueNow }) {
|
|
2230
2877
|
const [isDragging, setIsDragging] = reactExports.useState(false);
|
|
2231
|
-
const containerRef = reactExports.useRef(null);
|
|
2232
|
-
const gutterRef = reactExports.useRef(null);
|
|
2233
|
-
const rafRef = reactExports.useRef(null);
|
|
2234
|
-
const pendingPx = reactExports.useRef(defaultStartWidth);
|
|
2235
2878
|
const pointerIdRef = reactExports.useRef(null);
|
|
2879
|
+
const startXRef = reactExports.useRef(0);
|
|
2880
|
+
const startWidthRef = reactExports.useRef(0);
|
|
2881
|
+
const pendingWidthRef = reactExports.useRef(0);
|
|
2882
|
+
const rafRef = reactExports.useRef(null);
|
|
2883
|
+
const movedRef = reactExports.useRef(false);
|
|
2884
|
+
const lastDragEndAtRef = reactExports.useRef(0);
|
|
2236
2885
|
reactExports.useEffect(() => {
|
|
2237
2886
|
return () => {
|
|
2238
2887
|
if (rafRef.current)
|
|
2239
2888
|
cancelAnimationFrame(rafRef.current);
|
|
2240
2889
|
};
|
|
2241
|
-
}, []);
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
return
|
|
2248
|
-
|
|
2890
|
+
}, []);
|
|
2891
|
+
reactExports.useEffect(() => {
|
|
2892
|
+
if (!isDragging)
|
|
2893
|
+
return;
|
|
2894
|
+
const previous = document.body.style.userSelect;
|
|
2895
|
+
document.body.style.userSelect = "none";
|
|
2896
|
+
return () => {
|
|
2897
|
+
document.body.style.userSelect = previous;
|
|
2898
|
+
};
|
|
2899
|
+
}, [isDragging]);
|
|
2900
|
+
const stopDrag = () => {
|
|
2901
|
+
pointerIdRef.current = null;
|
|
2902
|
+
setIsDragging(false);
|
|
2903
|
+
if (rafRef.current) {
|
|
2904
|
+
cancelAnimationFrame(rafRef.current);
|
|
2905
|
+
rafRef.current = null;
|
|
2906
|
+
if (movedRef.current)
|
|
2907
|
+
onWidthChange(pendingWidthRef.current);
|
|
2908
|
+
}
|
|
2909
|
+
if (movedRef.current) {
|
|
2910
|
+
movedRef.current = false;
|
|
2911
|
+
lastDragEndAtRef.current = performance.now();
|
|
2912
|
+
}
|
|
2913
|
+
};
|
|
2914
|
+
const handlePointerDown = (e) => {
|
|
2915
|
+
if (pointerIdRef.current !== null)
|
|
2916
|
+
return;
|
|
2917
|
+
const el = element.current;
|
|
2918
|
+
if (!el)
|
|
2919
|
+
return;
|
|
2920
|
+
if (e.pointerType === "mouse" && e.button !== 0)
|
|
2921
|
+
return;
|
|
2922
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
2923
|
+
pointerIdRef.current = e.pointerId;
|
|
2924
|
+
startXRef.current = e.clientX;
|
|
2925
|
+
startWidthRef.current = el.offsetWidth;
|
|
2926
|
+
movedRef.current = false;
|
|
2927
|
+
setIsDragging(true);
|
|
2928
|
+
};
|
|
2929
|
+
const handlePointerMove = (e) => {
|
|
2930
|
+
if (pointerIdRef.current !== e.pointerId)
|
|
2931
|
+
return;
|
|
2932
|
+
if (Math.abs(e.clientX - startXRef.current) > 4) {
|
|
2933
|
+
movedRef.current = true;
|
|
2934
|
+
}
|
|
2935
|
+
const delta = position === "left" ? startXRef.current - e.clientX : e.clientX - startXRef.current;
|
|
2936
|
+
pendingWidthRef.current = startWidthRef.current + delta;
|
|
2937
|
+
if (!rafRef.current) {
|
|
2938
|
+
rafRef.current = requestAnimationFrame(() => {
|
|
2939
|
+
rafRef.current = null;
|
|
2940
|
+
onWidthChange(pendingWidthRef.current);
|
|
2941
|
+
});
|
|
2942
|
+
}
|
|
2943
|
+
};
|
|
2944
|
+
const handlePointerEnd = (e) => {
|
|
2945
|
+
if (pointerIdRef.current !== e.pointerId)
|
|
2946
|
+
return;
|
|
2947
|
+
stopDrag();
|
|
2948
|
+
};
|
|
2949
|
+
const handleLostPointerCapture = (e) => {
|
|
2950
|
+
if (pointerIdRef.current !== null && e.pointerId !== pointerIdRef.current) {
|
|
2951
|
+
return;
|
|
2952
|
+
}
|
|
2953
|
+
stopDrag();
|
|
2954
|
+
};
|
|
2955
|
+
const handleDoubleClick = () => {
|
|
2956
|
+
if (movedRef.current || performance.now() - lastDragEndAtRef.current < 500) {
|
|
2957
|
+
return;
|
|
2958
|
+
}
|
|
2959
|
+
onReset == null ? void 0 : onReset();
|
|
2960
|
+
};
|
|
2961
|
+
const handleKeyDown = (e) => {
|
|
2962
|
+
const el = element.current;
|
|
2963
|
+
if (!el)
|
|
2964
|
+
return;
|
|
2965
|
+
const step = e.shiftKey ? 64 : 16;
|
|
2966
|
+
const grow = position === "left" ? 1 : -1;
|
|
2967
|
+
let next = null;
|
|
2968
|
+
if (e.key === "ArrowLeft") {
|
|
2969
|
+
next = el.offsetWidth + grow * step;
|
|
2970
|
+
} else if (e.key === "ArrowRight") {
|
|
2971
|
+
next = el.offsetWidth - grow * step;
|
|
2972
|
+
} else if (e.key === "Home" && ariaValueMin !== void 0) {
|
|
2973
|
+
next = ariaValueMin;
|
|
2974
|
+
} else if (e.key === "End" && ariaValueMax !== void 0) {
|
|
2975
|
+
next = ariaValueMax;
|
|
2976
|
+
}
|
|
2977
|
+
if (next === null)
|
|
2978
|
+
return;
|
|
2979
|
+
e.preventDefault();
|
|
2980
|
+
onWidthChange(next);
|
|
2981
|
+
};
|
|
2982
|
+
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") }) });
|
|
2983
|
+
}
|
|
2984
|
+
function useElementWidth(ref, enabled = true) {
|
|
2985
|
+
const [width, setWidth] = reactExports.useState(0);
|
|
2986
|
+
reactExports.useLayoutEffect(() => {
|
|
2987
|
+
if (!enabled)
|
|
2988
|
+
return;
|
|
2989
|
+
const el = ref.current;
|
|
2990
|
+
if (!el)
|
|
2991
|
+
return;
|
|
2992
|
+
setWidth(Math.round(el.getBoundingClientRect().width));
|
|
2993
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
2994
|
+
setWidth(Math.round((entry == null ? void 0 : entry.contentRect.width) ?? 0));
|
|
2995
|
+
});
|
|
2996
|
+
observer.observe(el);
|
|
2997
|
+
return () => observer.disconnect();
|
|
2998
|
+
}, [ref, enabled]);
|
|
2999
|
+
return width;
|
|
3000
|
+
}
|
|
3001
|
+
const DETAIL_PANEL_ID = "trace-detail-panel";
|
|
3002
|
+
function useSelectedSpanInfo() {
|
|
3003
|
+
const { activeSpan } = useActiveSpan();
|
|
3004
|
+
const sidebar = useSidebarData();
|
|
3005
|
+
return reactExports.useMemo(() => {
|
|
3006
|
+
var _a, _b;
|
|
3007
|
+
if (!activeSpan)
|
|
3008
|
+
return null;
|
|
3009
|
+
const resource = (_a = activeSpan.attributes) == null ? void 0 : _a.resource;
|
|
3010
|
+
const rawEvents = filterSpanRawEvents(sidebar.events, resource, activeSpan.spanId);
|
|
3011
|
+
return {
|
|
3012
|
+
data: (_b = activeSpan.attributes) == null ? void 0 : _b.data,
|
|
3013
|
+
resource,
|
|
3014
|
+
spanId: activeSpan.spanId,
|
|
3015
|
+
rawEvents
|
|
3016
|
+
};
|
|
3017
|
+
}, [activeSpan, sidebar]);
|
|
3018
|
+
}
|
|
3019
|
+
function TraceDetailPanel({ containerRef, onNavigateToSpan, onClose }) {
|
|
3020
|
+
const { activeSpan, activeSpanId, spans } = useActiveSpan();
|
|
3021
|
+
const sidebar = useSidebarData();
|
|
3022
|
+
const selectedSpan = useSelectedSpanInfo();
|
|
3023
|
+
const isOpen = Boolean(activeSpan);
|
|
3024
|
+
const [storedWidth, setStoredWidth] = reactExports.useState(() => readStoredPanelWidth());
|
|
3025
|
+
const containerWidth = useElementWidth(containerRef, isOpen);
|
|
3026
|
+
const asideRef = reactExports.useRef(null);
|
|
3027
|
+
const handleResize = reactExports.useCallback((next) => {
|
|
3028
|
+
const clamped = clampPanelWidth(next, containerWidth);
|
|
3029
|
+
setStoredWidth(clamped);
|
|
3030
|
+
writeStoredPanelWidth(clamped);
|
|
3031
|
+
}, [containerWidth]);
|
|
3032
|
+
const panelWidth = clampPanelWidth(storedWidth, containerWidth);
|
|
3033
|
+
const panelMaxWidth = Math.max(PANEL_MIN_WIDTH, computeMaxPanelWidth(containerWidth));
|
|
3034
|
+
const { prevSpanId, nextSpanId } = reactExports.useMemo(() => {
|
|
3035
|
+
var _a, _b;
|
|
3036
|
+
if (!activeSpanId)
|
|
3037
|
+
return { prevSpanId: null, nextSpanId: null };
|
|
3038
|
+
const i = spans.findIndex((s) => s.spanId === activeSpanId);
|
|
3039
|
+
if (i === -1)
|
|
3040
|
+
return { prevSpanId: null, nextSpanId: null };
|
|
3041
|
+
return {
|
|
3042
|
+
prevSpanId: ((_a = spans[i - 1]) == null ? void 0 : _a.spanId) ?? null,
|
|
3043
|
+
nextSpanId: ((_b = spans[i + 1]) == null ? void 0 : _b.spanId) ?? null
|
|
3044
|
+
};
|
|
3045
|
+
}, [activeSpanId, spans]);
|
|
3046
|
+
const handleSelectPrev = reactExports.useCallback(() => {
|
|
3047
|
+
if (prevSpanId)
|
|
3048
|
+
onNavigateToSpan(prevSpanId);
|
|
3049
|
+
}, [prevSpanId, onNavigateToSpan]);
|
|
3050
|
+
const handleSelectNext = reactExports.useCallback(() => {
|
|
3051
|
+
if (nextSpanId)
|
|
3052
|
+
onNavigateToSpan(nextSpanId);
|
|
3053
|
+
}, [nextSpanId, onNavigateToSpan]);
|
|
2249
3054
|
reactExports.useEffect(() => {
|
|
2250
|
-
if (!
|
|
3055
|
+
if (!isOpen)
|
|
2251
3056
|
return;
|
|
2252
|
-
const
|
|
2253
|
-
if (e.
|
|
2254
|
-
return;
|
|
2255
|
-
const container = containerRef.current;
|
|
2256
|
-
if (!container)
|
|
3057
|
+
const onKeyDown = (e) => {
|
|
3058
|
+
if (e.key !== "j" && e.key !== "k" && e.key !== "ArrowDown" && e.key !== "ArrowUp") {
|
|
2257
3059
|
return;
|
|
2258
|
-
const rect = container.getBoundingClientRect();
|
|
2259
|
-
pendingPx.current = clampPx(e.clientX - rect.left);
|
|
2260
|
-
if (!rafRef.current) {
|
|
2261
|
-
rafRef.current = requestAnimationFrame(() => {
|
|
2262
|
-
rafRef.current = null;
|
|
2263
|
-
setStartPx(pendingPx.current);
|
|
2264
|
-
});
|
|
2265
3060
|
}
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
if (e.pointerId !== pointerIdRef.current)
|
|
3061
|
+
const target = e.target;
|
|
3062
|
+
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || (target == null ? void 0 : target.isContentEditable)) {
|
|
2269
3063
|
return;
|
|
2270
|
-
const gutter2 = gutterRef.current;
|
|
2271
|
-
if (gutter2 == null ? void 0 : gutter2.hasPointerCapture(e.pointerId)) {
|
|
2272
|
-
gutter2.releasePointerCapture(e.pointerId);
|
|
2273
3064
|
}
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
3065
|
+
const targetId = e.key === "k" || e.key === "ArrowUp" ? prevSpanId : nextSpanId;
|
|
3066
|
+
if (targetId) {
|
|
3067
|
+
e.preventDefault();
|
|
3068
|
+
onNavigateToSpan(targetId);
|
|
2277
3069
|
}
|
|
2278
|
-
pointerIdRef.current = null;
|
|
2279
|
-
setIsDragging(false);
|
|
2280
3070
|
};
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
e.currentTarget.setPointerCapture(e.pointerId);
|
|
2292
|
-
pointerIdRef.current = e.pointerId;
|
|
2293
|
-
setIsDragging(true);
|
|
2294
|
-
};
|
|
2295
|
-
const handleLostPointerCapture = () => {
|
|
2296
|
-
pointerIdRef.current = null;
|
|
2297
|
-
setIsDragging(false);
|
|
2298
|
-
if (rafRef.current) {
|
|
2299
|
-
cancelAnimationFrame(rafRef.current);
|
|
2300
|
-
rafRef.current = null;
|
|
3071
|
+
window.addEventListener("keydown", onKeyDown);
|
|
3072
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
3073
|
+
}, [isOpen, prevSpanId, nextSpanId, onNavigateToSpan]);
|
|
3074
|
+
const selectedSpanName = reactExports.useMemo(() => {
|
|
3075
|
+
var _a, _b;
|
|
3076
|
+
if (!(selectedSpan == null ? void 0 : selectedSpan.data))
|
|
3077
|
+
return "Details";
|
|
3078
|
+
const data = selectedSpan.data;
|
|
3079
|
+
if (selectedSpan.resource === "hook") {
|
|
3080
|
+
return data.token ?? data.hookId;
|
|
2301
3081
|
}
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
if (
|
|
2307
|
-
return
|
|
2308
|
-
}
|
|
2309
|
-
return jsxRuntimeExports.jsxs("div", { ref: containerRef, 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] });
|
|
3082
|
+
const stepName = data.stepName;
|
|
3083
|
+
const workflowName = data.workflowName;
|
|
3084
|
+
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";
|
|
3085
|
+
}, [selectedSpan == null ? void 0 : selectedSpan.data, selectedSpan == null ? void 0 : selectedSpan.resource]);
|
|
3086
|
+
if (!activeSpan)
|
|
3087
|
+
return null;
|
|
3088
|
+
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, getModuleSourceUrl: sidebar.getModuleSourceUrl }) }) })] });
|
|
2310
3089
|
}
|
|
2311
3090
|
const WorkflowIcon = () => {
|
|
2312
|
-
return jsxRuntimeExports.jsx("svg", { "data-testid": "geist-icon", height: "16",
|
|
3091
|
+
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" }) });
|
|
2313
3092
|
};
|
|
2314
3093
|
const WebhookIcon = () => {
|
|
2315
|
-
return jsxRuntimeExports.jsx("svg", { "data-testid": "geist-icon", height: "16",
|
|
3094
|
+
return jsxRuntimeExports.jsx("svg", { "data-testid": "geist-icon", height: "16", strokeLinejoin: "round", viewBox: "0 0 16 16", width: "16", style: { color: "currentColor" }, children: jsxRuntimeExports.jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M5.8349 3.24994C5.14454 4.44567 5.55423 5.97464 6.74996 6.665L7.39465 7.03721L7.02726 7.68466L5.14599 11C5.21289 11.1531 5.25 11.3222 5.25 11.5C5.25 12.1904 4.69036 12.75 4 12.75C3.30964 12.75 2.75 12.1904 2.75 11.5C2.75 10.8634 3.22584 10.338 3.84123 10.26L5.38944 7.5316C3.95909 6.30274 3.55857 4.19264 4.53586 2.49994C5.64043 0.586765 8.08679 -0.0687357 9.99996 1.03583C11.836 2.09584 12.5137 4.39156 11.5892 6.26591L10.4949 4.33754C10.4418 3.53274 10.0009 2.76843 9.24996 2.33487C8.05423 1.64452 6.52525 2.0542 5.8349 3.24994ZM9.146 4.99996C9.21289 4.84686 9.25 4.67776 9.25 4.5C9.25 3.80964 8.69036 3.25 8 3.25C7.30964 3.25 6.75 3.80964 6.75 4.5C6.75 5.13659 7.22586 5.66203 7.84127 5.74002L9.72266 9.05556L10.0956 9.71274L10.75 9.33493C11.9457 8.64458 13.4747 9.05427 14.165 10.25C14.8554 11.4457 14.4457 12.9747 13.25 13.6651C12.5047 14.0953 11.63 14.0983 10.9096 13.75H8.69252C9.85895 15.4685 12.1727 16.0191 14 14.9641C15.9131 13.8595 16.5686 11.4132 15.4641 9.5C14.4886 7.81038 12.4665 7.10169 10.6895 7.71998L9.146 4.99996ZM13.25 11.5C13.25 12.1904 12.6904 12.75 12 12.75C11.591 12.75 11.228 12.5536 10.9999 12.25H7.9298C7.57875 14.1006 5.95279 15.5 4 15.5C1.79086 15.5 0 13.7091 0 11.5C0 9.40018 1.61801 7.67826 3.67529 7.51299L2.58098 9.44147C1.92792 9.89251 1.5 10.6463 1.5 11.5C1.5 12.8807 2.61929 14 4 14C5.38071 14 6.5 12.8807 6.5 11.5V10.75H7.25H10.9999C11.228 10.4464 11.591 10.25 12 10.25C12.6904 10.25 13.25 10.8096 13.25 11.5Z", fill: "currentColor" }) });
|
|
2316
3095
|
};
|
|
2317
3096
|
const SleepIcon = () => {
|
|
2318
3097
|
return jsxRuntimeExports.jsx("svg", { "data-testid": "geist-icon", height: "16", strokeLinejoin: "round", viewBox: "0 0 16 16", width: "16", style: { color: "currentColor" }, children: jsxRuntimeExports.jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M7.25 1.25V2.03971C5.87928 2.18571 4.62678 2.72736 3.6089 3.54824L3.03033 2.96967L2.5 2.43934L1.43934 3.5L1.96967 4.03033L2.54824 4.6089C1.57979 5.80976 1 7.33717 1 9C1 12.866 4.13401 16 8 16C11.866 16 15 12.866 15 9C15 7.33717 14.4202 5.80976 13.4518 4.6089L14.0303 4.03033L14.5607 3.5L13.5 2.43934L12.9697 2.96967L12.3911 3.54824C11.3732 2.72736 10.1207 2.18571 8.75 2.03971V1.25H9.25H10V-0.25H9.25H8.75H7.25H6.75H6V1.25H6.75H7.25ZM2.5 9C2.5 5.96243 4.96243 3.5 8 3.5C11.0376 3.5 13.5 5.96243 13.5 9C13.5 12.0376 11.0376 14.5 8 14.5C4.96243 14.5 2.5 12.0376 2.5 9ZM8.75 6.75V6H7.25V6.75V9V9.75H8.75V9V6.75Z", fill: "currentColor" }) });
|
|
@@ -2323,13 +3102,14 @@ const StepForwardIcon = () => {
|
|
|
2323
3102
|
const eventStyles = {
|
|
2324
3103
|
run: { icon: WorkflowIcon, className: "text-blue-900" },
|
|
2325
3104
|
step: { icon: StepForwardIcon, className: "text-green-900" },
|
|
2326
|
-
hook: { icon: WebhookIcon, className: "text-
|
|
3105
|
+
hook: { icon: WebhookIcon, className: "text-gray-900" },
|
|
2327
3106
|
sleep: { icon: SleepIcon, className: "text-gray-900" }
|
|
2328
3107
|
};
|
|
2329
3108
|
const defaultStyle = {
|
|
2330
3109
|
icon: Circle,
|
|
2331
3110
|
className: "text-gray-900"
|
|
2332
3111
|
};
|
|
3112
|
+
const ROW_HEIGHT_CLASS = "h-10";
|
|
2333
3113
|
function getEventStyle(resource, isErrored) {
|
|
2334
3114
|
const style = eventStyles[resource] ?? defaultStyle;
|
|
2335
3115
|
return {
|
|
@@ -2337,30 +3117,110 @@ function getEventStyle(resource, isErrored) {
|
|
|
2337
3117
|
className: cn(isErrored ? "text-red-900" : style.className)
|
|
2338
3118
|
};
|
|
2339
3119
|
}
|
|
2340
|
-
const EventRow = ({ span, isSelected, onSelectSpan }) => {
|
|
2341
|
-
const durationMs =
|
|
2342
|
-
const isErrored = span
|
|
3120
|
+
const EventRow = ({ span, isSelected, isDimmed, onSelectSpan }) => {
|
|
3121
|
+
const durationMs = getSpanDurationMs(span);
|
|
3122
|
+
const isErrored = isSpanErrored(span);
|
|
2343
3123
|
const { icon: Icon, className: tagClassName } = getEventStyle(span.resource, isErrored);
|
|
2344
|
-
return jsxRuntimeExports.jsx("li", { className: "overflow-clip group", role: "treeitem", "aria-selected": isSelected, "aria-expanded": isSelected, "aria-level": 1, onClick: () => onSelectSpan(span.spanId), children: jsxRuntimeExports.
|
|
3124
|
+
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) }) })] }) }) });
|
|
2345
3125
|
};
|
|
2346
|
-
const EventList = ({ spans, activeSpanId, onSelectSpan }) => {
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
3126
|
+
const EventList = ({ spans, activeSpanId, searchResult, onSelectSpan }) => {
|
|
3127
|
+
const listRef = reactExports.useRef(null);
|
|
3128
|
+
const { start, end } = useRowWindow(listRef, spans.length, ROW_HEIGHT_PX);
|
|
3129
|
+
return jsxRuntimeExports.jsx("ul", { ref: listRef, id: "event-list", role: "tree", className: "block min-h-0 overflow-visible divide-y divide-gray-400 border-b border-gray-400", style: {
|
|
3130
|
+
paddingTop: start * ROW_HEIGHT_PX,
|
|
3131
|
+
paddingBottom: (spans.length - end) * ROW_HEIGHT_PX
|
|
3132
|
+
}, children: spans.slice(start, end).map((span) => jsxRuntimeExports.jsx(EventRow, { span, isSelected: span.spanId === activeSpanId, isDimmed: isSpanDimmedBySearch(span.spanId, searchResult), onSelectSpan }, span.spanId)) });
|
|
3133
|
+
};
|
|
3134
|
+
const SPLIT_PANE_START_ID = "trace-split-start";
|
|
3135
|
+
function SplitPane({ children, className, startHeader, endHeader, scrollContainerRef }) {
|
|
3136
|
+
const parts = reactExports.Children.toArray(children);
|
|
3137
|
+
if (parts.length !== 2) {
|
|
3138
|
+
throw new Error("SplitPane expects exactly two children");
|
|
3139
|
+
}
|
|
3140
|
+
const [start, end] = parts;
|
|
3141
|
+
const [startPx, setStartPx] = reactExports.useState(DEFAULT_START_PX);
|
|
3142
|
+
const containerRef = reactExports.useRef(null);
|
|
3143
|
+
const startRef = reactExports.useRef(null);
|
|
3144
|
+
const containerWidth = useElementWidth(containerRef);
|
|
3145
|
+
const setContainerRef = reactExports.useCallback((node) => {
|
|
3146
|
+
containerRef.current = node;
|
|
3147
|
+
if (scrollContainerRef) {
|
|
3148
|
+
scrollContainerRef.current = node;
|
|
3149
|
+
}
|
|
3150
|
+
}, [scrollContainerRef]);
|
|
3151
|
+
const clampPx = reactExports.useCallback((px) => {
|
|
3152
|
+
const el = containerRef.current;
|
|
3153
|
+
if (!el)
|
|
3154
|
+
return px;
|
|
3155
|
+
const maxPx = el.getBoundingClientRect().width - MIN_PX - GUTTER_PX;
|
|
3156
|
+
return Math.min(maxPx, Math.max(MIN_PX, px));
|
|
3157
|
+
}, []);
|
|
3158
|
+
const handleWidthChange = reactExports.useCallback((next) => setStartPx(clampPx(next)), [clampPx]);
|
|
3159
|
+
const handleReset = reactExports.useCallback(() => setStartPx(clampPx(DEFAULT_START_PX)), [clampPx]);
|
|
3160
|
+
const effectiveStartPx = containerWidth > 0 ? Math.max(MIN_PX, Math.min(containerWidth - MIN_PX - GUTTER_PX, startPx)) : startPx;
|
|
3161
|
+
const colTemplate = paneColTemplate(effectiveStartPx);
|
|
3162
|
+
const maxStartPx = Math.max(MIN_PX, containerWidth > 0 ? containerWidth - MIN_PX - GUTTER_PX : startPx);
|
|
3163
|
+
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: "grid flex-1 min-h-0 overflow-x-hidden overflow-y-auto", style: { gridTemplateColumns: colTemplate }, children: [jsxRuntimeExports.jsx("div", { ref: startRef, id: SPLIT_PANE_START_ID, className: "min-w-0", children: start }), jsxRuntimeExports.jsxs("div", { className: "relative z-20 isolate flex shrink-0 justify-center", children: [jsxRuntimeExports.jsx("span", { className: "pointer-events-none relative z-10 h-full w-px shrink-0 bg-gray-alpha-400", "aria-hidden": true }), jsxRuntimeExports.jsx(DraggableBorder, { element: startRef, position: "right", onWidthChange: handleWidthChange, onReset: handleReset, "aria-label": "Resize event list", "aria-controls": SPLIT_PANE_START_ID, "aria-valuemin": MIN_PX, "aria-valuemax": maxStartPx, "aria-valuenow": Math.min(Math.max(Math.round(effectiveStartPx), MIN_PX), maxStartPx) })] }), end] })] });
|
|
3164
|
+
}
|
|
3165
|
+
const hint = "_hint_1dmsq_3";
|
|
3166
|
+
const styles = {
|
|
3167
|
+
hint
|
|
2350
3168
|
};
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
3169
|
+
const DISMISSALS_KEY = "workflow-step-shortcut-helper-dismissals";
|
|
3170
|
+
const DISMISSAL_LIMIT = 3;
|
|
3171
|
+
const HINT_ROTATION_MS = 8e3;
|
|
3172
|
+
function getAltKeyLabel() {
|
|
3173
|
+
if (typeof navigator === "undefined")
|
|
3174
|
+
return "Alt";
|
|
3175
|
+
return navigator.platform.toLowerCase().includes("mac") ? "Option" : "Alt";
|
|
3176
|
+
}
|
|
3177
|
+
function readDismissals() {
|
|
3178
|
+
try {
|
|
3179
|
+
const dismissals = Number.parseInt(window.localStorage.getItem(DISMISSALS_KEY) ?? "0", 10);
|
|
3180
|
+
return Number.isNaN(dismissals) ? 0 : dismissals;
|
|
3181
|
+
} catch {
|
|
3182
|
+
return 0;
|
|
3183
|
+
}
|
|
3184
|
+
}
|
|
3185
|
+
function AltHint() {
|
|
3186
|
+
return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: ["Hold", jsxRuntimeExports.jsx(Kbd, { variant: "outline", size: "compact", className: "mx-1", children: getAltKeyLabel() }), "to see delta between spans"] });
|
|
3187
|
+
}
|
|
3188
|
+
function NavHint() {
|
|
3189
|
+
return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: ["Use", jsxRuntimeExports.jsx(Kbd, { variant: "outline", size: "compact", className: "ml-1", children: "J" }), jsxRuntimeExports.jsx("span", { className: "mx-1", children: "/" }), jsxRuntimeExports.jsx(Kbd, { variant: "outline", size: "compact", className: "mr-1", children: "K" }), "to move between spans"] });
|
|
3190
|
+
}
|
|
3191
|
+
function TraceShortcutHelper({ hasMultipleSpans, reducedMotion }) {
|
|
3192
|
+
const [visible, setVisible] = reactExports.useState(false);
|
|
3193
|
+
const [index, setIndex] = reactExports.useState(0);
|
|
3194
|
+
reactExports.useEffect(() => {
|
|
3195
|
+
setVisible(readDismissals() < DISMISSAL_LIMIT);
|
|
3196
|
+
}, []);
|
|
3197
|
+
reactExports.useEffect(() => {
|
|
3198
|
+
if (reducedMotion)
|
|
3199
|
+
return;
|
|
3200
|
+
const id = setInterval(() => {
|
|
3201
|
+
setIndex((i) => i === 0 ? 1 : 0);
|
|
3202
|
+
}, HINT_ROTATION_MS);
|
|
3203
|
+
return () => clearInterval(id);
|
|
3204
|
+
}, [reducedMotion]);
|
|
3205
|
+
if (!visible || !hasMultipleSpans)
|
|
3206
|
+
return null;
|
|
3207
|
+
const dismiss = () => {
|
|
3208
|
+
try {
|
|
3209
|
+
window.localStorage.setItem(DISMISSALS_KEY, String(readDismissals() + 1));
|
|
3210
|
+
} catch {
|
|
3211
|
+
}
|
|
3212
|
+
setVisible(false);
|
|
3213
|
+
};
|
|
3214
|
+
return jsxRuntimeExports.jsxs("div", { className: "group sticky bottom-3 z-10 ml-4 mb-3 hidden h-8 w-fit items-center gap-1 text-xs leading-none text-gray-900 @min-[480px]:flex", children: [jsxRuntimeExports.jsx("span", { "aria-live": "polite", "aria-atomic": "true", className: "inline-flex items-center whitespace-nowrap", children: reducedMotion ? jsxRuntimeExports.jsx(AltHint, {}) : jsxRuntimeExports.jsx("span", { className: `inline-flex items-center ${styles.hint}`, children: index === 0 ? jsxRuntimeExports.jsx(AltHint, {}) : jsxRuntimeExports.jsx(NavHint, {}) }, index) }), jsxRuntimeExports.jsx("button", { type: "button", className: "inline-flex h-5 w-5 items-center justify-center rounded text-muted-foreground opacity-0 transition-opacity hover:bg-accent hover:text-foreground group-hover:opacity-100 focus-visible:opacity-100 motion-reduce:transition-none", onClick: dismiss, "aria-label": "Dismiss trace shortcuts helper", children: jsxRuntimeExports.jsx(X, { className: "h-3 w-3" }) })] });
|
|
2356
3215
|
}
|
|
2357
3216
|
const MIN_VIEWPORT_MS = 1e-3;
|
|
2358
|
-
const
|
|
3217
|
+
const ZOOM_DEBOUNCE_MS = 150;
|
|
2359
3218
|
function useAnimatedViewport(initial) {
|
|
2360
3219
|
const [viewport, setViewportState] = reactExports.useState(initial);
|
|
2361
3220
|
const animRef = reactExports.useRef(null);
|
|
2362
3221
|
const currentRef = reactExports.useRef(initial);
|
|
2363
3222
|
currentRef.current = viewport;
|
|
3223
|
+
const reducedMotion = useReducedMotion();
|
|
2364
3224
|
const cancel = reactExports.useCallback(() => {
|
|
2365
3225
|
if (animRef.current) {
|
|
2366
3226
|
cancelAnimationFrame(animRef.current.raf);
|
|
@@ -2369,11 +3229,16 @@ function useAnimatedViewport(initial) {
|
|
|
2369
3229
|
}, []);
|
|
2370
3230
|
const animateTo = reactExports.useCallback((target) => {
|
|
2371
3231
|
cancel();
|
|
3232
|
+
if (reducedMotion) {
|
|
3233
|
+
currentRef.current = target;
|
|
3234
|
+
setViewportState(target);
|
|
3235
|
+
return;
|
|
3236
|
+
}
|
|
2372
3237
|
const from = currentRef.current;
|
|
2373
3238
|
const anim = { raf: 0, from, to: target, start: performance.now() };
|
|
2374
3239
|
const tick = () => {
|
|
2375
|
-
const t = Math.min((performance.now() - anim.start) /
|
|
2376
|
-
const e =
|
|
3240
|
+
const t = Math.min((performance.now() - anim.start) / 240, 1);
|
|
3241
|
+
const e = t < 0.5 ? 8 * t * t * t * t : 1 - (-2 * t + 2) ** 4 / 2;
|
|
2377
3242
|
setViewportState({
|
|
2378
3243
|
start: anim.from.start + (anim.to.start - anim.from.start) * e,
|
|
2379
3244
|
end: anim.from.end + (anim.to.end - anim.from.end) * e
|
|
@@ -2385,7 +3250,7 @@ function useAnimatedViewport(initial) {
|
|
|
2385
3250
|
};
|
|
2386
3251
|
animRef.current = anim;
|
|
2387
3252
|
anim.raf = requestAnimationFrame(tick);
|
|
2388
|
-
}, [cancel]);
|
|
3253
|
+
}, [cancel, reducedMotion]);
|
|
2389
3254
|
const setViewport = reactExports.useCallback((update) => {
|
|
2390
3255
|
cancel();
|
|
2391
3256
|
if (typeof update === "function") {
|
|
@@ -2402,38 +3267,26 @@ function useAnimatedViewport(initial) {
|
|
|
2402
3267
|
reactExports.useEffect(() => cancel, [cancel]);
|
|
2403
3268
|
return { viewport, setViewport, animateTo };
|
|
2404
3269
|
}
|
|
2405
|
-
function
|
|
2406
|
-
|
|
2407
|
-
const sidebar = useSidebarDataOptional();
|
|
2408
|
-
return reactExports.useMemo(() => {
|
|
2409
|
-
var _a, _b;
|
|
2410
|
-
if (!activeSpan || !sidebar)
|
|
2411
|
-
return null;
|
|
2412
|
-
const correlationId = activeSpan.spanId;
|
|
2413
|
-
const rawEvents = correlationId ? sidebar.events.filter((e) => e.correlationId === correlationId) : [];
|
|
2414
|
-
return {
|
|
2415
|
-
data: (_a = activeSpan.attributes) == null ? void 0 : _a.data,
|
|
2416
|
-
resource: (_b = activeSpan.attributes) == null ? void 0 : _b.resource,
|
|
2417
|
-
spanId: activeSpan.spanId,
|
|
2418
|
-
rawEvents
|
|
2419
|
-
};
|
|
2420
|
-
}, [activeSpan, sidebar == null ? void 0 : sidebar.events]);
|
|
2421
|
-
}
|
|
2422
|
-
function NewTraceViewer$1({ trace }) {
|
|
2423
|
-
return jsxRuntimeExports.jsx(ActiveSpanProvider, { spans: trace.spans, children: jsxRuntimeExports.jsx(NewTraceViewerContent, { trace }) });
|
|
3270
|
+
function NewTraceViewer$1({ trace, onLoadMore, hasMore, isLoadingMore }) {
|
|
3271
|
+
return jsxRuntimeExports.jsx(TooltipProvider, { delayDuration: 300, children: jsxRuntimeExports.jsx(ActiveSpanProvider, { spans: trace.spans, children: jsxRuntimeExports.jsx(NewTraceViewerContent, { trace, onLoadMore, hasMore, isLoadingMore }) }) });
|
|
2424
3272
|
}
|
|
2425
|
-
function NewTraceViewerContent({ trace }) {
|
|
2426
|
-
const {
|
|
2427
|
-
const
|
|
2428
|
-
const selectedSpan = useSelectedSpanInfo();
|
|
3273
|
+
function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
|
|
3274
|
+
const { activeSpanId, setActiveSpan, clearActiveSpan } = useActiveSpan();
|
|
3275
|
+
const reducedMotion = useReducedMotion();
|
|
2429
3276
|
const [searchQuery, setSearchQuery] = reactExports.useState("");
|
|
2430
|
-
const
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
return trace.spans;
|
|
2434
|
-
return trace.spans.filter((s) => s.name.toLowerCase().includes(q) || s.resource.toLowerCase().includes(q));
|
|
2435
|
-
}, [trace.spans, searchQuery]);
|
|
3277
|
+
const deferredSearchQuery = reactExports.useDeferredValue(searchQuery);
|
|
3278
|
+
const paneRootRef = reactExports.useRef(null);
|
|
3279
|
+
const searchResult = reactExports.useMemo(() => searchSpans(trace.spans, deferredSearchQuery), [trace.spans, deferredSearchQuery]);
|
|
2436
3280
|
const root = reactExports.useMemo(() => computeRootBounds(trace.spans), [trace.spans]);
|
|
3281
|
+
const scrollContainerRef = reactExports.useRef(null);
|
|
3282
|
+
const loadMore = reactExports.useCallback(() => {
|
|
3283
|
+
void (onLoadMore == null ? void 0 : onLoadMore());
|
|
3284
|
+
}, [onLoadMore]);
|
|
3285
|
+
const loadMoreSentinelRef = useLoadMoreOnScroll(loadMore, {
|
|
3286
|
+
hasMore: Boolean(onLoadMore && hasMore),
|
|
3287
|
+
isLoadingMore: Boolean(isLoadingMore),
|
|
3288
|
+
rootRef: scrollContainerRef
|
|
3289
|
+
});
|
|
2437
3290
|
const { viewport, setViewport, animateTo } = useAnimatedViewport({
|
|
2438
3291
|
start: root.startTime,
|
|
2439
3292
|
end: root.startTime + root.duration
|
|
@@ -2454,30 +3307,47 @@ function NewTraceViewerContent({ trace }) {
|
|
|
2454
3307
|
return prev;
|
|
2455
3308
|
});
|
|
2456
3309
|
prevRootRef.current = { start: newStart, end: newEnd };
|
|
2457
|
-
}, [root.startTime, root.duration]);
|
|
3310
|
+
}, [root.startTime, root.duration, setViewport]);
|
|
2458
3311
|
const viewDuration = viewport.end - viewport.start;
|
|
2459
|
-
const
|
|
2460
|
-
|
|
3312
|
+
const viewportRef = reactExports.useRef(viewport);
|
|
3313
|
+
viewportRef.current = viewport;
|
|
3314
|
+
const timeMarkers = reactExports.useMemo(() => computeTimeMarkers(viewDuration, viewport.start - root.startTime), [viewDuration, viewport.start, root.startTime]);
|
|
2461
3315
|
const resetZoom = reactExports.useCallback(() => {
|
|
2462
3316
|
animateTo({ start: root.startTime, end: root.startTime + root.duration });
|
|
2463
3317
|
}, [animateTo, root.startTime, root.duration]);
|
|
2464
|
-
const
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
3318
|
+
const clampToRoot = reactExports.useCallback((next) => clampViewportToRoot(next, root.startTime, root.endTime, MIN_VIEWPORT_MS), [root.startTime, root.endTime]);
|
|
3319
|
+
const handleRevealTime = reactExports.useCallback((timeMs) => {
|
|
3320
|
+
const { start, end } = viewportRef.current;
|
|
3321
|
+
const duration = end - start;
|
|
3322
|
+
animateTo(clampToRoot({
|
|
3323
|
+
start: timeMs - duration / 2,
|
|
3324
|
+
end: timeMs + duration / 2
|
|
3325
|
+
}));
|
|
3326
|
+
}, [animateTo, clampToRoot]);
|
|
3327
|
+
const ZOOM_FACTOR = 0.5;
|
|
3328
|
+
const zoomBy = reactExports.useCallback((factor) => {
|
|
3329
|
+
setViewport((prev) => {
|
|
3330
|
+
const center = (prev.start + prev.end) / 2;
|
|
3331
|
+
const newDuration = Math.max(MIN_VIEWPORT_MS, (prev.end - prev.start) * factor);
|
|
3332
|
+
return clampToRoot({
|
|
3333
|
+
start: center - newDuration / 2,
|
|
3334
|
+
end: center + newDuration / 2
|
|
3335
|
+
});
|
|
3336
|
+
});
|
|
3337
|
+
}, [setViewport, clampToRoot]);
|
|
3338
|
+
const zoomIn = reactExports.useCallback(() => zoomBy(ZOOM_FACTOR), [zoomBy]);
|
|
3339
|
+
const zoomOut = reactExports.useCallback(() => zoomBy(1 / ZOOM_FACTOR), [zoomBy]);
|
|
3340
|
+
const isAtMinZoom = viewDuration >= root.duration;
|
|
3341
|
+
const isAtMaxZoom = viewDuration <= MIN_VIEWPORT_MS;
|
|
3342
|
+
const focusViewportOnSpan = reactExports.useCallback((spanId) => {
|
|
2470
3343
|
const span = trace.spans.find((s) => s.spanId === spanId);
|
|
2471
3344
|
if (!span)
|
|
2472
3345
|
return;
|
|
2473
3346
|
const spanStart = getHighResInMs(span.startTime);
|
|
2474
3347
|
const spanEnd = getHighResInMs(span.endTime);
|
|
2475
3348
|
const spanDuration = spanEnd - spanStart;
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
const rootD = root.duration;
|
|
2479
|
-
if (spanDuration > rootD * 0.8) {
|
|
2480
|
-
animateTo({ start: rootS, end: rootE });
|
|
3349
|
+
if (spanDuration > root.duration * 0.8) {
|
|
3350
|
+
animateTo({ start: root.startTime, end: root.endTime });
|
|
2481
3351
|
return;
|
|
2482
3352
|
}
|
|
2483
3353
|
const padding = Math.max(spanDuration * 0.2, MIN_VIEWPORT_MS / 2);
|
|
@@ -2488,34 +3358,67 @@ function NewTraceViewerContent({ trace }) {
|
|
|
2488
3358
|
newStart = center - MIN_VIEWPORT_MS / 2;
|
|
2489
3359
|
newEnd = center + MIN_VIEWPORT_MS / 2;
|
|
2490
3360
|
}
|
|
2491
|
-
|
|
2492
|
-
const duration = newEnd - newStart;
|
|
2493
|
-
newStart = rootS;
|
|
2494
|
-
newEnd = Math.min(rootE, rootS + duration);
|
|
2495
|
-
}
|
|
2496
|
-
if (newEnd > rootE) {
|
|
2497
|
-
const duration = newEnd - newStart;
|
|
2498
|
-
newEnd = rootE;
|
|
2499
|
-
newStart = Math.max(rootS, rootE - duration);
|
|
2500
|
-
}
|
|
2501
|
-
animateTo({ start: newStart, end: newEnd });
|
|
3361
|
+
animateTo(clampToRoot({ start: newStart, end: newEnd }));
|
|
2502
3362
|
}, [
|
|
2503
3363
|
animateTo,
|
|
2504
|
-
setActiveSpan,
|
|
2505
|
-
clearActiveSpan,
|
|
2506
|
-
activeSpanId,
|
|
2507
3364
|
trace.spans,
|
|
2508
3365
|
root.startTime,
|
|
2509
|
-
root.
|
|
3366
|
+
root.endTime,
|
|
3367
|
+
root.duration,
|
|
3368
|
+
clampToRoot
|
|
3369
|
+
]);
|
|
3370
|
+
const scrollSpanIntoView = reactExports.useCallback((spanId) => {
|
|
3371
|
+
var _a;
|
|
3372
|
+
const index = trace.spans.findIndex((s) => s.spanId === spanId);
|
|
3373
|
+
if (index === -1)
|
|
3374
|
+
return;
|
|
3375
|
+
const list = ((_a = scrollContainerRef.current) == null ? void 0 : _a.querySelector("#event-list")) ?? null;
|
|
3376
|
+
scrollRowIntoView(list, index, ROW_HEIGHT_PX, {
|
|
3377
|
+
behavior: reducedMotion ? "auto" : "smooth"
|
|
3378
|
+
});
|
|
3379
|
+
}, [trace.spans, reducedMotion]);
|
|
3380
|
+
const zoomTimerRef = reactExports.useRef(null);
|
|
3381
|
+
const cancelPendingZoom = reactExports.useCallback(() => {
|
|
3382
|
+
if (zoomTimerRef.current !== null) {
|
|
3383
|
+
clearTimeout(zoomTimerRef.current);
|
|
3384
|
+
zoomTimerRef.current = null;
|
|
3385
|
+
}
|
|
3386
|
+
}, []);
|
|
3387
|
+
reactExports.useEffect(() => cancelPendingZoom, [cancelPendingZoom]);
|
|
3388
|
+
const handleClearActiveSpan = reactExports.useCallback(() => {
|
|
3389
|
+
cancelPendingZoom();
|
|
3390
|
+
clearActiveSpan();
|
|
3391
|
+
}, [cancelPendingZoom, clearActiveSpan]);
|
|
3392
|
+
const handleSelectSpan = reactExports.useCallback((spanId) => {
|
|
3393
|
+
cancelPendingZoom();
|
|
3394
|
+
if (spanId === activeSpanId) {
|
|
3395
|
+
clearActiveSpan();
|
|
3396
|
+
return;
|
|
3397
|
+
}
|
|
3398
|
+
setActiveSpan(spanId);
|
|
3399
|
+
focusViewportOnSpan(spanId);
|
|
3400
|
+
}, [
|
|
3401
|
+
cancelPendingZoom,
|
|
3402
|
+
activeSpanId,
|
|
3403
|
+
clearActiveSpan,
|
|
3404
|
+
setActiveSpan,
|
|
3405
|
+
focusViewportOnSpan
|
|
2510
3406
|
]);
|
|
3407
|
+
const navigateToSpan = reactExports.useCallback((spanId) => {
|
|
3408
|
+
setActiveSpan(spanId);
|
|
3409
|
+
scrollSpanIntoView(spanId);
|
|
3410
|
+
cancelPendingZoom();
|
|
3411
|
+
zoomTimerRef.current = setTimeout(() => {
|
|
3412
|
+
zoomTimerRef.current = null;
|
|
3413
|
+
focusViewportOnSpan(spanId);
|
|
3414
|
+
}, ZOOM_DEBOUNCE_MS);
|
|
3415
|
+
}, [setActiveSpan, scrollSpanIntoView, cancelPendingZoom, focusViewportOnSpan]);
|
|
2511
3416
|
const [altHeld, setAltHeld] = reactExports.useState(false);
|
|
2512
3417
|
reactExports.useEffect(() => {
|
|
2513
3418
|
const onKeyDown = (e) => {
|
|
2514
3419
|
if (e.key === "Escape") {
|
|
2515
|
-
|
|
2516
|
-
}
|
|
2517
|
-
if (e.key === "Alt") {
|
|
2518
|
-
e.preventDefault();
|
|
3420
|
+
handleClearActiveSpan();
|
|
3421
|
+
} else if (e.key === "Alt") {
|
|
2519
3422
|
setAltHeld(true);
|
|
2520
3423
|
}
|
|
2521
3424
|
};
|
|
@@ -2532,26 +3435,25 @@ function NewTraceViewerContent({ trace }) {
|
|
|
2532
3435
|
window.removeEventListener("keyup", onKeyUp);
|
|
2533
3436
|
window.removeEventListener("blur", onBlur);
|
|
2534
3437
|
};
|
|
2535
|
-
}, [
|
|
3438
|
+
}, [handleClearActiveSpan]);
|
|
2536
3439
|
const timelineRef = reactExports.useRef(null);
|
|
2537
3440
|
const [hoverFraction, setHoverFraction] = reactExports.useState(null);
|
|
2538
3441
|
const hoverInfo = reactExports.useMemo(() => {
|
|
2539
3442
|
if (hoverFraction == null)
|
|
2540
3443
|
return null;
|
|
2541
|
-
const absTime =
|
|
3444
|
+
const absTime = viewport.start + hoverFraction * viewDuration;
|
|
2542
3445
|
const offset = absTime - root.startTime;
|
|
2543
|
-
return { fraction: hoverFraction, label:
|
|
2544
|
-
}, [hoverFraction,
|
|
3446
|
+
return { fraction: hoverFraction, label: formatDurationPrecise(offset) };
|
|
3447
|
+
}, [hoverFraction, viewport.start, viewDuration, root.startTime]);
|
|
2545
3448
|
const handleTimelineMouseMove = reactExports.useCallback((e) => {
|
|
2546
3449
|
const el = timelineRef.current;
|
|
2547
3450
|
if (!el)
|
|
2548
3451
|
return;
|
|
2549
3452
|
const rect = el.getBoundingClientRect();
|
|
2550
|
-
const
|
|
2551
|
-
const contentWidth = rect.width - padding * 2;
|
|
3453
|
+
const contentWidth = rect.width - TIMELINE_PADDING_PX * 2;
|
|
2552
3454
|
if (contentWidth <= 0)
|
|
2553
3455
|
return;
|
|
2554
|
-
const fraction = Math.max(0, Math.min(1, (e.clientX - rect.left -
|
|
3456
|
+
const fraction = Math.max(0, Math.min(1, (e.clientX - rect.left - TIMELINE_PADDING_PX) / contentWidth));
|
|
2555
3457
|
setHoverFraction(fraction);
|
|
2556
3458
|
}, []);
|
|
2557
3459
|
const handleTimelineMouseLeave = reactExports.useCallback(() => {
|
|
@@ -2559,12 +3461,7 @@ function NewTraceViewerContent({ trace }) {
|
|
|
2559
3461
|
}, []);
|
|
2560
3462
|
reactExports.useEffect(() => {
|
|
2561
3463
|
const el = timelineRef.current;
|
|
2562
|
-
if (!el)
|
|
2563
|
-
return;
|
|
2564
|
-
const rootS = root.startTime;
|
|
2565
|
-
const rootE = root.startTime + root.duration;
|
|
2566
|
-
const rootD = root.duration;
|
|
2567
|
-
if (rootD <= 0)
|
|
3464
|
+
if (!el || root.duration <= 0)
|
|
2568
3465
|
return;
|
|
2569
3466
|
const onWheel = (e) => {
|
|
2570
3467
|
const isZoomGesture = e.ctrlKey || e.metaKey;
|
|
@@ -2573,85 +3470,54 @@ function NewTraceViewerContent({ trace }) {
|
|
|
2573
3470
|
return;
|
|
2574
3471
|
e.preventDefault();
|
|
2575
3472
|
const rect = el.getBoundingClientRect();
|
|
2576
|
-
const contentWidth = rect.width -
|
|
3473
|
+
const contentWidth = rect.width - TIMELINE_PADDING_PX * 2;
|
|
2577
3474
|
if (contentWidth <= 0)
|
|
2578
3475
|
return;
|
|
2579
3476
|
if (isZoomGesture) {
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
dy *= 16;
|
|
2583
|
-
const cursorFraction = Math.max(0, Math.min(1, (e.clientX - rect.left - TIMELINE_PADDING) / contentWidth));
|
|
2584
|
-
const scaleFactor = Math.pow(2, dy / 200);
|
|
3477
|
+
const cursorFraction = Math.max(0, Math.min(1, (e.clientX - rect.left - TIMELINE_PADDING_PX) / contentWidth));
|
|
3478
|
+
const scaleFactor = wheelZoomScaleFactor(e);
|
|
2585
3479
|
setViewport((prev) => {
|
|
2586
3480
|
const prevDuration = prev.end - prev.start;
|
|
2587
3481
|
const cursorTime = prev.start + cursorFraction * prevDuration;
|
|
2588
|
-
const newDuration = Math.max(MIN_VIEWPORT_MS, Math.min(
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
newEnd = rootS + newDuration;
|
|
2594
|
-
}
|
|
2595
|
-
if (newEnd > rootE) {
|
|
2596
|
-
newEnd = rootE;
|
|
2597
|
-
newStart = Math.max(rootS, rootE - newDuration);
|
|
2598
|
-
}
|
|
2599
|
-
return { start: newStart, end: newEnd };
|
|
3482
|
+
const newDuration = Math.max(MIN_VIEWPORT_MS, Math.min(root.duration, prevDuration * scaleFactor));
|
|
3483
|
+
return clampToRoot({
|
|
3484
|
+
start: cursorTime - cursorFraction * newDuration,
|
|
3485
|
+
end: cursorTime + (1 - cursorFraction) * newDuration
|
|
3486
|
+
});
|
|
2600
3487
|
});
|
|
2601
3488
|
} else {
|
|
2602
|
-
|
|
2603
|
-
if (e.deltaMode === 1)
|
|
2604
|
-
dx *= 16;
|
|
3489
|
+
const dx = wheelDeltaToPixels(e.deltaX, e.deltaMode);
|
|
2605
3490
|
setViewport((prev) => {
|
|
2606
|
-
const
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
newStart = rootS;
|
|
2612
|
-
newEnd = rootS + prevDuration;
|
|
2613
|
-
}
|
|
2614
|
-
if (newEnd > rootE) {
|
|
2615
|
-
newEnd = rootE;
|
|
2616
|
-
newStart = Math.max(rootS, rootE - prevDuration);
|
|
2617
|
-
}
|
|
2618
|
-
return { start: newStart, end: newEnd };
|
|
3491
|
+
const panAmount = dx / contentWidth * (prev.end - prev.start);
|
|
3492
|
+
return clampToRoot({
|
|
3493
|
+
start: prev.start + panAmount,
|
|
3494
|
+
end: prev.end + panAmount
|
|
3495
|
+
});
|
|
2619
3496
|
});
|
|
2620
3497
|
}
|
|
2621
3498
|
};
|
|
2622
3499
|
el.addEventListener("wheel", onWheel, { passive: false });
|
|
2623
3500
|
return () => el.removeEventListener("wheel", onWheel);
|
|
2624
|
-
}, [root.
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
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";
|
|
2633
|
-
}, [selectedSpan == null ? void 0 : selectedSpan.data]);
|
|
2634
|
-
const selectedResource = selectedSpan == null ? void 0 : selectedSpan.resource;
|
|
2635
|
-
const selectedResourceId = reactExports.useMemo(() => {
|
|
2636
|
-
if (!(selectedSpan == null ? void 0 : selectedSpan.data))
|
|
2637
|
-
return void 0;
|
|
2638
|
-
const data = selectedSpan.data;
|
|
2639
|
-
return data.stepId ?? data.runId ?? data.hookId ?? selectedSpan.spanId;
|
|
2640
|
-
}, [selectedSpan == null ? void 0 : selectedSpan.data, selectedSpan == null ? void 0 : selectedSpan.spanId]);
|
|
2641
|
-
return jsxRuntimeExports.jsxs("div", { "data-pane": "pane-root", "data-has-detail": activeSpan ? "" : void 0, className: "grid w-full h-full max-h-full grid-cols-[minmax(100px,1fr)] data-[has-detail]:grid-cols-[minmax(100px,1fr)_clamp(280px,420px,100%)]", children: [jsxRuntimeExports.jsx("div", { id: "trace-parent", className: "grid grid-rows-[1fr] h-full min-h-0 overflow-hidden relative bg-background-100", children: jsxRuntimeExports.jsxs(SplitPane, { startHeader: jsxRuntimeExports.jsxs("div", { className: "bg-background-100 border-b border-gray-alpha-400 h-10 min-h-10 flex items-center px-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), 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", onClick: () => setSearchQuery(""), className: "shrink-0 p-0.5 rounded-sm text-gray-800 hover:text-gray-1000 hover:bg-gray-200 transition-colors", children: jsxRuntimeExports.jsx(X, { className: "w-3 h-3" }) })] }), endHeader: jsxRuntimeExports.jsx(TimelineHeader, { viewStart: viewport.start, viewDuration, rootStart: root.startTime, compression, isZoomed, onResetZoom: resetZoom, hoverInfo }), children: [jsxRuntimeExports.jsx("div", { className: "block overflow-visible", children: jsxRuntimeExports.jsx(EventList, { spans: filteredSpans, activeSpanId, onSelectSpan: handleSelectSpan }) }), jsxRuntimeExports.jsx("div", { ref: timelineRef, className: "block min-h-0 overflow-visible relative px-2", onDoubleClick: resetZoom, onMouseMove: handleTimelineMouseMove, onMouseLeave: handleTimelineMouseLeave, children: jsxRuntimeExports.jsx(Timeline, { spans: filteredSpans, compression, selectedId: activeSpanId, onSelect: handleSelectSpan, hoverFraction, altHeld }) })] }) }), activeSpan && sidebar ? 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.jsx("div", { className: "flex-shrink-0 px-4 pt-4 pb-3", children: jsxRuntimeExports.jsxs("div", { className: "flex items-start justify-between gap-2", children: [jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [jsxRuntimeExports.jsx("span", { className: "text-[15px] font-semibold text-gray-1000 truncate block", children: selectedSpanName }), selectedResourceId && jsxRuntimeExports.jsxs("div", { className: "mt-1 flex items-center gap-2", children: [selectedResource && jsxRuntimeExports.jsx("span", { className: `inline-flex items-center rounded-md px-1.5 py-0.5 text-[11px] font-medium leading-none shrink-0 ${selectedResource === "step" ? "bg-green-200 text-green-900" : selectedResource === "run" ? "bg-blue-200 text-blue-900" : selectedResource === "hook" ? "bg-yellow-200 text-yellow-900" : "bg-gray-200 text-gray-900"}`, children: selectedResource.charAt(0).toUpperCase() + selectedResource.slice(1) }), jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-[13px] font-mono text-gray-700 min-w-0", title: selectedResourceId, children: [jsxRuntimeExports.jsx("span", { className: "truncate", children: selectedResourceId }), jsxRuntimeExports.jsx(CopyButton, { copyText: selectedResourceId, ariaLabel: "Copy ID", className: "shrink-0" })] })] })] }), jsxRuntimeExports.jsx("button", { type: "button", className: "p-1 rounded-md text-gray-900 hover:text-gray-1000 hover:bg-gray-alpha-200 transition-colors shrink-0", onClick: clearActiveSpan, children: jsxRuntimeExports.jsx(X, { className: "w-4 h-4" }) })] }) }), jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto", children: jsxRuntimeExports.jsx(ErrorBoundary, { children: jsxRuntimeExports.jsx(EntityDetailPanel, { run: sidebar.run, onStreamClick: sidebar.onStreamClick, onRunClick: sidebar.onRunClick, spanDetailData: sidebar.spanDetailData, spanDetailError: sidebar.spanDetailError, spanDetailLoading: sidebar.spanDetailLoading, onSpanSelect: sidebar.onSpanSelect, onWakeUpSleep: sidebar.onWakeUpSleep, onLoadEventData: sidebar.onLoadEventData, onResolveHook: sidebar.onResolveHook, encryptionKey: sidebar.encryptionKey, onDecrypt: sidebar.onDecrypt, isDecrypting: sidebar.isDecrypting, selectedSpan }) }) })] }) : activeSpan ? jsxRuntimeExports.jsx(DetailPanel, { span: activeSpan, rootStart: root.startTime, onClose: clearActiveSpan }) : null] });
|
|
3501
|
+
}, [root.duration, setViewport, clampToRoot]);
|
|
3502
|
+
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) => {
|
|
3503
|
+
if (e.key === "Escape" && searchQuery) {
|
|
3504
|
+
e.preventDefault();
|
|
3505
|
+
e.stopPropagation();
|
|
3506
|
+
setSearchQuery("");
|
|
3507
|
+
}
|
|
3508
|
+
}, 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.jsxs("div", { ref: timelineRef, id: "trace-timeline", className: "@container 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.jsx(TraceShortcutHelper, { hasMultipleSpans: trace.spans.length > 1, reducedMotion })] })] }), 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 })] });
|
|
2642
3509
|
}
|
|
2643
|
-
const NewTraceViewer = ({ run, events, sidebarData }) => {
|
|
2644
|
-
const
|
|
3510
|
+
const NewTraceViewer = ({ run, events, sidebarData, onLoadMore, hasMore, isLoadingMore, loading = false }) => {
|
|
3511
|
+
const trace = reactExports.useMemo(() => {
|
|
2645
3512
|
if (!(run == null ? void 0 : run.runId)) {
|
|
2646
3513
|
return void 0;
|
|
2647
3514
|
}
|
|
2648
3515
|
return buildTrace(run, events, /* @__PURE__ */ new Date());
|
|
2649
3516
|
}, [run, events]);
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
return jsxRuntimeExports.jsx("div", { className: "relative w-full h-full flex items-center justify-center", children: jsxRuntimeExports.jsx("div", { className: "text-gray-500 text-sm", children: "Loading trace…" }) });
|
|
3517
|
+
if (!trace || loading && events.length === 0) {
|
|
3518
|
+
return jsxRuntimeExports.jsx(TraceViewerSkeleton, {});
|
|
2653
3519
|
}
|
|
2654
|
-
return jsxRuntimeExports.jsx(SidebarDataProvider, { value: sidebarData, children: jsxRuntimeExports.jsx("div", { className: "relative w-full h-full flex", children: jsxRuntimeExports.jsx(NewTraceViewer$1, { trace }) }) });
|
|
3520
|
+
return jsxRuntimeExports.jsx(SidebarDataProvider, { value: sidebarData, children: jsxRuntimeExports.jsx("div", { className: "relative w-full h-full flex", children: jsxRuntimeExports.jsx(NewTraceViewer$1, { trace, onLoadMore, hasMore, isLoadingMore }) }) });
|
|
2655
3521
|
};
|
|
2656
3522
|
async function fetchResourceWithCorrelationId(env, resource, resourceId, options = {}) {
|
|
2657
3523
|
const resolveData = options.resolveData ?? "all";
|
|
@@ -2681,130 +3547,45 @@ async function fetchResourceWithCorrelationId(env, resource, resourceId, options
|
|
|
2681
3547
|
}
|
|
2682
3548
|
return { data: resourceData, correlationId };
|
|
2683
3549
|
}
|
|
2684
|
-
function
|
|
2685
|
-
const {
|
|
2686
|
-
const
|
|
2687
|
-
|
|
2688
|
-
)
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
setLoading(false);
|
|
2699
|
-
return;
|
|
2700
|
-
}
|
|
2701
|
-
const selectionKey = `${resource}:${resourceId}`;
|
|
2702
|
-
if (selectionKey !== prevSelectionRef.current) {
|
|
2703
|
-
setData(null);
|
|
2704
|
-
prevSelectionRef.current = selectionKey;
|
|
2705
|
-
}
|
|
2706
|
-
setError(null);
|
|
2707
|
-
setLoading(true);
|
|
2708
|
-
if (resource === "hook") {
|
|
2709
|
-
try {
|
|
2710
|
-
const { error: error2, result } = await unwrapServerActionResult(
|
|
2711
|
-
fetchHook(env, resourceId, "all")
|
|
2712
|
-
);
|
|
2713
|
-
if (error2) {
|
|
2714
|
-
setError(error2);
|
|
2715
|
-
return;
|
|
2716
|
-
}
|
|
2717
|
-
try {
|
|
2718
|
-
setData(await hydrate(result));
|
|
2719
|
-
} catch (hydrateError) {
|
|
2720
|
-
setError(
|
|
2721
|
-
hydrateError instanceof Error ? hydrateError : new Error(String(hydrateError))
|
|
2722
|
-
);
|
|
2723
|
-
}
|
|
2724
|
-
} finally {
|
|
2725
|
-
setLoading(false);
|
|
2726
|
-
}
|
|
2727
|
-
return;
|
|
2728
|
-
}
|
|
2729
|
-
if (resource === "sleep") {
|
|
2730
|
-
try {
|
|
2731
|
-
if (!runId) {
|
|
2732
|
-
setError(new Error("runId is required for loading sleep details"));
|
|
2733
|
-
return;
|
|
2734
|
-
}
|
|
2735
|
-
const { error: error2, result } = await unwrapServerActionResult(
|
|
2736
|
-
fetchEvents(env, runId, {
|
|
2737
|
-
sortOrder: "asc",
|
|
2738
|
-
limit: 1e3,
|
|
2739
|
-
withData: true
|
|
2740
|
-
})
|
|
2741
|
-
);
|
|
2742
|
-
if (error2) {
|
|
2743
|
-
setError(error2);
|
|
2744
|
-
return;
|
|
2745
|
-
}
|
|
2746
|
-
try {
|
|
2747
|
-
const allEvents = result.data.map(
|
|
2748
|
-
hydrateResourceIO
|
|
2749
|
-
);
|
|
2750
|
-
const waitEvents = await Promise.all(
|
|
2751
|
-
allEvents.filter((e) => e.correlationId === resourceId).map(hydrate)
|
|
2752
|
-
);
|
|
2753
|
-
const data2 = waitEventsToWaitEntity(waitEvents);
|
|
2754
|
-
if (data2 === null) {
|
|
2755
|
-
setError(
|
|
2756
|
-
new Error(
|
|
2757
|
-
`Failed to load ${resource} details: missing required event data`
|
|
2758
|
-
)
|
|
2759
|
-
);
|
|
2760
|
-
return;
|
|
2761
|
-
}
|
|
2762
|
-
setData(data2);
|
|
2763
|
-
} catch (hydrateError) {
|
|
2764
|
-
setError(
|
|
2765
|
-
hydrateError instanceof Error ? hydrateError : new Error(String(hydrateError))
|
|
2766
|
-
);
|
|
2767
|
-
}
|
|
2768
|
-
} finally {
|
|
2769
|
-
setLoading(false);
|
|
2770
|
-
}
|
|
2771
|
-
return;
|
|
3550
|
+
async function fetchSpanDetailResource(env, selection, options = {}) {
|
|
3551
|
+
const { resource, resourceId, runId } = selection;
|
|
3552
|
+
const { encryptionKey } = options;
|
|
3553
|
+
const hydrate = async (value) => hydrateResourceIOAsync(value, encryptionKey);
|
|
3554
|
+
if (resource === "hook") {
|
|
3555
|
+
const result = await unwrapOrThrow(fetchHook(env, resourceId, "all"));
|
|
3556
|
+
return hydrate(result);
|
|
3557
|
+
}
|
|
3558
|
+
if (resource === "sleep") {
|
|
3559
|
+
if (!runId) {
|
|
3560
|
+
throw new WorkflowWebAPIError(
|
|
3561
|
+
"runId is required for loading sleep details",
|
|
3562
|
+
{ layer: "client" }
|
|
3563
|
+
);
|
|
2772
3564
|
}
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
3565
|
+
const result = await unwrapOrThrow(
|
|
3566
|
+
fetchEvents(env, runId, { sortOrder: "asc", limit: 1e3, withData: true })
|
|
3567
|
+
);
|
|
3568
|
+
const waitEvents = await Promise.all(
|
|
3569
|
+
result.data.filter((e) => e.correlationId === resourceId).map(hydrate)
|
|
3570
|
+
);
|
|
3571
|
+
const data2 = waitEventsToWaitEntity(waitEvents);
|
|
3572
|
+
if (data2 === null) {
|
|
3573
|
+
throw new WorkflowWebAPIError(
|
|
3574
|
+
`Failed to load ${resource} details: missing required event data`,
|
|
3575
|
+
{ layer: "client" }
|
|
2779
3576
|
);
|
|
2780
|
-
setData(await hydrate(resourceData));
|
|
2781
|
-
} catch (error2) {
|
|
2782
|
-
if (error2 instanceof Error) {
|
|
2783
|
-
setError(error2);
|
|
2784
|
-
} else {
|
|
2785
|
-
setError(new Error(String(error2)));
|
|
2786
|
-
}
|
|
2787
|
-
return;
|
|
2788
|
-
} finally {
|
|
2789
|
-
setLoading(false);
|
|
2790
3577
|
}
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
3578
|
+
return data2;
|
|
3579
|
+
}
|
|
3580
|
+
const { data } = await fetchResourceWithCorrelationId(
|
|
3581
|
+
env,
|
|
3582
|
+
resource,
|
|
3583
|
+
resourceId,
|
|
3584
|
+
{
|
|
3585
|
+
runId
|
|
2798
3586
|
}
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
}, [refreshInterval, fetchData]);
|
|
2802
|
-
return {
|
|
2803
|
-
data,
|
|
2804
|
-
loading,
|
|
2805
|
-
error,
|
|
2806
|
-
refresh: fetchData
|
|
2807
|
-
};
|
|
3587
|
+
);
|
|
3588
|
+
return hydrate(data);
|
|
2808
3589
|
}
|
|
2809
3590
|
function mergeById(prev, next, idKey) {
|
|
2810
3591
|
const combined = [...prev, ...next];
|
|
@@ -2843,6 +3624,7 @@ const LIVE_POLL_LIMIT = 100;
|
|
|
2843
3624
|
const INITIAL_PAGE_SIZE$1 = 500;
|
|
2844
3625
|
const LOAD_MORE_PAGE_SIZE$1 = 100;
|
|
2845
3626
|
const LIVE_UPDATE_INTERVAL_MS = 5e3;
|
|
3627
|
+
const AUTO_LOAD_MAX_EVENTS = 500;
|
|
2846
3628
|
function useWorkflowTraceViewerData(env, runId, options = {}) {
|
|
2847
3629
|
const { live = false } = options;
|
|
2848
3630
|
const [run, setRun] = reactExports.useState(null);
|
|
@@ -2951,6 +3733,12 @@ function useWorkflowTraceViewerData(env, runId, options = {}) {
|
|
|
2951
3733
|
eventsHasMore,
|
|
2952
3734
|
eventsCursor
|
|
2953
3735
|
]);
|
|
3736
|
+
reactExports.useEffect(() => {
|
|
3737
|
+
if (events.length >= AUTO_LOAD_MAX_EVENTS) {
|
|
3738
|
+
return;
|
|
3739
|
+
}
|
|
3740
|
+
loadMoreTraceData();
|
|
3741
|
+
}, [events.length, loadMoreTraceData]);
|
|
2954
3742
|
const pollRun = reactExports.useCallback(async () => {
|
|
2955
3743
|
if (run == null ? void 0 : run.completedAt) {
|
|
2956
3744
|
return false;
|
|
@@ -4211,6 +4999,7 @@ function BreadcrumbSeparator({
|
|
|
4211
4999
|
}
|
|
4212
5000
|
const INITIAL_PAGE_SIZE = 100;
|
|
4213
5001
|
const LOAD_MORE_PAGE_SIZE = 100;
|
|
5002
|
+
const MAX_CORRELATION_SEARCH_PAGES = 30;
|
|
4214
5003
|
function useEventsListData(env, runId, options = {}) {
|
|
4215
5004
|
const { sortOrder = "asc", encryptionKey, enabled = true } = options;
|
|
4216
5005
|
const [events, setEvents] = reactExports.useState([]);
|
|
@@ -4222,6 +5011,10 @@ function useEventsListData(env, runId, options = {}) {
|
|
|
4222
5011
|
const isFetchingRef = reactExports.useRef(false);
|
|
4223
5012
|
const encryptionKeyRef = reactExports.useRef(encryptionKey);
|
|
4224
5013
|
encryptionKeyRef.current = encryptionKey;
|
|
5014
|
+
const hydrateEvents = reactExports.useCallback(async (rawEvents) => {
|
|
5015
|
+
const key = encryptionKeyRef.current;
|
|
5016
|
+
return Promise.all(rawEvents.map((ev) => hydrateResourceIOAsync(ev, key)));
|
|
5017
|
+
}, []);
|
|
4225
5018
|
const fetchInitial = reactExports.useCallback(async () => {
|
|
4226
5019
|
if (isFetchingRef.current) return;
|
|
4227
5020
|
isFetchingRef.current = true;
|
|
@@ -4241,16 +5034,7 @@ function useEventsListData(env, runId, options = {}) {
|
|
|
4241
5034
|
if (fetchError) {
|
|
4242
5035
|
setError(fetchError);
|
|
4243
5036
|
} else {
|
|
4244
|
-
|
|
4245
|
-
const key = encryptionKeyRef.current;
|
|
4246
|
-
if (key) {
|
|
4247
|
-
const decrypted = await Promise.all(
|
|
4248
|
-
hydrated.map((ev) => hydrateResourceIOWithKey(ev, key))
|
|
4249
|
-
);
|
|
4250
|
-
setEvents(decrypted);
|
|
4251
|
-
} else {
|
|
4252
|
-
setEvents(hydrated);
|
|
4253
|
-
}
|
|
5037
|
+
setEvents(await hydrateEvents(result.data));
|
|
4254
5038
|
setCursor(result.hasMore ? result.cursor : void 0);
|
|
4255
5039
|
setHasMore(Boolean(result.hasMore));
|
|
4256
5040
|
}
|
|
@@ -4260,14 +5044,14 @@ function useEventsListData(env, runId, options = {}) {
|
|
|
4260
5044
|
setLoading(false);
|
|
4261
5045
|
isFetchingRef.current = false;
|
|
4262
5046
|
}
|
|
4263
|
-
}, [env, runId, sortOrder]);
|
|
5047
|
+
}, [env, runId, sortOrder, hydrateEvents]);
|
|
4264
5048
|
reactExports.useEffect(() => {
|
|
4265
5049
|
if (enabled) fetchInitial();
|
|
4266
5050
|
}, [fetchInitial, enabled]);
|
|
4267
5051
|
reactExports.useEffect(() => {
|
|
4268
5052
|
if (!encryptionKey || events.length === 0) return;
|
|
4269
5053
|
let cancelled = false;
|
|
4270
|
-
Promise.all(events.map((ev) =>
|
|
5054
|
+
Promise.all(events.map((ev) => hydrateResourceIOAsync(ev, encryptionKey))).then((decrypted) => {
|
|
4271
5055
|
if (!cancelled) setEvents(decrypted);
|
|
4272
5056
|
}).catch(() => {
|
|
4273
5057
|
});
|
|
@@ -4291,16 +5075,8 @@ function useEventsListData(env, runId, options = {}) {
|
|
|
4291
5075
|
setError(fetchError);
|
|
4292
5076
|
} else {
|
|
4293
5077
|
if (result.data.length > 0) {
|
|
4294
|
-
const hydrated = result.data
|
|
4295
|
-
|
|
4296
|
-
if (key) {
|
|
4297
|
-
const decrypted = await Promise.all(
|
|
4298
|
-
hydrated.map((ev) => hydrateResourceIOWithKey(ev, key))
|
|
4299
|
-
);
|
|
4300
|
-
setEvents((prev) => [...prev, ...decrypted]);
|
|
4301
|
-
} else {
|
|
4302
|
-
setEvents((prev) => [...prev, ...hydrated]);
|
|
4303
|
-
}
|
|
5078
|
+
const hydrated = await hydrateEvents(result.data);
|
|
5079
|
+
setEvents((prev) => [...prev, ...hydrated]);
|
|
4304
5080
|
}
|
|
4305
5081
|
setCursor(result.hasMore ? result.cursor : void 0);
|
|
4306
5082
|
setHasMore(Boolean(result.hasMore));
|
|
@@ -4310,14 +5086,65 @@ function useEventsListData(env, runId, options = {}) {
|
|
|
4310
5086
|
} finally {
|
|
4311
5087
|
setLoadingMore(false);
|
|
4312
5088
|
}
|
|
4313
|
-
}, [env, runId, sortOrder, cursor, loadingMore]);
|
|
5089
|
+
}, [env, runId, sortOrder, cursor, loadingMore, hydrateEvents]);
|
|
5090
|
+
const searchByExactId = reactExports.useCallback(
|
|
5091
|
+
async (id, kind, signal) => {
|
|
5092
|
+
if (signal == null ? void 0 : signal.aborted) {
|
|
5093
|
+
throw new DOMException("Aborted", "AbortError");
|
|
5094
|
+
}
|
|
5095
|
+
if (kind === "event") {
|
|
5096
|
+
const { error: fetchError, result } = await unwrapServerActionResult(
|
|
5097
|
+
fetchEvent(env, runId, id, "none")
|
|
5098
|
+
);
|
|
5099
|
+
if (fetchError || (signal == null ? void 0 : signal.aborted)) {
|
|
5100
|
+
return fetchError ? { status: "error", message: fetchError.message } : (() => {
|
|
5101
|
+
throw new DOMException("Aborted", "AbortError");
|
|
5102
|
+
})();
|
|
5103
|
+
}
|
|
5104
|
+
const [event] = await hydrateEvents([result]);
|
|
5105
|
+
return (event == null ? void 0 : event.runId) === runId ? { status: "ok", events: [event] } : { status: "not_found" };
|
|
5106
|
+
}
|
|
5107
|
+
const matched = [];
|
|
5108
|
+
let nextCursor;
|
|
5109
|
+
let pagesFetched = 0;
|
|
5110
|
+
let truncated = false;
|
|
5111
|
+
do {
|
|
5112
|
+
if (signal == null ? void 0 : signal.aborted) {
|
|
5113
|
+
throw new DOMException("Aborted", "AbortError");
|
|
5114
|
+
}
|
|
5115
|
+
const { error: fetchError, result } = await unwrapServerActionResult(
|
|
5116
|
+
fetchEventsByCorrelationId(env, id, {
|
|
5117
|
+
cursor: nextCursor,
|
|
5118
|
+
sortOrder,
|
|
5119
|
+
limit: 100,
|
|
5120
|
+
withData: false
|
|
5121
|
+
})
|
|
5122
|
+
);
|
|
5123
|
+
if (fetchError) {
|
|
5124
|
+
return { status: "error", message: fetchError.message };
|
|
5125
|
+
}
|
|
5126
|
+
if (signal == null ? void 0 : signal.aborted) {
|
|
5127
|
+
throw new DOMException("Aborted", "AbortError");
|
|
5128
|
+
}
|
|
5129
|
+
pagesFetched += 1;
|
|
5130
|
+
const hydrated = await hydrateEvents(result.data);
|
|
5131
|
+
matched.push(...hydrated.filter((event) => event.runId === runId));
|
|
5132
|
+
const hitPageCap = pagesFetched >= MAX_CORRELATION_SEARCH_PAGES;
|
|
5133
|
+
truncated = truncated || hitPageCap && Boolean(result.hasMore && result.cursor);
|
|
5134
|
+
nextCursor = !hitPageCap && result.hasMore && result.cursor ? result.cursor : void 0;
|
|
5135
|
+
} while (nextCursor);
|
|
5136
|
+
return matched.length > 0 ? { status: "ok", events: matched, truncated: truncated || void 0 } : { status: "not_found" };
|
|
5137
|
+
},
|
|
5138
|
+
[env, runId, sortOrder, hydrateEvents]
|
|
5139
|
+
);
|
|
4314
5140
|
return {
|
|
4315
5141
|
events,
|
|
4316
5142
|
loading,
|
|
4317
5143
|
error,
|
|
4318
5144
|
hasMore,
|
|
4319
5145
|
loadingMore,
|
|
4320
|
-
loadMore
|
|
5146
|
+
loadMore,
|
|
5147
|
+
searchByExactId
|
|
4321
5148
|
};
|
|
4322
5149
|
}
|
|
4323
5150
|
const FRAME_HEADER_SIZE = 4;
|
|
@@ -4600,8 +5427,8 @@ function useStreamReader(env, streamId, runId, encryptionKey, runStatus) {
|
|
|
4600
5427
|
return { chunks, isLive, error };
|
|
4601
5428
|
}
|
|
4602
5429
|
function LiveStatus({ hasError, errorMessage }) {
|
|
4603
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
4604
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
5430
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip$1, { children: [
|
|
5431
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger$1, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
4605
5432
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4606
5433
|
"div",
|
|
4607
5434
|
{
|
|
@@ -4619,7 +5446,7 @@ function LiveStatus({ hasError, errorMessage }) {
|
|
|
4619
5446
|
}
|
|
4620
5447
|
)
|
|
4621
5448
|
] }) }),
|
|
4622
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: hasError ? `Error updating data: ${errorMessage}` : `Content updates every ${LIVE_UPDATE_INTERVAL_MS$1 / 1e3} seconds` }) })
|
|
5449
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: hasError ? `Error updating data: ${errorMessage}` : `Content updates every ${LIVE_UPDATE_INTERVAL_MS$1 / 1e3} seconds` }) })
|
|
4623
5450
|
] }) });
|
|
4624
5451
|
}
|
|
4625
5452
|
({
|
|
@@ -4627,7 +5454,6 @@ function LiveStatus({ hasError, errorMessage }) {
|
|
|
4627
5454
|
});
|
|
4628
5455
|
function RunDetailView({
|
|
4629
5456
|
runId,
|
|
4630
|
-
// TODO: This should open the right sidebar within the trace viewer
|
|
4631
5457
|
selectedId: _selectedId
|
|
4632
5458
|
}) {
|
|
4633
5459
|
var _a;
|
|
@@ -4705,29 +5531,16 @@ function RunDetailView({
|
|
|
4705
5531
|
if (error2) {
|
|
4706
5532
|
throw error2;
|
|
4707
5533
|
}
|
|
4708
|
-
const fullEvent =
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
}
|
|
4712
|
-
return null;
|
|
4713
|
-
},
|
|
4714
|
-
[env]
|
|
4715
|
-
);
|
|
4716
|
-
const handleLoadSidebarEventData = reactExports.useCallback(
|
|
4717
|
-
async (_correlationId, eventId) => {
|
|
4718
|
-
const { error: error2, result } = await unwrapServerActionResult(
|
|
4719
|
-
fetchEvent(env, runId, eventId, "all")
|
|
5534
|
+
const fullEvent = await hydrateResourceIOAsync(
|
|
5535
|
+
result,
|
|
5536
|
+
encryptionKeyRef.current ?? void 0
|
|
4720
5537
|
);
|
|
4721
|
-
if (error2) {
|
|
4722
|
-
throw error2;
|
|
4723
|
-
}
|
|
4724
|
-
const fullEvent = encryptionKeyRef.current ? await hydrateResourceIOWithKey(result, encryptionKeyRef.current) : hydrateResourceIO(result);
|
|
4725
5538
|
if ("eventData" in fullEvent) {
|
|
4726
5539
|
return fullEvent.eventData;
|
|
4727
5540
|
}
|
|
4728
5541
|
return null;
|
|
4729
5542
|
},
|
|
4730
|
-
[env
|
|
5543
|
+
[env]
|
|
4731
5544
|
);
|
|
4732
5545
|
serverConfig.backendId === "local" || serverConfig.backendId === "@workflow/world-local";
|
|
4733
5546
|
const {
|
|
@@ -4736,7 +5549,10 @@ function RunDetailView({
|
|
|
4736
5549
|
loading,
|
|
4737
5550
|
error,
|
|
4738
5551
|
update,
|
|
4739
|
-
hasEncryptedData
|
|
5552
|
+
hasEncryptedData,
|
|
5553
|
+
loadMoreTraceData,
|
|
5554
|
+
hasMoreTraceData,
|
|
5555
|
+
isLoadingMoreTraceData
|
|
4740
5556
|
} = useWorkflowTraceViewerData(env, runId, { live: true });
|
|
4741
5557
|
const run = runData ?? {};
|
|
4742
5558
|
const [encryptionKey, setEncryptionKey] = reactExports.useState(null);
|
|
@@ -4747,36 +5563,22 @@ function RunDetailView({
|
|
|
4747
5563
|
loading: eventsListLoading,
|
|
4748
5564
|
hasMore: hasMoreEventsTab,
|
|
4749
5565
|
loadingMore: loadingMoreEventsTab,
|
|
4750
|
-
loadMore: loadMoreEventsTab
|
|
5566
|
+
loadMore: loadMoreEventsTab,
|
|
5567
|
+
searchByExactId
|
|
4751
5568
|
} = useEventsListData(env, runId, {
|
|
4752
5569
|
sortOrder: eventsSortOrder,
|
|
4753
5570
|
encryptionKey: encryptionKey ?? void 0,
|
|
4754
5571
|
enabled: activeTab === "events"
|
|
4755
5572
|
});
|
|
4756
|
-
const
|
|
4757
|
-
|
|
4758
|
-
);
|
|
4759
|
-
const {
|
|
4760
|
-
data: spanDetailData,
|
|
4761
|
-
loading: spanDetailLoading,
|
|
4762
|
-
error: spanDetailError,
|
|
4763
|
-
refresh: refreshSpanDetail
|
|
4764
|
-
} = useWorkflowResourceData(
|
|
4765
|
-
env,
|
|
4766
|
-
(spanSelection == null ? void 0 : spanSelection.resource) ?? "run",
|
|
4767
|
-
(spanSelection == null ? void 0 : spanSelection.resourceId) ?? "",
|
|
4768
|
-
{
|
|
4769
|
-
runId: spanSelection == null ? void 0 : spanSelection.runId,
|
|
4770
|
-
enabled: Boolean(
|
|
4771
|
-
(spanSelection == null ? void 0 : spanSelection.resource) && (spanSelection == null ? void 0 : spanSelection.resourceId) && spanSelection.resource !== "hook"
|
|
4772
|
-
),
|
|
5573
|
+
const fetchSpanDetail = reactExports.useCallback(
|
|
5574
|
+
(selection) => fetchSpanDetailResource(env, selection, {
|
|
4773
5575
|
encryptionKey: encryptionKey ?? void 0
|
|
4774
|
-
}
|
|
5576
|
+
}),
|
|
5577
|
+
[env, encryptionKey]
|
|
4775
5578
|
);
|
|
4776
5579
|
const [isDecrypting, setIsDecrypting] = reactExports.useState(false);
|
|
4777
5580
|
const handleDecrypt = reactExports.useCallback(async () => {
|
|
4778
5581
|
if (encryptionKey) {
|
|
4779
|
-
refreshSpanDetail();
|
|
4780
5582
|
return;
|
|
4781
5583
|
}
|
|
4782
5584
|
setIsDecrypting(true);
|
|
@@ -4791,26 +5593,19 @@ function RunDetailView({
|
|
|
4791
5593
|
return;
|
|
4792
5594
|
}
|
|
4793
5595
|
setEncryptionKey(keyResult);
|
|
4794
|
-
toast.success("Run data decrypted successfully");
|
|
4795
5596
|
} finally {
|
|
4796
5597
|
setIsDecrypting(false);
|
|
4797
5598
|
}
|
|
4798
|
-
}, [encryptionKey, env, runId
|
|
4799
|
-
const handleSpanSelect = reactExports.useCallback((info) => {
|
|
4800
|
-
setSpanSelection(info);
|
|
4801
|
-
}, []);
|
|
5599
|
+
}, [encryptionKey, env, runId]);
|
|
4802
5600
|
const sidebarData = reactExports.useMemo(
|
|
4803
5601
|
() => ({
|
|
4804
5602
|
run,
|
|
4805
5603
|
events: allEvents ?? [],
|
|
4806
|
-
|
|
4807
|
-
spanDetailError,
|
|
4808
|
-
spanDetailLoading,
|
|
4809
|
-
onSpanSelect: handleSpanSelect,
|
|
5604
|
+
fetchSpanDetail,
|
|
4810
5605
|
onStreamClick: handleStreamClick,
|
|
4811
5606
|
onRunClick: handleRunRefClick,
|
|
4812
5607
|
onWakeUpSleep: handleWakeUpSleep,
|
|
4813
|
-
onLoadEventData:
|
|
5608
|
+
onLoadEventData: handleLoadEventData,
|
|
4814
5609
|
onResolveHook: handleResolveHook,
|
|
4815
5610
|
encryptionKey: encryptionKey ?? void 0,
|
|
4816
5611
|
onDecrypt: handleDecrypt,
|
|
@@ -4820,14 +5615,11 @@ function RunDetailView({
|
|
|
4820
5615
|
[
|
|
4821
5616
|
run,
|
|
4822
5617
|
allEvents,
|
|
4823
|
-
|
|
4824
|
-
spanDetailError,
|
|
4825
|
-
spanDetailLoading,
|
|
4826
|
-
handleSpanSelect,
|
|
5618
|
+
fetchSpanDetail,
|
|
4827
5619
|
handleStreamClick,
|
|
4828
5620
|
handleRunRefClick,
|
|
4829
5621
|
handleWakeUpSleep,
|
|
4830
|
-
|
|
5622
|
+
handleLoadEventData,
|
|
4831
5623
|
handleResolveHook,
|
|
4832
5624
|
encryptionKey,
|
|
4833
5625
|
handleDecrypt,
|
|
@@ -4855,7 +5647,7 @@ function RunDetailView({
|
|
|
4855
5647
|
setShowCancelDialog(false);
|
|
4856
5648
|
await cancelRun(env, runId);
|
|
4857
5649
|
await update();
|
|
4858
|
-
toast.success("Run cancelled
|
|
5650
|
+
toast.success("Run cancelled");
|
|
4859
5651
|
} catch (err) {
|
|
4860
5652
|
console.error("Failed to cancel run:", err);
|
|
4861
5653
|
toast.error("Failed to cancel run", {
|
|
@@ -4874,7 +5666,7 @@ function RunDetailView({
|
|
|
4874
5666
|
setRerunning(true);
|
|
4875
5667
|
setShowRerunDialog(false);
|
|
4876
5668
|
const newRunId = await recreateRun(env, run.runId);
|
|
4877
|
-
toast.success("New run started
|
|
5669
|
+
toast.success("New run started", {
|
|
4878
5670
|
description: `Run ID: ${newRunId}`
|
|
4879
5671
|
});
|
|
4880
5672
|
navigate(`/run/${newRunId}`);
|
|
@@ -4891,8 +5683,8 @@ function RunDetailView({
|
|
|
4891
5683
|
if (error && !runData) {
|
|
4892
5684
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Alert, { variant: "destructive", className: "m-4", children: [
|
|
4893
5685
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4" }),
|
|
4894
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: "Error loading workflow run" }),
|
|
4895
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: error
|
|
5686
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: getErrorTitle(error, "Error loading workflow run") }),
|
|
5687
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: getErrorMessage(error) })
|
|
4896
5688
|
] });
|
|
4897
5689
|
}
|
|
4898
5690
|
const workflowName = (_a = parseWorkflowName(run.workflowName)) == null ? void 0 : _a.shortName;
|
|
@@ -4992,12 +5784,12 @@ function RunDetailView({
|
|
|
4992
5784
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs", children: run.runId ? run.completedAt ? /* @__PURE__ */ jsxRuntimeExports.jsx(RelativeTime, { date: run.completedAt }) : "-" : /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton$1, { className: "w-[110px] h-[20px]" }) })
|
|
4993
5785
|
] }),
|
|
4994
5786
|
run.expiredAt != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
4995
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
4996
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground cursor-help flex items-center gap-1", children: [
|
|
5787
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip$1, { children: [
|
|
5788
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger$1, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground cursor-help flex items-center gap-1", children: [
|
|
4997
5789
|
"Expired",
|
|
4998
5790
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleQuestionMark, { className: "w-3 h-3" })
|
|
4999
5791
|
] }) }),
|
|
5000
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "The storage data for this run has expired and is no longer available." }) })
|
|
5792
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "The storage data for this run has expired and is no longer available." }) })
|
|
5001
5793
|
] }),
|
|
5002
5794
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(RelativeTime, { date: run.expiredAt }) })
|
|
5003
5795
|
] })
|
|
@@ -5026,12 +5818,16 @@ function RunDetailView({
|
|
|
5026
5818
|
"Streams"
|
|
5027
5819
|
] })
|
|
5028
5820
|
] }),
|
|
5029
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "trace", className: "mt-0 flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, { title: "Failed to load trace viewer", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full -mx-6
|
|
5821
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "trace", className: "mt-0 flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, { title: "Failed to load trace viewer", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative h-full -mx-6 bg-background-100 border-t border-gray-alpha-400 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5030
5822
|
NewTraceViewer,
|
|
5031
5823
|
{
|
|
5032
5824
|
run,
|
|
5033
5825
|
events: allEvents ?? [],
|
|
5034
|
-
|
|
5826
|
+
loading,
|
|
5827
|
+
sidebarData,
|
|
5828
|
+
onLoadMore: loadMoreTraceData,
|
|
5829
|
+
hasMore: hasMoreTraceData,
|
|
5830
|
+
isLoadingMore: isLoadingMoreTraceData
|
|
5035
5831
|
}
|
|
5036
5832
|
) }) }) }),
|
|
5037
5833
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "events", className: "mt-0 flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, { title: "Failed to load events list", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -5049,7 +5845,8 @@ function RunDetailView({
|
|
|
5049
5845
|
onSortOrderChange: setEventsSortOrder,
|
|
5050
5846
|
onDecrypt: handleDecrypt,
|
|
5051
5847
|
isDecrypting,
|
|
5052
|
-
hasEncryptedData
|
|
5848
|
+
hasEncryptedData,
|
|
5849
|
+
onExactIdSearch: searchByExactId
|
|
5053
5850
|
}
|
|
5054
5851
|
) }) }) }),
|
|
5055
5852
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "streams", className: "mt-0 flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, { title: "Failed to load stream data", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-full flex gap-4", children: [
|