@acmekit/dashboard 2.13.34 → 2.13.36
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/dist/{api-key-management-create-4AG76FJV.mjs → api-key-management-create-U37VC624.mjs} +3 -3
- package/dist/{api-key-management-detail-T2TB4KST.mjs → api-key-management-detail-ZYKL4ATI.mjs} +10 -10
- package/dist/{api-key-management-edit-R44OHS7B.mjs → api-key-management-edit-TSZGMIBL.mjs} +3 -3
- package/dist/{api-key-management-list-QK4Q7Y5I.mjs → api-key-management-list-HCJFJWWB.mjs} +3 -3
- package/dist/app.css +31 -0
- package/dist/app.js +3726 -1386
- package/dist/app.mjs +240 -38
- package/dist/{chunk-GBFVWROS.mjs → chunk-5IEHCYJO.mjs} +1 -1
- package/dist/{chunk-DQCEH3X2.mjs → chunk-7F3CWXUH.mjs} +1 -1
- package/dist/chunk-A7ULKHDE.mjs +126 -0
- package/dist/{chunk-DN3MIYQH.mjs → chunk-FKTMBR44.mjs} +1 -1
- package/dist/chunk-GBPAZAJK.mjs +34 -0
- package/dist/{chunk-YRWSG3YM.mjs → chunk-HHPPTD3B.mjs} +1 -1
- package/dist/chunk-LP6CPB7N.mjs +213 -0
- package/dist/{chunk-EFRMWHRX.mjs → chunk-PFZQYK7R.mjs} +1 -1
- package/dist/{chunk-XIM7X4FB.mjs → chunk-SYACY6AL.mjs} +1 -1
- package/dist/{chunk-2U3RK3JG.mjs → chunk-VEI6HW6L.mjs} +3 -5
- package/dist/{chunk-ST2YB7JN.mjs → chunk-WLRJXEKL.mjs} +1 -1
- package/dist/{chunk-ULSPL3DR.mjs → chunk-XIP35KXF.mjs} +1 -1
- package/dist/{chunk-DTY37DDZ.mjs → chunk-YKIWIMJX.mjs} +1 -0
- package/dist/en.json +132 -3
- package/dist/{invite-XGPZZBUP.mjs → invite-3JSNOA2B.mjs} +3 -3
- package/dist/{login-GNP3QIPI.mjs → login-BEJ5EFGE.mjs} +9 -9
- package/dist/{profile-detail-YX27F7N6.mjs → profile-detail-QVTJC4JC.mjs} +3 -3
- package/dist/{profile-edit-2VRDU75O.mjs → profile-edit-MIO62TWH.mjs} +3 -3
- package/dist/{reset-password-TWRNZO6Z.mjs → reset-password-BN4KAJQL.mjs} +2 -2
- package/dist/{settings-3XWLL5LG.mjs → settings-GH5IWXHE.mjs} +3 -3
- package/dist/{translation-list-CCEQJNED.mjs → translation-list-JA22BUKN.mjs} +10 -10
- package/dist/{translations-edit-E57GVUFV.mjs → translations-edit-STTMANVT.mjs} +11 -11
- package/dist/{user-detail-KUSRRVNX.mjs → user-detail-WCXBFRGS.mjs} +3 -3
- package/dist/{user-edit-HTN3ZGCL.mjs → user-edit-XDVMJOS4.mjs} +3 -3
- package/dist/{user-invite-E3FAAU3V.mjs → user-invite-73ZDSDFC.mjs} +3 -3
- package/dist/{user-list-KNJ5S3IM.mjs → user-list-MPJXE3CA.mjs} +5 -5
- package/dist/{user-metadata-5GQK75DT.mjs → user-metadata-ADNTL3LT.mjs} +10 -10
- package/dist/workflow-analytics-4WCI4ODQ.mjs +152 -0
- package/dist/workflow-definition-detail-GI6CFBMG.mjs +94 -0
- package/dist/workflow-definition-list-GF3XAEPS.mjs +142 -0
- package/dist/workflow-execution-complete-step-WSRLO572.mjs +245 -0
- package/dist/workflow-execution-detail-3RH6EQSS.mjs +1411 -0
- package/dist/workflow-execution-list-AQEGAME4.mjs +596 -0
- package/dist/workflow-execution-rerun-WCYLYL3Q.mjs +138 -0
- package/dist/workflow-execution-run-MWN5KWNY.mjs +135 -0
- package/dist/workflow-scheduled-list-ZPXR7CZM.mjs +174 -0
- package/package.json +9 -9
- package/dist/chunk-LKWTBYYC.mjs +0 -35
- package/dist/chunk-RPAL6FHW.mjs +0 -73
- package/dist/workflow-execution-detail-5O5VCXL3.mjs +0 -870
- package/dist/workflow-execution-list-DETG4MRT.mjs +0 -347
- /package/dist/{chunk-22YYMH6M.mjs → chunk-RISX76YT.mjs} +0 -0
|
@@ -0,0 +1,1411 @@
|
|
|
1
|
+
import {
|
|
2
|
+
STEP_ERROR_STATES,
|
|
3
|
+
STEP_INACTIVE_STATES,
|
|
4
|
+
STEP_IN_PROGRESS_STATES,
|
|
5
|
+
STEP_OK_STATES,
|
|
6
|
+
STEP_SKIPPED_STATES,
|
|
7
|
+
TRANSACTION_ACTIVE_STATES,
|
|
8
|
+
TRANSACTION_ERROR_STATES,
|
|
9
|
+
TRANSACTION_IN_PROGRESS_STATES,
|
|
10
|
+
computeIdempotencyKey,
|
|
11
|
+
formatStepDuration,
|
|
12
|
+
getFailedSteps,
|
|
13
|
+
getTransactionState,
|
|
14
|
+
getTransactionStateColor,
|
|
15
|
+
getWaitingSteps,
|
|
16
|
+
isTerminalState,
|
|
17
|
+
mergeStepEvent
|
|
18
|
+
} from "./chunk-LP6CPB7N.mjs";
|
|
19
|
+
import {
|
|
20
|
+
useDate
|
|
21
|
+
} from "./chunk-DFFLVEZ5.mjs";
|
|
22
|
+
import "./chunk-535OVBXR.mjs";
|
|
23
|
+
import {
|
|
24
|
+
JsonViewSection,
|
|
25
|
+
SingleColumnPage
|
|
26
|
+
} from "./chunk-RISX76YT.mjs";
|
|
27
|
+
import {
|
|
28
|
+
useExtension
|
|
29
|
+
} from "./chunk-C5P5PL3E.mjs";
|
|
30
|
+
import {
|
|
31
|
+
ActionMenu
|
|
32
|
+
} from "./chunk-S3REQHPQ.mjs";
|
|
33
|
+
import "./chunk-WLRJXEKL.mjs";
|
|
34
|
+
import "./chunk-5IEHCYJO.mjs";
|
|
35
|
+
import "./chunk-XIP35KXF.mjs";
|
|
36
|
+
import "./chunk-PFZQYK7R.mjs";
|
|
37
|
+
import {
|
|
38
|
+
useCancelWorkflowExecution,
|
|
39
|
+
useRetryStep,
|
|
40
|
+
useRunWorkflow,
|
|
41
|
+
useWorkflowExecution,
|
|
42
|
+
workflowExecutionsQueryKeys
|
|
43
|
+
} from "./chunk-A7ULKHDE.mjs";
|
|
44
|
+
import "./chunk-FKTMBR44.mjs";
|
|
45
|
+
import "./chunk-SYACY6AL.mjs";
|
|
46
|
+
import {
|
|
47
|
+
SingleColumnPageSkeleton
|
|
48
|
+
} from "./chunk-ITNQKZQQ.mjs";
|
|
49
|
+
import "./chunk-OAHCJFG3.mjs";
|
|
50
|
+
import {
|
|
51
|
+
useDocumentDirection
|
|
52
|
+
} from "./chunk-S4DMV3ZT.mjs";
|
|
53
|
+
import "./chunk-HHPPTD3B.mjs";
|
|
54
|
+
import {
|
|
55
|
+
queryClient
|
|
56
|
+
} from "./chunk-FXYH54JP.mjs";
|
|
57
|
+
import "./chunk-774WSTCC.mjs";
|
|
58
|
+
import {
|
|
59
|
+
backendUrl,
|
|
60
|
+
sdk
|
|
61
|
+
} from "./chunk-YKIWIMJX.mjs";
|
|
62
|
+
import "./chunk-QZ7TP4HQ.mjs";
|
|
63
|
+
|
|
64
|
+
// src/routes/workflow-executions/workflow-execution-detail/breadcrumb.tsx
|
|
65
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
66
|
+
var WorkflowExecutionDetailBreadcrumb = (props) => {
|
|
67
|
+
const { id } = props.params || {};
|
|
68
|
+
const { workflow_execution } = useWorkflowExecution(id, {
|
|
69
|
+
initialData: props.data,
|
|
70
|
+
enabled: Boolean(id)
|
|
71
|
+
});
|
|
72
|
+
if (!workflow_execution) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const cleanId = workflow_execution.id.replace("wf_exec_", "");
|
|
76
|
+
return /* @__PURE__ */ jsxs("span", { children: [
|
|
77
|
+
workflow_execution.workflow_id,
|
|
78
|
+
/* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: " / " }),
|
|
79
|
+
cleanId
|
|
80
|
+
] });
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// src/routes/workflow-executions/workflow-execution-detail/loader.ts
|
|
84
|
+
var executionDetailQuery = (id) => ({
|
|
85
|
+
queryKey: workflowExecutionsQueryKeys.detail(id),
|
|
86
|
+
queryFn: async () => sdk.admin.workflowExecution.retrieve(id)
|
|
87
|
+
});
|
|
88
|
+
var workflowExecutionLoader = async ({
|
|
89
|
+
params
|
|
90
|
+
}) => {
|
|
91
|
+
const id = params.id;
|
|
92
|
+
const query = executionDetailQuery(id);
|
|
93
|
+
return queryClient.ensureQueryData(query);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// src/routes/workflow-executions/workflow-execution-detail/workflow-detail.tsx
|
|
97
|
+
import { useParams } from "react-router-dom";
|
|
98
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
99
|
+
|
|
100
|
+
// src/hooks/use-workflow-sse.tsx
|
|
101
|
+
import { useEffect, useRef, useState } from "react";
|
|
102
|
+
var useWorkflowSSE = (workflowId, options) => {
|
|
103
|
+
const { enabled = true, onEvent } = options || {};
|
|
104
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
105
|
+
const eventSourceRef = useRef(null);
|
|
106
|
+
const onEventRef = useRef(onEvent);
|
|
107
|
+
onEventRef.current = onEvent;
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (!enabled || !workflowId) {
|
|
110
|
+
if (eventSourceRef.current) {
|
|
111
|
+
eventSourceRef.current.close();
|
|
112
|
+
eventSourceRef.current = null;
|
|
113
|
+
setIsConnected(false);
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const base = backendUrl === "/" ? "" : backendUrl;
|
|
118
|
+
const url = `${base}/admin/workflows-executions/${workflowId}/subscribe`;
|
|
119
|
+
const es = new EventSource(url, { withCredentials: true });
|
|
120
|
+
eventSourceRef.current = es;
|
|
121
|
+
es.onopen = () => {
|
|
122
|
+
setIsConnected(true);
|
|
123
|
+
};
|
|
124
|
+
es.onmessage = (e) => {
|
|
125
|
+
try {
|
|
126
|
+
const data = JSON.parse(e.data);
|
|
127
|
+
onEventRef.current?.(data);
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
es.onerror = () => {
|
|
132
|
+
setIsConnected(false);
|
|
133
|
+
};
|
|
134
|
+
return () => {
|
|
135
|
+
es.close();
|
|
136
|
+
eventSourceRef.current = null;
|
|
137
|
+
setIsConnected(false);
|
|
138
|
+
};
|
|
139
|
+
}, [enabled, workflowId]);
|
|
140
|
+
const disconnect = () => {
|
|
141
|
+
if (eventSourceRef.current) {
|
|
142
|
+
eventSourceRef.current.close();
|
|
143
|
+
eventSourceRef.current = null;
|
|
144
|
+
setIsConnected(false);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
return { isConnected, disconnect };
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-action-bar/workflow-execution-action-bar.tsx
|
|
151
|
+
import { ArrowPathMini, EllipsisHorizontal, XMark } from "@acmekit/icons";
|
|
152
|
+
import {
|
|
153
|
+
Badge,
|
|
154
|
+
Button,
|
|
155
|
+
Container,
|
|
156
|
+
Copy,
|
|
157
|
+
StatusBadge,
|
|
158
|
+
toast,
|
|
159
|
+
usePrompt
|
|
160
|
+
} from "@acmekit/ui";
|
|
161
|
+
import { useTranslation } from "react-i18next";
|
|
162
|
+
import { Link } from "react-router-dom";
|
|
163
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
164
|
+
var WorkflowExecutionActionBar = ({
|
|
165
|
+
execution
|
|
166
|
+
}) => {
|
|
167
|
+
const { t } = useTranslation();
|
|
168
|
+
const prompt = usePrompt();
|
|
169
|
+
const state = execution.state;
|
|
170
|
+
const stateColor = getTransactionStateColor(state);
|
|
171
|
+
const translatedState = getTransactionState(t, state);
|
|
172
|
+
const workflowId = execution.workflow_id;
|
|
173
|
+
const transactionId = execution.transaction_id;
|
|
174
|
+
const isFailed = TRANSACTION_ERROR_STATES.includes(state);
|
|
175
|
+
const isRunning = TRANSACTION_IN_PROGRESS_STATES.includes(state);
|
|
176
|
+
const waitingSteps = getWaitingSteps(execution);
|
|
177
|
+
const hasWaitingSteps = waitingSteps.length > 0;
|
|
178
|
+
const { mutateAsync: runAsync, isPending: isRunning_ } = useRunWorkflow(workflowId);
|
|
179
|
+
const { mutateAsync: cancelAsync, isPending: isCancelling } = useCancelWorkflowExecution(workflowId, transactionId);
|
|
180
|
+
const handleRetry = async () => {
|
|
181
|
+
const payload = execution?.context?.data?.payload;
|
|
182
|
+
const input = payload && typeof payload === "object" ? payload : {};
|
|
183
|
+
await runAsync(
|
|
184
|
+
{ input },
|
|
185
|
+
{
|
|
186
|
+
onSuccess: () => {
|
|
187
|
+
toast.success(t("workflowExecutions.actions.retrySuccess"));
|
|
188
|
+
},
|
|
189
|
+
onError: (err) => {
|
|
190
|
+
toast.error(err.message);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
};
|
|
195
|
+
const handleCancel = async () => {
|
|
196
|
+
const res = await prompt({
|
|
197
|
+
title: t("workflowExecutions.actions.cancelConfirmTitle"),
|
|
198
|
+
description: t("workflowExecutions.actions.cancelConfirmDescription", {
|
|
199
|
+
workflow_id: workflowId
|
|
200
|
+
}),
|
|
201
|
+
confirmText: t("workflowExecutions.actions.cancel"),
|
|
202
|
+
cancelText: t("actions.cancel")
|
|
203
|
+
});
|
|
204
|
+
if (!res) return;
|
|
205
|
+
await cancelAsync(void 0, {
|
|
206
|
+
onSuccess: () => {
|
|
207
|
+
toast.success(t("workflowExecutions.actions.cancelSuccess"));
|
|
208
|
+
},
|
|
209
|
+
onError: (err) => {
|
|
210
|
+
toast.error(err.message);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
const handleExportJson = () => {
|
|
215
|
+
const data = JSON.stringify(execution, null, 2);
|
|
216
|
+
const blob = new Blob([data], { type: "application/json" });
|
|
217
|
+
const url = URL.createObjectURL(blob);
|
|
218
|
+
const a = document.createElement("a");
|
|
219
|
+
a.href = url;
|
|
220
|
+
a.download = `workflow-${workflowId}-${execution.id}.json`;
|
|
221
|
+
a.click();
|
|
222
|
+
URL.revokeObjectURL(url);
|
|
223
|
+
};
|
|
224
|
+
const handleExportCsv = () => {
|
|
225
|
+
const steps = execution?.execution?.steps || {};
|
|
226
|
+
const rows = [["Step", "State", "Duration"]];
|
|
227
|
+
for (const [stepId, step] of Object.entries(steps)) {
|
|
228
|
+
if (stepId === "_root") continue;
|
|
229
|
+
const invokeState = step?.invoke?.state || "unknown";
|
|
230
|
+
rows.push([stepId, invokeState, ""]);
|
|
231
|
+
}
|
|
232
|
+
const csv = rows.map((r) => r.join(",")).join("\n");
|
|
233
|
+
const blob = new Blob([csv], { type: "text/csv" });
|
|
234
|
+
const url = URL.createObjectURL(blob);
|
|
235
|
+
const a = document.createElement("a");
|
|
236
|
+
a.href = url;
|
|
237
|
+
a.download = `workflow-${workflowId}-${execution.id}.csv`;
|
|
238
|
+
a.click();
|
|
239
|
+
URL.revokeObjectURL(url);
|
|
240
|
+
};
|
|
241
|
+
const cleanId = execution.id.replace("wf_exec_", "");
|
|
242
|
+
return /* @__PURE__ */ jsx2(Container, { className: "sticky top-14 z-10 p-0", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between px-6 py-3", children: [
|
|
243
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-x-3", children: [
|
|
244
|
+
/* @__PURE__ */ jsx2(Copy, { content: workflowId, asChild: true, children: /* @__PURE__ */ jsx2(Badge, { size: "2xsmall", className: "cursor-pointer", children: workflowId }) }),
|
|
245
|
+
/* @__PURE__ */ jsx2(StatusBadge, { color: stateColor, children: translatedState }),
|
|
246
|
+
/* @__PURE__ */ jsx2(Copy, { content: execution.id, asChild: true, children: /* @__PURE__ */ jsx2(
|
|
247
|
+
Badge,
|
|
248
|
+
{
|
|
249
|
+
size: "2xsmall",
|
|
250
|
+
color: "grey",
|
|
251
|
+
className: "cursor-pointer text-ui-fg-muted",
|
|
252
|
+
children: cleanId
|
|
253
|
+
}
|
|
254
|
+
) })
|
|
255
|
+
] }),
|
|
256
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-x-2", children: [
|
|
257
|
+
isFailed && /* @__PURE__ */ jsxs2(
|
|
258
|
+
Button,
|
|
259
|
+
{
|
|
260
|
+
variant: "secondary",
|
|
261
|
+
size: "small",
|
|
262
|
+
onClick: handleRetry,
|
|
263
|
+
isLoading: isRunning_,
|
|
264
|
+
children: [
|
|
265
|
+
/* @__PURE__ */ jsx2(ArrowPathMini, { className: "mr-1" }),
|
|
266
|
+
t("workflowExecutions.actions.retry")
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
),
|
|
270
|
+
isRunning && /* @__PURE__ */ jsxs2(
|
|
271
|
+
Button,
|
|
272
|
+
{
|
|
273
|
+
variant: "danger",
|
|
274
|
+
size: "small",
|
|
275
|
+
onClick: handleCancel,
|
|
276
|
+
isLoading: isCancelling,
|
|
277
|
+
children: [
|
|
278
|
+
/* @__PURE__ */ jsx2(XMark, { className: "mr-1" }),
|
|
279
|
+
t("workflowExecutions.actions.cancel")
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
),
|
|
283
|
+
hasWaitingSteps && /* @__PURE__ */ jsx2(Button, { variant: "secondary", size: "small", asChild: true, children: /* @__PURE__ */ jsx2(Link, { to: "complete-step", children: t("workflowExecutions.actions.completeStep") }) }),
|
|
284
|
+
/* @__PURE__ */ jsx2(
|
|
285
|
+
ActionMenu,
|
|
286
|
+
{
|
|
287
|
+
groups: [
|
|
288
|
+
{
|
|
289
|
+
actions: [
|
|
290
|
+
...isFailed ? [
|
|
291
|
+
{
|
|
292
|
+
label: t(
|
|
293
|
+
"workflowExecutions.actions.retryWithNewInput"
|
|
294
|
+
),
|
|
295
|
+
icon: /* @__PURE__ */ jsx2(ArrowPathMini, {}),
|
|
296
|
+
to: "rerun"
|
|
297
|
+
}
|
|
298
|
+
] : [],
|
|
299
|
+
{
|
|
300
|
+
label: t("workflowExecutions.actions.exportJson"),
|
|
301
|
+
icon: /* @__PURE__ */ jsx2(EllipsisHorizontal, {}),
|
|
302
|
+
onClick: handleExportJson
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
label: t("workflowExecutions.actions.exportCsv"),
|
|
306
|
+
icon: /* @__PURE__ */ jsx2(EllipsisHorizontal, {}),
|
|
307
|
+
onClick: handleExportCsv
|
|
308
|
+
}
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
]
|
|
312
|
+
}
|
|
313
|
+
)
|
|
314
|
+
] })
|
|
315
|
+
] }) });
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
// src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-error-card/workflow-execution-error-card.tsx
|
|
319
|
+
import { XCircle } from "@acmekit/icons";
|
|
320
|
+
import { Container as Container2, Heading, Text } from "@acmekit/ui";
|
|
321
|
+
import { useTranslation as useTranslation2 } from "react-i18next";
|
|
322
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
323
|
+
var WorkflowExecutionErrorCard = ({
|
|
324
|
+
execution
|
|
325
|
+
}) => {
|
|
326
|
+
const { t } = useTranslation2();
|
|
327
|
+
if (execution.state !== "failed" /* FAILED */) {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
const failedSteps = getFailedSteps(execution);
|
|
331
|
+
if (failedSteps.length === 0) return null;
|
|
332
|
+
const firstFailure = failedSteps[0];
|
|
333
|
+
const errorMessage = firstFailure.error?.error?.message || firstFailure.error?.error || "Unknown error";
|
|
334
|
+
const handlerType = firstFailure.error?.handlerType || "invoke";
|
|
335
|
+
return /* @__PURE__ */ jsx3(Container2, { className: "border border-ui-tag-red-border bg-ui-tag-red-bg p-0", children: /* @__PURE__ */ jsxs3("div", { className: "flex items-start gap-x-3 px-6 py-4", children: [
|
|
336
|
+
/* @__PURE__ */ jsx3("div", { className: "mt-0.5", children: /* @__PURE__ */ jsx3(XCircle, { className: "text-ui-tag-red-icon" }) }),
|
|
337
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex flex-1 flex-col gap-y-1", children: [
|
|
338
|
+
/* @__PURE__ */ jsx3(Heading, { level: "h3", children: t("workflowExecutions.error.failureAtStep", {
|
|
339
|
+
step: firstFailure.stepId
|
|
340
|
+
}) }),
|
|
341
|
+
/* @__PURE__ */ jsx3(Text, { size: "small", className: "text-ui-fg-subtle", children: String(errorMessage) }),
|
|
342
|
+
/* @__PURE__ */ jsxs3(Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
|
|
343
|
+
handlerType === "compensate" ? "Compensation" : "Invoke",
|
|
344
|
+
" failure"
|
|
345
|
+
] })
|
|
346
|
+
] }),
|
|
347
|
+
/* @__PURE__ */ jsx3(
|
|
348
|
+
"a",
|
|
349
|
+
{
|
|
350
|
+
href: `#${firstFailure.stepId}`,
|
|
351
|
+
className: "text-ui-fg-interactive txt-compact-small-plus shrink-0 hover:underline",
|
|
352
|
+
children: t("workflowExecutions.error.jumpToStep")
|
|
353
|
+
}
|
|
354
|
+
)
|
|
355
|
+
] }) });
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-waiting-banner/workflow-execution-waiting-banner.tsx
|
|
359
|
+
import { ClockSolidMini } from "@acmekit/icons";
|
|
360
|
+
import { Container as Container3, Copy as Copy2, Heading as Heading2, Text as Text2 } from "@acmekit/ui";
|
|
361
|
+
import { useTranslation as useTranslation3 } from "react-i18next";
|
|
362
|
+
import { Link as Link2 } from "react-router-dom";
|
|
363
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
364
|
+
var WorkflowExecutionWaitingBanner = ({
|
|
365
|
+
execution
|
|
366
|
+
}) => {
|
|
367
|
+
const { t } = useTranslation3();
|
|
368
|
+
const waitingSteps = getWaitingSteps(execution);
|
|
369
|
+
if (waitingSteps.length === 0) return null;
|
|
370
|
+
const firstStep = waitingSteps[0];
|
|
371
|
+
const idempotencyKey = computeIdempotencyKey(
|
|
372
|
+
execution.workflow_id,
|
|
373
|
+
execution.transaction_id,
|
|
374
|
+
firstStep.stepId,
|
|
375
|
+
"invoke"
|
|
376
|
+
);
|
|
377
|
+
return /* @__PURE__ */ jsx4(Container3, { className: "border border-ui-tag-purple-border bg-ui-tag-purple-bg p-0", children: /* @__PURE__ */ jsxs4("div", { className: "flex items-start gap-x-3 px-6 py-4", children: [
|
|
378
|
+
/* @__PURE__ */ jsx4("div", { className: "mt-0.5", children: /* @__PURE__ */ jsx4(ClockSolidMini, { className: "text-ui-tag-purple-icon" }) }),
|
|
379
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex flex-1 flex-col gap-y-1", children: [
|
|
380
|
+
/* @__PURE__ */ jsx4(Heading2, { level: "h3", children: t("workflowExecutions.asyncStep.waitingBanner") }),
|
|
381
|
+
/* @__PURE__ */ jsx4(Text2, { size: "small", className: "text-ui-fg-subtle", children: t("workflowExecutions.asyncStep.waitingDescription", {
|
|
382
|
+
step: firstStep.stepId
|
|
383
|
+
}) }),
|
|
384
|
+
/* @__PURE__ */ jsxs4("div", { className: "mt-1 flex items-center gap-x-2", children: [
|
|
385
|
+
/* @__PURE__ */ jsxs4(Text2, { size: "xsmall", className: "text-ui-fg-muted", children: [
|
|
386
|
+
t("workflowExecutions.asyncStep.idempotencyKey"),
|
|
387
|
+
":"
|
|
388
|
+
] }),
|
|
389
|
+
/* @__PURE__ */ jsx4(Copy2, { content: idempotencyKey, asChild: true, children: /* @__PURE__ */ jsx4("code", { className: "bg-ui-bg-base txt-compact-xsmall cursor-pointer rounded px-1.5 py-0.5", children: idempotencyKey }) })
|
|
390
|
+
] })
|
|
391
|
+
] }),
|
|
392
|
+
/* @__PURE__ */ jsx4(
|
|
393
|
+
Link2,
|
|
394
|
+
{
|
|
395
|
+
to: "complete-step",
|
|
396
|
+
className: "text-ui-fg-interactive txt-compact-small-plus shrink-0 hover:underline",
|
|
397
|
+
children: t("workflowExecutions.actions.completeStep")
|
|
398
|
+
}
|
|
399
|
+
)
|
|
400
|
+
] }) });
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-general-section/workflow-execution-general-section.tsx
|
|
404
|
+
import { Badge as Badge2, Container as Container4, Copy as Copy3, Heading as Heading3, StatusBadge as StatusBadge2, Text as Text3, clx } from "@acmekit/ui";
|
|
405
|
+
import { useTranslation as useTranslation4 } from "react-i18next";
|
|
406
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
407
|
+
var WorkflowExecutionGeneralSection = ({
|
|
408
|
+
execution
|
|
409
|
+
}) => {
|
|
410
|
+
const { t } = useTranslation4();
|
|
411
|
+
const { getFullDate } = useDate();
|
|
412
|
+
const cleanId = execution.id.replace("wf_exec_", "");
|
|
413
|
+
const translatedState = getTransactionState(
|
|
414
|
+
t,
|
|
415
|
+
execution.state
|
|
416
|
+
);
|
|
417
|
+
const stateColor = getTransactionStateColor(
|
|
418
|
+
execution.state
|
|
419
|
+
);
|
|
420
|
+
const createdAt = execution.created_at;
|
|
421
|
+
const updatedAt = execution.updated_at;
|
|
422
|
+
const allSteps = Object.values(execution.execution?.steps || {}).filter(
|
|
423
|
+
(step) => step.id !== ROOT_PREFIX
|
|
424
|
+
);
|
|
425
|
+
const totalSteps = allSteps.length;
|
|
426
|
+
const completedSteps = allSteps.filter(
|
|
427
|
+
(step) => step.invoke.state === "done" /* DONE */
|
|
428
|
+
).length;
|
|
429
|
+
const failedSteps = allSteps.filter(
|
|
430
|
+
(step) => STEP_ERROR_STATES.includes(step.invoke.state)
|
|
431
|
+
).length;
|
|
432
|
+
const skippedSteps = allSteps.filter(
|
|
433
|
+
(step) => STEP_SKIPPED_STATES.includes(step.invoke.state)
|
|
434
|
+
).length;
|
|
435
|
+
const compensatedSteps = allSteps.filter(
|
|
436
|
+
(step) => step.compensate.state === "reverted" /* REVERTED */
|
|
437
|
+
).length;
|
|
438
|
+
return /* @__PURE__ */ jsxs5(Container4, { className: "divide-y p-0", children: [
|
|
439
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between px-6 py-4", children: [
|
|
440
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-x-0.5", children: [
|
|
441
|
+
/* @__PURE__ */ jsx5(Heading3, { children: cleanId }),
|
|
442
|
+
/* @__PURE__ */ jsx5(Copy3, { content: cleanId, className: "text-ui-fg-muted" })
|
|
443
|
+
] }),
|
|
444
|
+
/* @__PURE__ */ jsx5(StatusBadge2, { color: stateColor, children: translatedState })
|
|
445
|
+
] }),
|
|
446
|
+
/* @__PURE__ */ jsxs5("div", { className: "text-ui-fg-subtle grid grid-cols-2 px-6 py-4", children: [
|
|
447
|
+
/* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", weight: "plus", children: t("workflowExecutions.workflowIdLabel") }),
|
|
448
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-x-1", children: [
|
|
449
|
+
/* @__PURE__ */ jsx5(Badge2, { size: "2xsmall", className: "w-fit", children: execution.workflow_id }),
|
|
450
|
+
/* @__PURE__ */ jsx5(Copy3, { content: execution.workflow_id, className: "text-ui-fg-muted" })
|
|
451
|
+
] })
|
|
452
|
+
] }),
|
|
453
|
+
/* @__PURE__ */ jsxs5("div", { className: "text-ui-fg-subtle grid grid-cols-2 px-6 py-4", children: [
|
|
454
|
+
/* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", weight: "plus", children: t("workflowExecutions.transactionIdLabel") }),
|
|
455
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-x-1", children: [
|
|
456
|
+
/* @__PURE__ */ jsx5(Badge2, { size: "2xsmall", className: "w-fit", children: execution.transaction_id }),
|
|
457
|
+
/* @__PURE__ */ jsx5(
|
|
458
|
+
Copy3,
|
|
459
|
+
{
|
|
460
|
+
content: execution.transaction_id,
|
|
461
|
+
className: "text-ui-fg-muted"
|
|
462
|
+
}
|
|
463
|
+
)
|
|
464
|
+
] })
|
|
465
|
+
] }),
|
|
466
|
+
/* @__PURE__ */ jsxs5("div", { className: "text-ui-fg-subtle grid grid-cols-2 px-6 py-4", children: [
|
|
467
|
+
/* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", weight: "plus", children: t("workflowExecutions.progressLabel") }),
|
|
468
|
+
/* @__PURE__ */ jsx5(Progress, { steps: execution.execution?.steps })
|
|
469
|
+
] }),
|
|
470
|
+
/* @__PURE__ */ jsxs5("div", { className: "text-ui-fg-subtle grid grid-cols-2 px-6 py-4", children: [
|
|
471
|
+
/* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", weight: "plus", children: t("fields.summary") }),
|
|
472
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-y-1", children: [
|
|
473
|
+
/* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: t("workflowExecutions.metrics.stepsSummary", {
|
|
474
|
+
completed: completedSteps,
|
|
475
|
+
total: totalSteps
|
|
476
|
+
}) }),
|
|
477
|
+
failedSteps > 0 && /* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: t("workflowExecutions.metrics.failedSteps", {
|
|
478
|
+
count: failedSteps
|
|
479
|
+
}) }),
|
|
480
|
+
skippedSteps > 0 && /* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: t("workflowExecutions.metrics.skippedSteps", {
|
|
481
|
+
count: skippedSteps
|
|
482
|
+
}) }),
|
|
483
|
+
/* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: compensatedSteps > 0 ? t("workflowExecutions.metrics.compensatedYes") : t("workflowExecutions.metrics.compensatedNo") })
|
|
484
|
+
] })
|
|
485
|
+
] }),
|
|
486
|
+
/* @__PURE__ */ jsxs5("div", { className: "text-ui-fg-subtle grid grid-cols-2 px-6 py-4", children: [
|
|
487
|
+
/* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", weight: "plus", children: t("fields.createdAt") }),
|
|
488
|
+
/* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", children: createdAt ? getFullDate({ date: createdAt, includeTime: true }) : "-" })
|
|
489
|
+
] }),
|
|
490
|
+
/* @__PURE__ */ jsxs5("div", { className: "text-ui-fg-subtle grid grid-cols-2 px-6 py-4", children: [
|
|
491
|
+
/* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", weight: "plus", children: t("fields.updatedAt") }),
|
|
492
|
+
/* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", children: updatedAt ? getFullDate({ date: updatedAt, includeTime: true }) : "-" })
|
|
493
|
+
] })
|
|
494
|
+
] });
|
|
495
|
+
};
|
|
496
|
+
var ROOT_PREFIX = "_root";
|
|
497
|
+
var Progress = ({
|
|
498
|
+
steps
|
|
499
|
+
}) => {
|
|
500
|
+
const { t } = useTranslation4();
|
|
501
|
+
if (!steps) {
|
|
502
|
+
return /* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: t("workflowExecutions.stepsCompletedLabel", {
|
|
503
|
+
completed: 0,
|
|
504
|
+
count: 0
|
|
505
|
+
}) });
|
|
506
|
+
}
|
|
507
|
+
const actionableSteps = Object.values(steps).filter(
|
|
508
|
+
(step) => step.id !== ROOT_PREFIX
|
|
509
|
+
);
|
|
510
|
+
const completedSteps = actionableSteps.filter(
|
|
511
|
+
(step) => step.invoke.state === "done" /* DONE */
|
|
512
|
+
);
|
|
513
|
+
return /* @__PURE__ */ jsxs5("div", { className: "flex w-fit items-center gap-x-2", children: [
|
|
514
|
+
/* @__PURE__ */ jsx5("div", { className: "flex items-center gap-x-[3px]", children: actionableSteps.map((step) => /* @__PURE__ */ jsx5(
|
|
515
|
+
"div",
|
|
516
|
+
{
|
|
517
|
+
className: clx(
|
|
518
|
+
"bg-ui-bg-switch-off shadow-details-switch-background h-3 w-1.5 rounded-full",
|
|
519
|
+
{
|
|
520
|
+
"bg-ui-fg-muted": step.invoke.state === "done" /* DONE */
|
|
521
|
+
}
|
|
522
|
+
)
|
|
523
|
+
},
|
|
524
|
+
step.id
|
|
525
|
+
)) }),
|
|
526
|
+
/* @__PURE__ */ jsx5(Text3, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: t("workflowExecutions.stepsCompletedLabel", {
|
|
527
|
+
completed: completedSteps.length,
|
|
528
|
+
count: actionableSteps.length
|
|
529
|
+
}) })
|
|
530
|
+
] });
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
// src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-history-section/workflow-execution-history-section.tsx
|
|
534
|
+
import { Spinner, TriangleDownMini } from "@acmekit/icons";
|
|
535
|
+
import {
|
|
536
|
+
Button as Button2,
|
|
537
|
+
clx as clx2,
|
|
538
|
+
CodeBlock,
|
|
539
|
+
Container as Container5,
|
|
540
|
+
Copy as Copy4,
|
|
541
|
+
Heading as Heading4,
|
|
542
|
+
IconButton,
|
|
543
|
+
Text as Text4,
|
|
544
|
+
toast as toast2
|
|
545
|
+
} from "@acmekit/ui";
|
|
546
|
+
import { format } from "date-fns";
|
|
547
|
+
import { Collapsible as RadixCollapsible } from "radix-ui";
|
|
548
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
549
|
+
import { useTranslation as useTranslation5 } from "react-i18next";
|
|
550
|
+
import { useLocation } from "react-router-dom";
|
|
551
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
552
|
+
var WorkflowExecutionHistorySection = ({
|
|
553
|
+
execution
|
|
554
|
+
}) => {
|
|
555
|
+
const { t } = useTranslation5();
|
|
556
|
+
const map = Object.values(execution.execution?.steps || {});
|
|
557
|
+
const steps = map.filter((step) => step.id !== "_root");
|
|
558
|
+
const hasCompensation = [
|
|
559
|
+
"compensating" /* COMPENSATING */,
|
|
560
|
+
"reverted" /* REVERTED */,
|
|
561
|
+
"waiting_to_compensate" /* WAITING_TO_COMPENSATE */
|
|
562
|
+
].includes(execution.state);
|
|
563
|
+
const [showCompensation, setShowCompensation] = useState2(false);
|
|
564
|
+
const unreachableStepId = steps.find(
|
|
565
|
+
(step) => step.invoke.status === "permanent_failure" /* PERMANENT_FAILURE */
|
|
566
|
+
)?.id;
|
|
567
|
+
const unreachableSteps = unreachableStepId ? steps.filter(
|
|
568
|
+
(step) => step.id !== unreachableStepId && step.id.includes(unreachableStepId)
|
|
569
|
+
).map((step) => step.id) : [];
|
|
570
|
+
return /* @__PURE__ */ jsxs6(Container5, { className: "divide-y p-0", children: [
|
|
571
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between px-6 py-4", children: [
|
|
572
|
+
/* @__PURE__ */ jsx6(Heading4, { level: "h2", children: t("workflowExecutions.history.sectionTitle") }),
|
|
573
|
+
hasCompensation && /* @__PURE__ */ jsx6(
|
|
574
|
+
Button2,
|
|
575
|
+
{
|
|
576
|
+
size: "small",
|
|
577
|
+
variant: "secondary",
|
|
578
|
+
onClick: () => setShowCompensation((v) => !v),
|
|
579
|
+
children: showCompensation ? t("workflowExecutions.history.showInvoke") : t("workflowExecutions.history.showCompensation")
|
|
580
|
+
}
|
|
581
|
+
)
|
|
582
|
+
] }),
|
|
583
|
+
/* @__PURE__ */ jsx6("div", { className: "flex flex-col gap-y-0.5 px-6 py-4", children: steps.map((step, index) => {
|
|
584
|
+
const stepId = step.id.split(".").pop();
|
|
585
|
+
if (!stepId) {
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
const context = execution.context?.data.invoke[stepId];
|
|
589
|
+
const error = execution.context?.errors.find(
|
|
590
|
+
(e) => e.action === stepId
|
|
591
|
+
);
|
|
592
|
+
return /* @__PURE__ */ jsx6(
|
|
593
|
+
Event,
|
|
594
|
+
{
|
|
595
|
+
step,
|
|
596
|
+
stepInvokeContext: context,
|
|
597
|
+
stepError: error,
|
|
598
|
+
isLast: index === steps.length - 1,
|
|
599
|
+
isUnreachable: unreachableSteps.includes(step.id),
|
|
600
|
+
execution,
|
|
601
|
+
showCompensation
|
|
602
|
+
},
|
|
603
|
+
step.id
|
|
604
|
+
);
|
|
605
|
+
}) })
|
|
606
|
+
] });
|
|
607
|
+
};
|
|
608
|
+
var Event = ({
|
|
609
|
+
step,
|
|
610
|
+
stepInvokeContext,
|
|
611
|
+
stepError,
|
|
612
|
+
isLast,
|
|
613
|
+
isUnreachable,
|
|
614
|
+
execution,
|
|
615
|
+
showCompensation
|
|
616
|
+
}) => {
|
|
617
|
+
const [open, setOpen] = useState2(false);
|
|
618
|
+
const ref = useRef2(null);
|
|
619
|
+
const { hash } = useLocation();
|
|
620
|
+
const { t } = useTranslation5();
|
|
621
|
+
const stepId = step.id.split(".").pop();
|
|
622
|
+
useEffect2(() => {
|
|
623
|
+
if (hash === `#${stepId}`) {
|
|
624
|
+
setOpen(true);
|
|
625
|
+
}
|
|
626
|
+
}, [hash, stepId]);
|
|
627
|
+
const identifier = step.id.split(".").pop();
|
|
628
|
+
const isPermanentFailure = step.invoke.status === "permanent_failure" /* PERMANENT_FAILURE */;
|
|
629
|
+
const isWaiting = step.invoke.status === "waiting_response" /* WAITING */;
|
|
630
|
+
const idempotencyKey = computeIdempotencyKey(
|
|
631
|
+
execution.workflow_id,
|
|
632
|
+
execution.transaction_id,
|
|
633
|
+
stepId,
|
|
634
|
+
"invoke"
|
|
635
|
+
);
|
|
636
|
+
const duration = formatStepDuration(
|
|
637
|
+
step.startedAt ?? void 0,
|
|
638
|
+
step.endedAt ?? void 0
|
|
639
|
+
);
|
|
640
|
+
const { mutateAsync: retryStep, isPending: isRetrying } = useRetryStep(
|
|
641
|
+
execution.workflow_id,
|
|
642
|
+
execution.transaction_id
|
|
643
|
+
);
|
|
644
|
+
const handleRetryStep = async () => {
|
|
645
|
+
await retryStep(
|
|
646
|
+
{ step_id: stepId },
|
|
647
|
+
{
|
|
648
|
+
onSuccess: () => {
|
|
649
|
+
toast2.success(t("workflowExecutions.actions.retryStepSuccess"));
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
);
|
|
653
|
+
};
|
|
654
|
+
return /* @__PURE__ */ jsxs6(
|
|
655
|
+
"div",
|
|
656
|
+
{
|
|
657
|
+
className: "grid grid-cols-[20px_1fr] items-start gap-x-2 px-2",
|
|
658
|
+
id: stepId,
|
|
659
|
+
children: [
|
|
660
|
+
/* @__PURE__ */ jsxs6("div", { className: "grid h-full grid-rows-[20px_1fr] items-center justify-center gap-y-0.5", children: [
|
|
661
|
+
/* @__PURE__ */ jsx6("div", { className: "flex size-5 items-center justify-center", children: /* @__PURE__ */ jsx6("div", { className: "bg-ui-bg-base shadow-borders-base flex size-2.5 items-center justify-center rounded-full", children: /* @__PURE__ */ jsx6(
|
|
662
|
+
"div",
|
|
663
|
+
{
|
|
664
|
+
className: clx2("size-1.5 rounded-full", {
|
|
665
|
+
"bg-ui-tag-neutral-bg": STEP_SKIPPED_STATES.includes(
|
|
666
|
+
step.invoke.state
|
|
667
|
+
),
|
|
668
|
+
"bg-ui-tag-green-icon": STEP_OK_STATES.includes(
|
|
669
|
+
step.invoke.state
|
|
670
|
+
),
|
|
671
|
+
"bg-ui-tag-purple-icon": isWaiting,
|
|
672
|
+
"bg-ui-tag-orange-icon": !isWaiting && STEP_IN_PROGRESS_STATES.includes(step.invoke.state),
|
|
673
|
+
"bg-ui-tag-red-icon": STEP_ERROR_STATES.includes(
|
|
674
|
+
step.invoke.state
|
|
675
|
+
),
|
|
676
|
+
"bg-ui-tag-neutral-icon": STEP_INACTIVE_STATES.includes(
|
|
677
|
+
step.invoke.state
|
|
678
|
+
)
|
|
679
|
+
})
|
|
680
|
+
}
|
|
681
|
+
) }) }),
|
|
682
|
+
/* @__PURE__ */ jsx6("div", { className: "flex h-full flex-col items-center", children: /* @__PURE__ */ jsx6(
|
|
683
|
+
"div",
|
|
684
|
+
{
|
|
685
|
+
"aria-hidden": true,
|
|
686
|
+
role: "presentation",
|
|
687
|
+
className: clx2({
|
|
688
|
+
"bg-ui-border-base h-full min-h-[14px] w-px": !isLast
|
|
689
|
+
})
|
|
690
|
+
}
|
|
691
|
+
) })
|
|
692
|
+
] }),
|
|
693
|
+
/* @__PURE__ */ jsxs6(
|
|
694
|
+
RadixCollapsible.Root,
|
|
695
|
+
{
|
|
696
|
+
open,
|
|
697
|
+
onOpenChange: (isOpen) => {
|
|
698
|
+
setOpen(isOpen);
|
|
699
|
+
if (isOpen) {
|
|
700
|
+
window.history.replaceState(null, "", `#${stepId}`);
|
|
701
|
+
}
|
|
702
|
+
},
|
|
703
|
+
children: [
|
|
704
|
+
/* @__PURE__ */ jsx6(RadixCollapsible.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs6("div", { className: "group flex cursor-pointer items-start justify-between outline-none", children: [
|
|
705
|
+
/* @__PURE__ */ jsx6(Text4, { size: "small", leading: "compact", weight: "plus", children: identifier }),
|
|
706
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-x-2", children: [
|
|
707
|
+
duration && /* @__PURE__ */ jsx6(Text4, { size: "small", leading: "compact", className: "text-ui-fg-muted", children: duration }),
|
|
708
|
+
/* @__PURE__ */ jsx6(
|
|
709
|
+
StepState,
|
|
710
|
+
{
|
|
711
|
+
state: step.invoke.state,
|
|
712
|
+
status: step.invoke.status,
|
|
713
|
+
startedAt: step.startedAt,
|
|
714
|
+
isUnreachable
|
|
715
|
+
}
|
|
716
|
+
),
|
|
717
|
+
/* @__PURE__ */ jsx6(IconButton, { size: "2xsmall", variant: "transparent", children: /* @__PURE__ */ jsx6(TriangleDownMini, { className: "text-ui-fg-muted transition-transform group-data-[state=open]:rotate-180" }) })
|
|
718
|
+
] })
|
|
719
|
+
] }) }),
|
|
720
|
+
/* @__PURE__ */ jsx6(RadixCollapsible.Content, { ref, children: /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-y-2 pb-4 pt-2", children: [
|
|
721
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between", children: [
|
|
722
|
+
/* @__PURE__ */ jsx6(Text4, { size: "xsmall", className: "text-ui-fg-muted", children: t("workflowExecutions.history.idempotencyKeyLabel") }),
|
|
723
|
+
/* @__PURE__ */ jsx6(Copy4, { content: idempotencyKey, asChild: true, children: /* @__PURE__ */ jsx6(
|
|
724
|
+
Text4,
|
|
725
|
+
{
|
|
726
|
+
size: "xsmall",
|
|
727
|
+
className: "text-ui-fg-subtle cursor-pointer font-mono",
|
|
728
|
+
children: idempotencyKey
|
|
729
|
+
}
|
|
730
|
+
) })
|
|
731
|
+
] }),
|
|
732
|
+
isPermanentFailure && /* @__PURE__ */ jsx6("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx6(
|
|
733
|
+
Button2,
|
|
734
|
+
{
|
|
735
|
+
size: "small",
|
|
736
|
+
variant: "secondary",
|
|
737
|
+
isLoading: isRetrying,
|
|
738
|
+
onClick: handleRetryStep,
|
|
739
|
+
children: t("workflowExecutions.history.retryFromStep")
|
|
740
|
+
}
|
|
741
|
+
) }),
|
|
742
|
+
/* @__PURE__ */ jsxs6("div", { className: "text-ui-fg-subtle flex flex-col gap-y-2", children: [
|
|
743
|
+
/* @__PURE__ */ jsx6(Text4, { size: "small", leading: "compact", children: t("workflowExecutions.history.definitionLabel") }),
|
|
744
|
+
/* @__PURE__ */ jsx6(
|
|
745
|
+
CodeBlock,
|
|
746
|
+
{
|
|
747
|
+
snippets: [
|
|
748
|
+
{
|
|
749
|
+
code: JSON.stringify(step.definition, null, 2),
|
|
750
|
+
label: t("workflowExecutions.history.definitionLabel"),
|
|
751
|
+
language: "json",
|
|
752
|
+
hideLineNumbers: true
|
|
753
|
+
}
|
|
754
|
+
],
|
|
755
|
+
children: /* @__PURE__ */ jsx6(CodeBlock.Body, {})
|
|
756
|
+
}
|
|
757
|
+
)
|
|
758
|
+
] }),
|
|
759
|
+
stepInvokeContext && /* @__PURE__ */ jsxs6("div", { className: "text-ui-fg-subtle flex flex-col gap-y-2", children: [
|
|
760
|
+
/* @__PURE__ */ jsx6(Text4, { size: "small", leading: "compact", children: t("workflowExecutions.history.outputLabel") }),
|
|
761
|
+
/* @__PURE__ */ jsx6(
|
|
762
|
+
CodeBlock,
|
|
763
|
+
{
|
|
764
|
+
snippets: [
|
|
765
|
+
{
|
|
766
|
+
code: JSON.stringify(
|
|
767
|
+
// TODO: Apply resolve value: packages/core/workflows-sdk/src/utils/composer/helpers/resolve-value.ts
|
|
768
|
+
stepInvokeContext?.output?.output ?? {},
|
|
769
|
+
null,
|
|
770
|
+
2
|
|
771
|
+
),
|
|
772
|
+
label: t("workflowExecutions.history.outputLabel"),
|
|
773
|
+
language: "json",
|
|
774
|
+
hideLineNumbers: true
|
|
775
|
+
}
|
|
776
|
+
],
|
|
777
|
+
children: /* @__PURE__ */ jsx6(CodeBlock.Body, {})
|
|
778
|
+
}
|
|
779
|
+
)
|
|
780
|
+
] }),
|
|
781
|
+
showCompensation && step.compensate.state !== "not_started" /* NOT_STARTED */ && /* @__PURE__ */ jsxs6("div", { className: "border-ui-tag-orange-border bg-ui-tag-orange-bg rounded-md border p-3", children: [
|
|
782
|
+
/* @__PURE__ */ jsxs6(Text4, { size: "xsmall", weight: "plus", className: "text-ui-tag-orange-text mb-2", children: [
|
|
783
|
+
"\u21A9 ",
|
|
784
|
+
t("workflowExecutions.history.revertedLabel"),
|
|
785
|
+
" \u2014 ",
|
|
786
|
+
step.compensate.state
|
|
787
|
+
] }),
|
|
788
|
+
!!stepInvokeContext?.output?.compensateInput && /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-y-1", children: [
|
|
789
|
+
/* @__PURE__ */ jsx6(Text4, { size: "xsmall", className: "text-ui-fg-subtle", children: t("workflowExecutions.history.compensateInputLabel") }),
|
|
790
|
+
/* @__PURE__ */ jsx6(
|
|
791
|
+
CodeBlock,
|
|
792
|
+
{
|
|
793
|
+
snippets: [
|
|
794
|
+
{
|
|
795
|
+
code: JSON.stringify(
|
|
796
|
+
stepInvokeContext?.output?.compensateInput ?? {},
|
|
797
|
+
null,
|
|
798
|
+
2
|
|
799
|
+
),
|
|
800
|
+
label: t("workflowExecutions.history.compensateInputLabel"),
|
|
801
|
+
language: "json",
|
|
802
|
+
hideLineNumbers: true
|
|
803
|
+
}
|
|
804
|
+
],
|
|
805
|
+
children: /* @__PURE__ */ jsx6(CodeBlock.Body, {})
|
|
806
|
+
}
|
|
807
|
+
)
|
|
808
|
+
] })
|
|
809
|
+
] }),
|
|
810
|
+
!showCompensation && !!stepInvokeContext?.output?.compensateInput && step.compensate.state === "reverted" /* REVERTED */ && /* @__PURE__ */ jsxs6("div", { className: "text-ui-fg-subtle flex flex-col gap-y-2", children: [
|
|
811
|
+
/* @__PURE__ */ jsx6(Text4, { size: "small", leading: "compact", children: t("workflowExecutions.history.compensateInputLabel") }),
|
|
812
|
+
/* @__PURE__ */ jsx6(
|
|
813
|
+
CodeBlock,
|
|
814
|
+
{
|
|
815
|
+
snippets: [
|
|
816
|
+
{
|
|
817
|
+
// TODO: Apply resolve value: packages/core/workflows-sdk/src/utils/composer/helpers/resolve-value.ts
|
|
818
|
+
code: JSON.stringify(
|
|
819
|
+
stepInvokeContext?.output?.compensateInput ?? {},
|
|
820
|
+
null,
|
|
821
|
+
2
|
|
822
|
+
),
|
|
823
|
+
label: t(
|
|
824
|
+
"workflowExecutions.history.compensateInputLabel"
|
|
825
|
+
),
|
|
826
|
+
language: "json",
|
|
827
|
+
hideLineNumbers: true
|
|
828
|
+
}
|
|
829
|
+
],
|
|
830
|
+
children: /* @__PURE__ */ jsx6(CodeBlock.Body, {})
|
|
831
|
+
}
|
|
832
|
+
)
|
|
833
|
+
] }),
|
|
834
|
+
stepError && /* @__PURE__ */ jsxs6("div", { className: "text-ui-fg-subtle flex flex-col gap-y-2", children: [
|
|
835
|
+
/* @__PURE__ */ jsx6(Text4, { size: "small", leading: "compact", children: t("workflowExecutions.history.errorLabel") }),
|
|
836
|
+
/* @__PURE__ */ jsx6(
|
|
837
|
+
CodeBlock,
|
|
838
|
+
{
|
|
839
|
+
snippets: [
|
|
840
|
+
{
|
|
841
|
+
code: JSON.stringify(
|
|
842
|
+
{
|
|
843
|
+
error: stepError.error,
|
|
844
|
+
handlerType: stepError.handlerType
|
|
845
|
+
},
|
|
846
|
+
null,
|
|
847
|
+
2
|
|
848
|
+
),
|
|
849
|
+
label: t("workflowExecutions.history.errorLabel"),
|
|
850
|
+
language: "json",
|
|
851
|
+
hideLineNumbers: true
|
|
852
|
+
}
|
|
853
|
+
],
|
|
854
|
+
children: /* @__PURE__ */ jsx6(CodeBlock.Body, {})
|
|
855
|
+
}
|
|
856
|
+
)
|
|
857
|
+
] })
|
|
858
|
+
] }) })
|
|
859
|
+
]
|
|
860
|
+
}
|
|
861
|
+
)
|
|
862
|
+
]
|
|
863
|
+
}
|
|
864
|
+
);
|
|
865
|
+
};
|
|
866
|
+
var StepState = ({
|
|
867
|
+
state,
|
|
868
|
+
status,
|
|
869
|
+
startedAt,
|
|
870
|
+
isUnreachable
|
|
871
|
+
}) => {
|
|
872
|
+
const { t } = useTranslation5();
|
|
873
|
+
const isFailed = state === "failed" /* FAILED */;
|
|
874
|
+
const isRunning = state === "invoking" /* INVOKING */;
|
|
875
|
+
const isWaitingResponse = status === "waiting_response" /* WAITING */;
|
|
876
|
+
const isSkipped = state === "skipped" /* SKIPPED */;
|
|
877
|
+
const isSkippedFailure = state === "skipped_failure" /* SKIPPED_FAILURE */;
|
|
878
|
+
if (isUnreachable) {
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
if (isWaitingResponse) {
|
|
882
|
+
return /* @__PURE__ */ jsx6("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsx6(Text4, { size: "small", leading: "compact", className: "text-ui-tag-purple-text", children: t("workflowExecutions.history.awaitingState") }) });
|
|
883
|
+
}
|
|
884
|
+
if (isRunning) {
|
|
885
|
+
return /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-x-1", children: [
|
|
886
|
+
/* @__PURE__ */ jsx6(Text4, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: t("workflowExecutions.history.runningState") }),
|
|
887
|
+
/* @__PURE__ */ jsx6(Spinner, { className: "text-ui-fg-interactive animate-spin" })
|
|
888
|
+
] });
|
|
889
|
+
}
|
|
890
|
+
let stateText;
|
|
891
|
+
if (isSkipped) {
|
|
892
|
+
stateText = t("workflowExecutions.history.skippedState");
|
|
893
|
+
} else if (isSkippedFailure) {
|
|
894
|
+
stateText = t("workflowExecutions.history.skippedFailureState");
|
|
895
|
+
} else if (isFailed) {
|
|
896
|
+
stateText = t("workflowExecutions.history.failedState");
|
|
897
|
+
}
|
|
898
|
+
if (stateText !== null) {
|
|
899
|
+
return /* @__PURE__ */ jsx6(Text4, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: stateText });
|
|
900
|
+
}
|
|
901
|
+
if (startedAt) {
|
|
902
|
+
return /* @__PURE__ */ jsx6(Text4, { size: "small", leading: "compact", className: "text-ui-fg-muted", children: format(startedAt, "dd MMM yyyy HH:mm:ss") });
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
|
|
906
|
+
// src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-payload-section/workflow-execution-payload-section.tsx
|
|
907
|
+
import { Button as Button3, Container as Container6, Heading as Heading5, Tabs, toast as toast3 } from "@acmekit/ui";
|
|
908
|
+
import { useState as useState3 } from "react";
|
|
909
|
+
import { useTranslation as useTranslation6 } from "react-i18next";
|
|
910
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
911
|
+
function downloadJson(data, filename) {
|
|
912
|
+
const blob = new Blob([JSON.stringify(data, null, 2)], {
|
|
913
|
+
type: "application/json"
|
|
914
|
+
});
|
|
915
|
+
const url = URL.createObjectURL(blob);
|
|
916
|
+
const a = document.createElement("a");
|
|
917
|
+
a.href = url;
|
|
918
|
+
a.download = filename;
|
|
919
|
+
a.click();
|
|
920
|
+
URL.revokeObjectURL(url);
|
|
921
|
+
}
|
|
922
|
+
var WorkflowExecutionPayloadSection = ({
|
|
923
|
+
execution
|
|
924
|
+
}) => {
|
|
925
|
+
const { t } = useTranslation6();
|
|
926
|
+
let payload = execution.context?.data?.payload;
|
|
927
|
+
if (payload && typeof payload !== "object") {
|
|
928
|
+
payload = { input: payload };
|
|
929
|
+
}
|
|
930
|
+
const checkpoint = execution.context || {};
|
|
931
|
+
const errors = execution.context?.errors || [];
|
|
932
|
+
const stepOutputs = {};
|
|
933
|
+
const steps = execution?.execution?.steps || {};
|
|
934
|
+
for (const [stepId, step] of Object.entries(steps)) {
|
|
935
|
+
if (stepId === "_root") continue;
|
|
936
|
+
const output = step?.invoke?.output;
|
|
937
|
+
if (output !== void 0) {
|
|
938
|
+
stepOutputs[stepId] = output;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
const hasPayload = !!payload;
|
|
942
|
+
const hasStepOutputs = Object.keys(stepOutputs).length > 0;
|
|
943
|
+
const hasErrors = errors.length > 0;
|
|
944
|
+
const defaultTab = hasPayload ? "input" : "checkpoint";
|
|
945
|
+
const [activeTab, setActiveTab] = useState3(defaultTab);
|
|
946
|
+
if (!hasPayload && !hasStepOutputs && !hasErrors) {
|
|
947
|
+
return null;
|
|
948
|
+
}
|
|
949
|
+
const activeData = activeTab === "input" ? payload : activeTab === "checkpoint" ? checkpoint : activeTab === "outputs" ? stepOutputs : errors;
|
|
950
|
+
const handleCopyAll = () => {
|
|
951
|
+
navigator.clipboard.writeText(JSON.stringify(activeData, null, 2));
|
|
952
|
+
toast3.success("Copied to clipboard");
|
|
953
|
+
};
|
|
954
|
+
const handleDownload = () => {
|
|
955
|
+
downloadJson(
|
|
956
|
+
activeData,
|
|
957
|
+
`${execution.workflow_id}-${activeTab}.json`
|
|
958
|
+
);
|
|
959
|
+
};
|
|
960
|
+
return /* @__PURE__ */ jsxs7(Container6, { className: "divide-y p-0", children: [
|
|
961
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between px-6 py-4", children: [
|
|
962
|
+
/* @__PURE__ */ jsx7(Heading5, { level: "h2", children: t("workflowExecutions.payload.inputPayload") }),
|
|
963
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-x-2", children: [
|
|
964
|
+
/* @__PURE__ */ jsx7(Button3, { size: "small", variant: "transparent", onClick: handleCopyAll, children: t("workflowExecutions.payload.copyAll") }),
|
|
965
|
+
/* @__PURE__ */ jsx7(Button3, { size: "small", variant: "transparent", onClick: handleDownload, children: t("workflowExecutions.payload.downloadJson") })
|
|
966
|
+
] })
|
|
967
|
+
] }),
|
|
968
|
+
/* @__PURE__ */ jsxs7(
|
|
969
|
+
Tabs,
|
|
970
|
+
{
|
|
971
|
+
value: activeTab,
|
|
972
|
+
onValueChange: setActiveTab,
|
|
973
|
+
children: [
|
|
974
|
+
/* @__PURE__ */ jsx7("div", { className: "border-ui-border-base border-b px-6", children: /* @__PURE__ */ jsxs7(Tabs.List, { children: [
|
|
975
|
+
hasPayload && /* @__PURE__ */ jsx7(Tabs.Trigger, { value: "input", children: t("workflowExecutions.payload.inputPayload") }),
|
|
976
|
+
/* @__PURE__ */ jsx7(Tabs.Trigger, { value: "checkpoint", children: t("workflowExecutions.payload.fullCheckpoint") }),
|
|
977
|
+
hasStepOutputs && /* @__PURE__ */ jsx7(Tabs.Trigger, { value: "outputs", children: t("workflowExecutions.payload.stepOutputs") }),
|
|
978
|
+
hasErrors && /* @__PURE__ */ jsx7(Tabs.Trigger, { value: "errors", children: t("workflowExecutions.payload.errors") })
|
|
979
|
+
] }) }),
|
|
980
|
+
hasPayload && /* @__PURE__ */ jsx7(Tabs.Content, { value: "input", className: "p-0", children: /* @__PURE__ */ jsx7(JsonViewSection, { data: payload }) }),
|
|
981
|
+
/* @__PURE__ */ jsx7(Tabs.Content, { value: "checkpoint", className: "p-0", children: /* @__PURE__ */ jsx7(JsonViewSection, { data: checkpoint }) }),
|
|
982
|
+
hasStepOutputs && /* @__PURE__ */ jsx7(Tabs.Content, { value: "outputs", className: "p-0", children: /* @__PURE__ */ jsx7(JsonViewSection, { data: stepOutputs }) }),
|
|
983
|
+
hasErrors && /* @__PURE__ */ jsx7(Tabs.Content, { value: "errors", className: "p-0", children: /* @__PURE__ */ jsx7(JsonViewSection, { data: errors }) })
|
|
984
|
+
]
|
|
985
|
+
}
|
|
986
|
+
)
|
|
987
|
+
] });
|
|
988
|
+
};
|
|
989
|
+
|
|
990
|
+
// src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-timeline-section/workflow-execution-timeline-section.tsx
|
|
991
|
+
import { ArrowPathMini as ArrowPathMini2, MinusMini, PlusMini } from "@acmekit/icons";
|
|
992
|
+
import { Container as Container7, DropdownMenu, Heading as Heading6, Text as Text5, clx as clx3 } from "@acmekit/ui";
|
|
993
|
+
import {
|
|
994
|
+
motion,
|
|
995
|
+
useAnimationControls,
|
|
996
|
+
useDragControls,
|
|
997
|
+
useMotionValue
|
|
998
|
+
} from "motion/react";
|
|
999
|
+
import { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
|
|
1000
|
+
import { useTranslation as useTranslation7 } from "react-i18next";
|
|
1001
|
+
import { Link as Link3 } from "react-router-dom";
|
|
1002
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1003
|
+
var WorkflowExecutionTimelineSection = ({
|
|
1004
|
+
execution
|
|
1005
|
+
}) => {
|
|
1006
|
+
const { t } = useTranslation7();
|
|
1007
|
+
return /* @__PURE__ */ jsxs8(Container7, { className: "overflow-hidden px-0 pb-8 pt-0", children: [
|
|
1008
|
+
/* @__PURE__ */ jsx8("div", { className: "flex items-center justify-between px-6 py-4", children: /* @__PURE__ */ jsx8(Heading6, { level: "h2", children: t("general.timeline") }) }),
|
|
1009
|
+
/* @__PURE__ */ jsx8("div", { className: "w-full overflow-hidden border-y", children: /* @__PURE__ */ jsx8(Canvas, { execution }) })
|
|
1010
|
+
] });
|
|
1011
|
+
};
|
|
1012
|
+
var createNodeClusters = (steps) => {
|
|
1013
|
+
const actionableSteps = Object.values(steps).filter(
|
|
1014
|
+
(step) => step.id !== "_root"
|
|
1015
|
+
);
|
|
1016
|
+
const clusters = {};
|
|
1017
|
+
actionableSteps.forEach((step) => {
|
|
1018
|
+
if (!clusters[step.depth]) {
|
|
1019
|
+
clusters[step.depth] = [];
|
|
1020
|
+
}
|
|
1021
|
+
clusters[step.depth].push(step);
|
|
1022
|
+
});
|
|
1023
|
+
return clusters;
|
|
1024
|
+
};
|
|
1025
|
+
var getNextCluster = (clusters, depth) => {
|
|
1026
|
+
const nextDepth = depth + 1;
|
|
1027
|
+
return clusters[nextDepth];
|
|
1028
|
+
};
|
|
1029
|
+
var defaultState = {
|
|
1030
|
+
x: -860,
|
|
1031
|
+
y: -1020,
|
|
1032
|
+
scale: 1
|
|
1033
|
+
};
|
|
1034
|
+
var MAX_ZOOM = 1.5;
|
|
1035
|
+
var MIN_ZOOM = 0.5;
|
|
1036
|
+
var ZOOM_STEP = 0.25;
|
|
1037
|
+
var Canvas = ({
|
|
1038
|
+
execution
|
|
1039
|
+
}) => {
|
|
1040
|
+
const [zoom, setZoom] = useState4(1);
|
|
1041
|
+
const [isDragging, setIsDragging] = useState4(false);
|
|
1042
|
+
const direction = useDocumentDirection();
|
|
1043
|
+
const scale = useMotionValue(defaultState.scale);
|
|
1044
|
+
const x = useMotionValue(defaultState.x);
|
|
1045
|
+
const y = useMotionValue(defaultState.y);
|
|
1046
|
+
const controls = useAnimationControls();
|
|
1047
|
+
const dragControls = useDragControls();
|
|
1048
|
+
const dragConstraints = useRef3(null);
|
|
1049
|
+
const canZoomIn = zoom < MAX_ZOOM;
|
|
1050
|
+
const canZoomOut = zoom > MIN_ZOOM;
|
|
1051
|
+
useEffect3(() => {
|
|
1052
|
+
const unsubscribe = scale.on("change", (latest) => {
|
|
1053
|
+
setZoom(latest);
|
|
1054
|
+
});
|
|
1055
|
+
return () => {
|
|
1056
|
+
unsubscribe();
|
|
1057
|
+
};
|
|
1058
|
+
}, [scale]);
|
|
1059
|
+
const clusters = createNodeClusters(execution.execution?.steps || {});
|
|
1060
|
+
function scaleXandY(prevScale, newScale, x2, y2) {
|
|
1061
|
+
const scaleRatio = newScale / prevScale;
|
|
1062
|
+
return {
|
|
1063
|
+
x: x2 * scaleRatio,
|
|
1064
|
+
y: y2 * scaleRatio
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
const changeZoom = (newScale) => {
|
|
1068
|
+
const { x: newX, y: newY } = scaleXandY(zoom, newScale, x.get(), y.get());
|
|
1069
|
+
setZoom(newScale);
|
|
1070
|
+
controls.set({ scale: newScale, x: newX, y: newY });
|
|
1071
|
+
};
|
|
1072
|
+
const zoomIn = () => {
|
|
1073
|
+
const curr = scale.get();
|
|
1074
|
+
if (curr < 1.5) {
|
|
1075
|
+
const newScale = curr + ZOOM_STEP;
|
|
1076
|
+
changeZoom(newScale);
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
const zoomOut = () => {
|
|
1080
|
+
const curr = scale.get();
|
|
1081
|
+
if (curr > 0.5) {
|
|
1082
|
+
const newScale = curr - ZOOM_STEP;
|
|
1083
|
+
changeZoom(newScale);
|
|
1084
|
+
}
|
|
1085
|
+
};
|
|
1086
|
+
const resetCanvas = () => {
|
|
1087
|
+
controls.start(defaultState);
|
|
1088
|
+
};
|
|
1089
|
+
return /* @__PURE__ */ jsx8("div", { className: "h-[400px] w-full", children: /* @__PURE__ */ jsxs8("div", { ref: dragConstraints, className: "relative size-full", children: [
|
|
1090
|
+
/* @__PURE__ */ jsx8("div", { className: "relative size-full overflow-hidden object-contain", children: /* @__PURE__ */ jsx8("div", { children: /* @__PURE__ */ jsx8(
|
|
1091
|
+
motion.div,
|
|
1092
|
+
{
|
|
1093
|
+
onMouseDown: () => setIsDragging(true),
|
|
1094
|
+
onMouseUp: () => setIsDragging(false),
|
|
1095
|
+
drag: true,
|
|
1096
|
+
dragConstraints,
|
|
1097
|
+
dragElastic: 0,
|
|
1098
|
+
dragMomentum: false,
|
|
1099
|
+
dragControls,
|
|
1100
|
+
initial: false,
|
|
1101
|
+
animate: controls,
|
|
1102
|
+
transition: { duration: 0.25 },
|
|
1103
|
+
style: {
|
|
1104
|
+
x,
|
|
1105
|
+
y,
|
|
1106
|
+
scale
|
|
1107
|
+
},
|
|
1108
|
+
className: clx3(
|
|
1109
|
+
"bg-ui-bg-subtle relative size-[500rem] origin-top-left items-start justify-start overflow-hidden",
|
|
1110
|
+
"bg-[radial-gradient(var(--border-base)_1.5px,transparent_0)] bg-[length:20px_20px] bg-repeat",
|
|
1111
|
+
{
|
|
1112
|
+
"cursor-grab": !isDragging,
|
|
1113
|
+
"cursor-grabbing": isDragging
|
|
1114
|
+
}
|
|
1115
|
+
),
|
|
1116
|
+
children: /* @__PURE__ */ jsx8("main", { className: "size-full", children: /* @__PURE__ */ jsx8("div", { className: "absolute left-[1100px] top-[1100px] flex select-none items-start", children: Object.entries(clusters).map(([depth, cluster]) => {
|
|
1117
|
+
const next = getNextCluster(clusters, Number(depth));
|
|
1118
|
+
return /* @__PURE__ */ jsxs8("div", { className: "flex items-start", children: [
|
|
1119
|
+
/* @__PURE__ */ jsx8("div", { className: "flex flex-col justify-center gap-y-2", children: cluster.map((step) => /* @__PURE__ */ jsx8(Node, { step }, step.id)) }),
|
|
1120
|
+
/* @__PURE__ */ jsx8(Line, { next })
|
|
1121
|
+
] }, depth);
|
|
1122
|
+
}) }) })
|
|
1123
|
+
}
|
|
1124
|
+
) }) }),
|
|
1125
|
+
/* @__PURE__ */ jsxs8("div", { className: "bg-ui-bg-base shadow-borders-base text-ui-fg-subtle absolute bottom-4 left-6 flex h-7 items-center overflow-hidden rounded-md", children: [
|
|
1126
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center", children: [
|
|
1127
|
+
/* @__PURE__ */ jsx8(
|
|
1128
|
+
"button",
|
|
1129
|
+
{
|
|
1130
|
+
onClick: zoomIn,
|
|
1131
|
+
type: "button",
|
|
1132
|
+
disabled: !canZoomIn,
|
|
1133
|
+
"aria-label": "Zoom in",
|
|
1134
|
+
className: "disabled:text-ui-fg-disabled transition-fg hover:bg-ui-bg-base-hover active:bg-ui-bg-base-pressed focus-visible:bg-ui-bg-base-pressed border-r p-1 outline-none",
|
|
1135
|
+
children: /* @__PURE__ */ jsx8(PlusMini, {})
|
|
1136
|
+
}
|
|
1137
|
+
),
|
|
1138
|
+
/* @__PURE__ */ jsx8("div", { children: /* @__PURE__ */ jsxs8(DropdownMenu, { dir: direction, children: [
|
|
1139
|
+
/* @__PURE__ */ jsx8(DropdownMenu.Trigger, { className: "disabled:text-ui-fg-disabled transition-fg hover:bg-ui-bg-base-hover active:bg-ui-bg-base-pressed focus-visible:bg-ui-bg-base-pressed flex w-[50px] items-center justify-center border-r p-1 outline-none", children: /* @__PURE__ */ jsxs8(
|
|
1140
|
+
Text5,
|
|
1141
|
+
{
|
|
1142
|
+
as: "span",
|
|
1143
|
+
size: "xsmall",
|
|
1144
|
+
leading: "compact",
|
|
1145
|
+
className: "select-none tabular-nums",
|
|
1146
|
+
children: [
|
|
1147
|
+
Math.round(zoom * 100),
|
|
1148
|
+
"%"
|
|
1149
|
+
]
|
|
1150
|
+
}
|
|
1151
|
+
) }),
|
|
1152
|
+
/* @__PURE__ */ jsx8(DropdownMenu.Content, { children: [50, 75, 100, 125, 150].map((value) => /* @__PURE__ */ jsxs8(
|
|
1153
|
+
DropdownMenu.Item,
|
|
1154
|
+
{
|
|
1155
|
+
onClick: () => changeZoom(value / 100),
|
|
1156
|
+
children: [
|
|
1157
|
+
value,
|
|
1158
|
+
"%"
|
|
1159
|
+
]
|
|
1160
|
+
},
|
|
1161
|
+
value
|
|
1162
|
+
)) })
|
|
1163
|
+
] }) }),
|
|
1164
|
+
/* @__PURE__ */ jsx8(
|
|
1165
|
+
"button",
|
|
1166
|
+
{
|
|
1167
|
+
onClick: zoomOut,
|
|
1168
|
+
type: "button",
|
|
1169
|
+
disabled: !canZoomOut,
|
|
1170
|
+
"aria-label": "Zoom out",
|
|
1171
|
+
className: "disabled:text-ui-fg-disabled transition-fg hover:bg-ui-bg-base-hover active:bg-ui-bg-base-pressed focus-visible:bg-ui-bg-base-pressed border-r p-1 outline-none",
|
|
1172
|
+
children: /* @__PURE__ */ jsx8(MinusMini, {})
|
|
1173
|
+
}
|
|
1174
|
+
)
|
|
1175
|
+
] }),
|
|
1176
|
+
/* @__PURE__ */ jsx8(
|
|
1177
|
+
"button",
|
|
1178
|
+
{
|
|
1179
|
+
onClick: resetCanvas,
|
|
1180
|
+
type: "button",
|
|
1181
|
+
"aria-label": "Reset canvas",
|
|
1182
|
+
className: "disabled:text-ui-fg-disabled transition-fg hover:bg-ui-bg-base-hover active:bg-ui-bg-base-pressed focus-visible:bg-ui-bg-base-pressed p-1 outline-none",
|
|
1183
|
+
children: /* @__PURE__ */ jsx8(ArrowPathMini2, {})
|
|
1184
|
+
}
|
|
1185
|
+
)
|
|
1186
|
+
] })
|
|
1187
|
+
] }) });
|
|
1188
|
+
};
|
|
1189
|
+
var HorizontalArrow = () => {
|
|
1190
|
+
return /* @__PURE__ */ jsx8(
|
|
1191
|
+
"svg",
|
|
1192
|
+
{
|
|
1193
|
+
width: "42",
|
|
1194
|
+
height: "12",
|
|
1195
|
+
viewBox: "0 0 42 12",
|
|
1196
|
+
fill: "none",
|
|
1197
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1198
|
+
children: /* @__PURE__ */ jsx8(
|
|
1199
|
+
"path",
|
|
1200
|
+
{
|
|
1201
|
+
d: "M41.5303 6.53033C41.8232 6.23744 41.8232 5.76256 41.5303 5.46967L36.7574 0.696699C36.4645 0.403806 35.9896 0.403806 35.6967 0.696699C35.4038 0.989593 35.4038 1.46447 35.6967 1.75736L39.9393 6L35.6967 10.2426C35.4038 10.5355 35.4038 11.0104 35.6967 11.3033C35.9896 11.5962 36.4645 11.5962 36.7574 11.3033L41.5303 6.53033ZM0.999996 5.25C0.585785 5.25 0.249996 5.58579 0.249996 6C0.249996 6.41421 0.585785 6.75 0.999996 6.75V5.25ZM41 5.25L0.999996 5.25V6.75L41 6.75V5.25Z",
|
|
1202
|
+
fill: "var(--border-strong)"
|
|
1203
|
+
}
|
|
1204
|
+
)
|
|
1205
|
+
}
|
|
1206
|
+
);
|
|
1207
|
+
};
|
|
1208
|
+
var MiddleArrow = () => {
|
|
1209
|
+
return /* @__PURE__ */ jsx8(
|
|
1210
|
+
"svg",
|
|
1211
|
+
{
|
|
1212
|
+
width: "22",
|
|
1213
|
+
height: "38",
|
|
1214
|
+
viewBox: "0 0 22 38",
|
|
1215
|
+
fill: "none",
|
|
1216
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1217
|
+
className: "-mt-[6px]",
|
|
1218
|
+
children: /* @__PURE__ */ jsx8(
|
|
1219
|
+
"path",
|
|
1220
|
+
{
|
|
1221
|
+
d: "M0.999878 32H0.249878V32.75H0.999878V32ZM21.5284 32.5303C21.8213 32.2374 21.8213 31.7626 21.5284 31.4697L16.7554 26.6967C16.4625 26.4038 15.9876 26.4038 15.6947 26.6967C15.4019 26.9896 15.4019 27.4645 15.6947 27.7574L19.9374 32L15.6947 36.2426C15.4019 36.5355 15.4019 37.0104 15.6947 37.3033C15.9876 37.5962 16.4625 37.5962 16.7554 37.3033L21.5284 32.5303ZM0.249878 0L0.249878 32H1.74988L1.74988 0H0.249878ZM0.999878 32.75L20.998 32.75V31.25L0.999878 31.25V32.75Z",
|
|
1222
|
+
fill: "var(--border-strong)"
|
|
1223
|
+
}
|
|
1224
|
+
)
|
|
1225
|
+
}
|
|
1226
|
+
);
|
|
1227
|
+
};
|
|
1228
|
+
var EndArrow = () => {
|
|
1229
|
+
return /* @__PURE__ */ jsx8(
|
|
1230
|
+
"svg",
|
|
1231
|
+
{
|
|
1232
|
+
width: "22",
|
|
1233
|
+
height: "38",
|
|
1234
|
+
viewBox: "0 0 22 38",
|
|
1235
|
+
fill: "none",
|
|
1236
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1237
|
+
className: "-mt-[6px]",
|
|
1238
|
+
children: /* @__PURE__ */ jsx8(
|
|
1239
|
+
"path",
|
|
1240
|
+
{
|
|
1241
|
+
d: "M21.5284 32.5303C21.8213 32.2374 21.8213 31.7626 21.5284 31.4697L16.7554 26.6967C16.4625 26.4038 15.9876 26.4038 15.6947 26.6967C15.4019 26.9896 15.4019 27.4645 15.6947 27.7574L19.9374 32L15.6947 36.2426C15.4019 36.5355 15.4019 37.0104 15.6947 37.3033C15.9876 37.5962 16.4625 37.5962 16.7554 37.3033L21.5284 32.5303ZM0.249878 0L0.249878 28H1.74988L1.74988 0H0.249878ZM4.99988 32.75L20.998 32.75V31.25L4.99988 31.25V32.75ZM0.249878 28C0.249878 30.6234 2.37653 32.75 4.99988 32.75V31.25C3.20495 31.25 1.74988 29.7949 1.74988 28H0.249878Z",
|
|
1242
|
+
fill: "var(--border-strong)"
|
|
1243
|
+
}
|
|
1244
|
+
)
|
|
1245
|
+
}
|
|
1246
|
+
);
|
|
1247
|
+
};
|
|
1248
|
+
var Arrow = ({ depth }) => {
|
|
1249
|
+
if (depth === 1) {
|
|
1250
|
+
return /* @__PURE__ */ jsx8(HorizontalArrow, {});
|
|
1251
|
+
}
|
|
1252
|
+
if (depth === 2) {
|
|
1253
|
+
return /* @__PURE__ */ jsxs8("div", { className: "flex flex-col items-end", children: [
|
|
1254
|
+
/* @__PURE__ */ jsx8(HorizontalArrow, {}),
|
|
1255
|
+
/* @__PURE__ */ jsx8(EndArrow, {})
|
|
1256
|
+
] });
|
|
1257
|
+
}
|
|
1258
|
+
const inbetween = Array.from({ length: depth - 2 }).map((_, index) => /* @__PURE__ */ jsx8(MiddleArrow, {}, index));
|
|
1259
|
+
return /* @__PURE__ */ jsxs8("div", { className: "flex flex-col items-end", children: [
|
|
1260
|
+
/* @__PURE__ */ jsx8(HorizontalArrow, {}),
|
|
1261
|
+
inbetween,
|
|
1262
|
+
/* @__PURE__ */ jsx8(EndArrow, {})
|
|
1263
|
+
] });
|
|
1264
|
+
};
|
|
1265
|
+
var Line = ({ next }) => {
|
|
1266
|
+
if (!next) {
|
|
1267
|
+
return null;
|
|
1268
|
+
}
|
|
1269
|
+
return /* @__PURE__ */ jsx8("div", { className: "-ml-[5px] -mr-[7px] w-[60px] pr-[7px]", children: /* @__PURE__ */ jsxs8("div", { className: "flex min-h-[24px] w-full items-start", children: [
|
|
1270
|
+
/* @__PURE__ */ jsx8("div", { className: "flex h-6 w-2.5 items-center justify-center", children: /* @__PURE__ */ jsx8("div", { className: "bg-ui-button-neutral shadow-borders-base size-2.5 shrink-0 rounded-full" }) }),
|
|
1271
|
+
/* @__PURE__ */ jsx8("div", { className: "pt-1.5", children: /* @__PURE__ */ jsx8(Arrow, { depth: next.length }) })
|
|
1272
|
+
] }) });
|
|
1273
|
+
};
|
|
1274
|
+
var Node = ({ step }) => {
|
|
1275
|
+
if (step.id === "_root") {
|
|
1276
|
+
return null;
|
|
1277
|
+
}
|
|
1278
|
+
const stepId = step.id.split(".").pop();
|
|
1279
|
+
const handleScrollTo = () => {
|
|
1280
|
+
if (!stepId) {
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
const historyItem = document.getElementById(stepId);
|
|
1284
|
+
if (!historyItem) {
|
|
1285
|
+
return;
|
|
1286
|
+
}
|
|
1287
|
+
setTimeout(() => {
|
|
1288
|
+
historyItem.scrollIntoView({
|
|
1289
|
+
behavior: "smooth",
|
|
1290
|
+
block: "end"
|
|
1291
|
+
});
|
|
1292
|
+
}, 100);
|
|
1293
|
+
};
|
|
1294
|
+
const isInvoking = step.invoke.state === "invoking" /* INVOKING */;
|
|
1295
|
+
return /* @__PURE__ */ jsx8(
|
|
1296
|
+
Link3,
|
|
1297
|
+
{
|
|
1298
|
+
to: `#${stepId}`,
|
|
1299
|
+
onClick: handleScrollTo,
|
|
1300
|
+
className: "focus-visible:shadow-borders-focus transition-fg rounded-md outline-none",
|
|
1301
|
+
children: /* @__PURE__ */ jsxs8(
|
|
1302
|
+
"div",
|
|
1303
|
+
{
|
|
1304
|
+
className: clx3(
|
|
1305
|
+
"bg-ui-bg-base shadow-borders-base flex min-w-[120px] items-center gap-x-0.5 rounded-md p-0.5",
|
|
1306
|
+
{ "animate-pulse": isInvoking }
|
|
1307
|
+
),
|
|
1308
|
+
"data-step-id": step.id,
|
|
1309
|
+
children: [
|
|
1310
|
+
/* @__PURE__ */ jsx8("div", { className: "flex size-5 items-center justify-center", children: /* @__PURE__ */ jsx8(
|
|
1311
|
+
"div",
|
|
1312
|
+
{
|
|
1313
|
+
className: clx3(
|
|
1314
|
+
"size-2 rounded-sm shadow-[inset_0_0_0_1px_rgba(0,0,0,0.12)]",
|
|
1315
|
+
{
|
|
1316
|
+
"bg-ui-tag-neutral-bg": STEP_SKIPPED_STATES.includes(
|
|
1317
|
+
step.invoke.state
|
|
1318
|
+
),
|
|
1319
|
+
"bg-ui-tag-green-icon": STEP_OK_STATES.includes(
|
|
1320
|
+
step.invoke.state
|
|
1321
|
+
),
|
|
1322
|
+
"bg-ui-tag-orange-icon": STEP_IN_PROGRESS_STATES.includes(
|
|
1323
|
+
step.invoke.state
|
|
1324
|
+
),
|
|
1325
|
+
"bg-ui-tag-red-icon": STEP_ERROR_STATES.includes(
|
|
1326
|
+
step.invoke.state
|
|
1327
|
+
),
|
|
1328
|
+
"bg-ui-tag-neutral-icon": STEP_INACTIVE_STATES.includes(
|
|
1329
|
+
step.invoke.state
|
|
1330
|
+
)
|
|
1331
|
+
}
|
|
1332
|
+
)
|
|
1333
|
+
}
|
|
1334
|
+
) }),
|
|
1335
|
+
/* @__PURE__ */ jsx8(
|
|
1336
|
+
Text5,
|
|
1337
|
+
{
|
|
1338
|
+
size: "xsmall",
|
|
1339
|
+
leading: "compact",
|
|
1340
|
+
weight: "plus",
|
|
1341
|
+
className: "select-none",
|
|
1342
|
+
children: stepId
|
|
1343
|
+
}
|
|
1344
|
+
)
|
|
1345
|
+
]
|
|
1346
|
+
}
|
|
1347
|
+
)
|
|
1348
|
+
}
|
|
1349
|
+
);
|
|
1350
|
+
};
|
|
1351
|
+
|
|
1352
|
+
// src/routes/workflow-executions/workflow-execution-detail/workflow-detail.tsx
|
|
1353
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1354
|
+
var ExecutionDetail = () => {
|
|
1355
|
+
const { id } = useParams();
|
|
1356
|
+
const queryClient2 = useQueryClient();
|
|
1357
|
+
const { workflow_execution, isLoading, isError, error } = useWorkflowExecution(id);
|
|
1358
|
+
const { getWidgets } = useExtension();
|
|
1359
|
+
const isActive = workflow_execution ? TRANSACTION_ACTIVE_STATES.includes(
|
|
1360
|
+
workflow_execution.state
|
|
1361
|
+
) : false;
|
|
1362
|
+
useWorkflowSSE(workflow_execution?.workflow_id || "", {
|
|
1363
|
+
enabled: isActive && !!workflow_execution?.workflow_id,
|
|
1364
|
+
onEvent: (event) => {
|
|
1365
|
+
queryClient2.setQueryData(
|
|
1366
|
+
workflowExecutionsQueryKeys.detail(id),
|
|
1367
|
+
(current) => {
|
|
1368
|
+
if (!current) return current;
|
|
1369
|
+
return mergeStepEvent(current, event);
|
|
1370
|
+
}
|
|
1371
|
+
);
|
|
1372
|
+
if (event.event_type === "onFinish" || event.response?.state && isTerminalState(event.response.state)) {
|
|
1373
|
+
queryClient2.invalidateQueries({
|
|
1374
|
+
queryKey: workflowExecutionsQueryKeys.detail(id)
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
});
|
|
1379
|
+
if (isLoading || !workflow_execution) {
|
|
1380
|
+
return /* @__PURE__ */ jsx9(SingleColumnPageSkeleton, { sections: 4, showJSON: true });
|
|
1381
|
+
}
|
|
1382
|
+
if (isError) {
|
|
1383
|
+
throw error;
|
|
1384
|
+
}
|
|
1385
|
+
return /* @__PURE__ */ jsxs9(
|
|
1386
|
+
SingleColumnPage,
|
|
1387
|
+
{
|
|
1388
|
+
widgets: {
|
|
1389
|
+
after: getWidgets("workflow.details.after"),
|
|
1390
|
+
before: getWidgets("workflow.details.before")
|
|
1391
|
+
},
|
|
1392
|
+
data: workflow_execution,
|
|
1393
|
+
showJSON: true,
|
|
1394
|
+
hasOutlet: true,
|
|
1395
|
+
children: [
|
|
1396
|
+
/* @__PURE__ */ jsx9(WorkflowExecutionActionBar, { execution: workflow_execution }),
|
|
1397
|
+
/* @__PURE__ */ jsx9(WorkflowExecutionErrorCard, { execution: workflow_execution }),
|
|
1398
|
+
/* @__PURE__ */ jsx9(WorkflowExecutionWaitingBanner, { execution: workflow_execution }),
|
|
1399
|
+
/* @__PURE__ */ jsx9(WorkflowExecutionGeneralSection, { execution: workflow_execution }),
|
|
1400
|
+
/* @__PURE__ */ jsx9(WorkflowExecutionTimelineSection, { execution: workflow_execution }),
|
|
1401
|
+
/* @__PURE__ */ jsx9(WorkflowExecutionPayloadSection, { execution: workflow_execution }),
|
|
1402
|
+
/* @__PURE__ */ jsx9(WorkflowExecutionHistorySection, { execution: workflow_execution })
|
|
1403
|
+
]
|
|
1404
|
+
}
|
|
1405
|
+
);
|
|
1406
|
+
};
|
|
1407
|
+
export {
|
|
1408
|
+
WorkflowExecutionDetailBreadcrumb as Breadcrumb,
|
|
1409
|
+
ExecutionDetail as Component,
|
|
1410
|
+
workflowExecutionLoader as loader
|
|
1411
|
+
};
|