@acmekit/dashboard 2.13.35 → 2.13.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/{api-key-management-create-U37VC624.mjs → api-key-management-create-4AG76FJV.mjs} +3 -3
  2. package/dist/{api-key-management-detail-ZYKL4ATI.mjs → api-key-management-detail-T2TB4KST.mjs} +10 -10
  3. package/dist/{api-key-management-edit-TSZGMIBL.mjs → api-key-management-edit-R44OHS7B.mjs} +3 -3
  4. package/dist/{api-key-management-list-HCJFJWWB.mjs → api-key-management-list-QK4Q7Y5I.mjs} +3 -3
  5. package/dist/app.css +0 -31
  6. package/dist/app.js +1386 -3726
  7. package/dist/app.mjs +38 -240
  8. package/dist/{chunk-VEI6HW6L.mjs → chunk-2U3RK3JG.mjs} +5 -3
  9. package/dist/{chunk-FKTMBR44.mjs → chunk-DN3MIYQH.mjs} +1 -1
  10. package/dist/{chunk-7F3CWXUH.mjs → chunk-DQCEH3X2.mjs} +1 -1
  11. package/dist/{chunk-YKIWIMJX.mjs → chunk-DTY37DDZ.mjs} +0 -1
  12. package/dist/{chunk-PFZQYK7R.mjs → chunk-EFRMWHRX.mjs} +1 -1
  13. package/dist/{chunk-5IEHCYJO.mjs → chunk-GBFVWROS.mjs} +1 -1
  14. package/dist/chunk-LKWTBYYC.mjs +35 -0
  15. package/dist/chunk-RPAL6FHW.mjs +73 -0
  16. package/dist/{chunk-WLRJXEKL.mjs → chunk-ST2YB7JN.mjs} +1 -1
  17. package/dist/{chunk-XIP35KXF.mjs → chunk-ULSPL3DR.mjs} +1 -1
  18. package/dist/{chunk-SYACY6AL.mjs → chunk-XIM7X4FB.mjs} +1 -1
  19. package/dist/{chunk-HHPPTD3B.mjs → chunk-YRWSG3YM.mjs} +1 -1
  20. package/dist/en.json +3 -132
  21. package/dist/{invite-3JSNOA2B.mjs → invite-XGPZZBUP.mjs} +3 -3
  22. package/dist/{login-BEJ5EFGE.mjs → login-GNP3QIPI.mjs} +9 -9
  23. package/dist/{profile-detail-QVTJC4JC.mjs → profile-detail-YX27F7N6.mjs} +3 -3
  24. package/dist/{profile-edit-MIO62TWH.mjs → profile-edit-2VRDU75O.mjs} +3 -3
  25. package/dist/{reset-password-BN4KAJQL.mjs → reset-password-TWRNZO6Z.mjs} +2 -2
  26. package/dist/{settings-GH5IWXHE.mjs → settings-3XWLL5LG.mjs} +3 -3
  27. package/dist/{translation-list-JA22BUKN.mjs → translation-list-CCEQJNED.mjs} +10 -10
  28. package/dist/{translations-edit-STTMANVT.mjs → translations-edit-E57GVUFV.mjs} +11 -11
  29. package/dist/{user-detail-WCXBFRGS.mjs → user-detail-KUSRRVNX.mjs} +3 -3
  30. package/dist/{user-edit-XDVMJOS4.mjs → user-edit-HTN3ZGCL.mjs} +3 -3
  31. package/dist/{user-invite-73ZDSDFC.mjs → user-invite-E3FAAU3V.mjs} +3 -3
  32. package/dist/{user-list-MPJXE3CA.mjs → user-list-KNJ5S3IM.mjs} +5 -5
  33. package/dist/{user-metadata-ADNTL3LT.mjs → user-metadata-5GQK75DT.mjs} +10 -10
  34. package/dist/workflow-execution-detail-5O5VCXL3.mjs +870 -0
  35. package/dist/workflow-execution-list-DETG4MRT.mjs +347 -0
  36. package/package.json +9 -9
  37. package/src/components/layout/main-layout/main-layout.tsx +1 -28
  38. package/src/dashboard-app/routes/get-route.map.tsx +0 -71
  39. package/src/hooks/api/workflow-executions.tsx +1 -145
  40. package/src/i18n/translations/$schema.json +4 -534
  41. package/src/i18n/translations/en.json +3 -132
  42. package/src/routes/workflow-executions/constants.ts +0 -16
  43. package/src/routes/workflow-executions/utils.ts +14 -170
  44. package/src/routes/workflow-executions/workflow-execution-detail/breadcrumb.tsx +1 -7
  45. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-history-section/workflow-execution-history-section.tsx +6 -157
  46. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-payload-section/workflow-execution-payload-section.tsx +6 -122
  47. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-timeline-section/workflow-execution-timeline-section.tsx +1 -7
  48. package/src/routes/workflow-executions/workflow-execution-detail/workflow-detail.tsx +1 -46
  49. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/use-workflow-execution-table-columns.tsx +0 -7
  50. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/use-workflow-execution-table-filters.tsx +1 -7
  51. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/use-workflow-execution-table-query.tsx +2 -4
  52. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/workflow-execution-list-table.tsx +1 -17
  53. package/src/routes/workflow-executions/workflow-execution-list/workflow-execution-list.tsx +1 -1
  54. package/dist/chunk-A7ULKHDE.mjs +0 -126
  55. package/dist/chunk-GBPAZAJK.mjs +0 -34
  56. package/dist/chunk-LP6CPB7N.mjs +0 -213
  57. package/dist/workflow-analytics-4WCI4ODQ.mjs +0 -152
  58. package/dist/workflow-definition-detail-GI6CFBMG.mjs +0 -94
  59. package/dist/workflow-definition-list-GF3XAEPS.mjs +0 -142
  60. package/dist/workflow-execution-complete-step-WSRLO572.mjs +0 -245
  61. package/dist/workflow-execution-detail-3RH6EQSS.mjs +0 -1411
  62. package/dist/workflow-execution-list-AQEGAME4.mjs +0 -596
  63. package/dist/workflow-execution-rerun-WCYLYL3Q.mjs +0 -138
  64. package/dist/workflow-execution-run-MWN5KWNY.mjs +0 -135
  65. package/dist/workflow-scheduled-list-ZPXR7CZM.mjs +0 -174
  66. package/src/hooks/api/workflow-definitions.tsx +0 -79
  67. package/src/hooks/api/workflow-metrics.tsx +0 -48
  68. package/src/hooks/use-workflow-sse.tsx +0 -78
  69. package/src/routes/workflow-analytics/workflow-analytics.tsx +0 -167
  70. package/src/routes/workflow-definitions/workflow-definition-detail/workflow-definition-detail.tsx +0 -98
  71. package/src/routes/workflow-definitions/workflow-definition-list/components/workflow-definition-list-table/use-workflow-definition-table-columns.tsx +0 -78
  72. package/src/routes/workflow-definitions/workflow-definition-list/components/workflow-definition-list-table/workflow-definition-list-table.tsx +0 -65
  73. package/src/routes/workflow-definitions/workflow-definition-list/workflow-definition-list.tsx +0 -15
  74. package/src/routes/workflow-executions/workflow-execution-complete-step/workflow-execution-complete-step.tsx +0 -270
  75. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-action-bar/index.ts +0 -1
  76. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-action-bar/workflow-execution-action-bar.tsx +0 -212
  77. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-error-card/index.ts +0 -1
  78. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-error-card/workflow-execution-error-card.tsx +0 -59
  79. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-waiting-banner/index.ts +0 -1
  80. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-waiting-banner/workflow-execution-waiting-banner.tsx +0 -63
  81. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/workflow-execution-auto-refresh.tsx +0 -73
  82. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/workflow-execution-row-actions.tsx +0 -116
  83. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/workflow-execution-saved-views.tsx +0 -84
  84. package/src/routes/workflow-executions/workflow-execution-rerun/workflow-execution-rerun.tsx +0 -159
  85. package/src/routes/workflow-executions/workflow-execution-run/workflow-execution-run.tsx +0 -139
  86. package/src/routes/workflow-scheduled/workflow-scheduled-list.tsx +0 -269
  87. /package/dist/{chunk-RISX76YT.mjs → chunk-22YYMH6M.mjs} +0 -0
@@ -1,212 +0,0 @@
1
- import { ArrowPathMini, EllipsisHorizontal, XMark } from "@acmekit/icons"
2
- import { HttpTypes } from "@acmekit/types"
3
- import {
4
- Badge,
5
- Button,
6
- Container,
7
- Copy,
8
- StatusBadge,
9
- toast,
10
- usePrompt,
11
- } from "@acmekit/ui"
12
- import { useTranslation } from "react-i18next"
13
- import { Link } from "react-router-dom"
14
- import { ActionMenu } from "../../../../../components/common/action-menu"
15
- import {
16
- useCancelWorkflowExecution,
17
- useRunWorkflow,
18
- } from "../../../../../hooks/api/workflow-executions"
19
- import {
20
- TRANSACTION_ERROR_STATES,
21
- TRANSACTION_IN_PROGRESS_STATES,
22
- } from "../../../constants"
23
- import { TransactionState } from "../../../types"
24
- import {
25
- getTransactionState,
26
- getTransactionStateColor,
27
- getWaitingSteps,
28
- } from "../../../utils"
29
-
30
- type WorkflowExecutionActionBarProps = {
31
- execution: HttpTypes.AdminWorkflowExecution
32
- }
33
-
34
- export const WorkflowExecutionActionBar = ({
35
- execution,
36
- }: WorkflowExecutionActionBarProps) => {
37
- const { t } = useTranslation()
38
- const prompt = usePrompt()
39
-
40
- const state = execution.state as TransactionState
41
- const stateColor = getTransactionStateColor(state)
42
- const translatedState = getTransactionState(t, state)
43
-
44
- const workflowId = execution.workflow_id
45
- const transactionId = execution.transaction_id
46
-
47
- const isFailed = TRANSACTION_ERROR_STATES.includes(state)
48
- const isRunning = TRANSACTION_IN_PROGRESS_STATES.includes(state)
49
- const waitingSteps = getWaitingSteps(execution)
50
- const hasWaitingSteps = waitingSteps.length > 0
51
-
52
- const { mutateAsync: runAsync, isPending: isRunning_ } =
53
- useRunWorkflow(workflowId)
54
- const { mutateAsync: cancelAsync, isPending: isCancelling } =
55
- useCancelWorkflowExecution(workflowId, transactionId)
56
-
57
- const handleRetry = async () => {
58
- const payload = (execution as any)?.context?.data?.payload
59
- const input =
60
- payload && typeof payload === "object"
61
- ? (payload as Record<string, unknown>)
62
- : {}
63
- await runAsync(
64
- { input },
65
- {
66
- onSuccess: () => {
67
- toast.success(t("workflowExecutions.actions.retrySuccess"))
68
- },
69
- onError: (err) => {
70
- toast.error(err.message)
71
- },
72
- }
73
- )
74
- }
75
-
76
- const handleCancel = async () => {
77
- const res = await prompt({
78
- title: t("workflowExecutions.actions.cancelConfirmTitle"),
79
- description: t("workflowExecutions.actions.cancelConfirmDescription", {
80
- workflow_id: workflowId,
81
- }),
82
- confirmText: t("workflowExecutions.actions.cancel"),
83
- cancelText: t("actions.cancel"),
84
- })
85
-
86
- if (!res) return
87
-
88
- await cancelAsync(undefined, {
89
- onSuccess: () => {
90
- toast.success(t("workflowExecutions.actions.cancelSuccess"))
91
- },
92
- onError: (err) => {
93
- toast.error(err.message)
94
- },
95
- })
96
- }
97
-
98
- const handleExportJson = () => {
99
- const data = JSON.stringify(execution, null, 2)
100
- const blob = new Blob([data], { type: "application/json" })
101
- const url = URL.createObjectURL(blob)
102
- const a = document.createElement("a")
103
- a.href = url
104
- a.download = `workflow-${workflowId}-${execution.id}.json`
105
- a.click()
106
- URL.revokeObjectURL(url)
107
- }
108
-
109
- const handleExportCsv = () => {
110
- const steps = execution?.execution?.steps || {}
111
- const rows = [["Step", "State", "Duration"]]
112
- for (const [stepId, step] of Object.entries(steps)) {
113
- if (stepId === "_root") continue
114
- const invokeState = (step as any)?.invoke?.state || "unknown"
115
- rows.push([stepId, invokeState, ""])
116
- }
117
- const csv = rows.map((r) => r.join(",")).join("\n")
118
- const blob = new Blob([csv], { type: "text/csv" })
119
- const url = URL.createObjectURL(blob)
120
- const a = document.createElement("a")
121
- a.href = url
122
- a.download = `workflow-${workflowId}-${execution.id}.csv`
123
- a.click()
124
- URL.revokeObjectURL(url)
125
- }
126
-
127
- const cleanId = execution.id.replace("wf_exec_", "")
128
-
129
- return (
130
- <Container className="sticky top-14 z-10 p-0">
131
- <div className="flex items-center justify-between px-6 py-3">
132
- <div className="flex items-center gap-x-3">
133
- <Copy content={workflowId} asChild>
134
- <Badge size="2xsmall" className="cursor-pointer">
135
- {workflowId}
136
- </Badge>
137
- </Copy>
138
- <StatusBadge color={stateColor}>{translatedState}</StatusBadge>
139
- <Copy content={execution.id} asChild>
140
- <Badge
141
- size="2xsmall"
142
- color="grey"
143
- className="cursor-pointer text-ui-fg-muted"
144
- >
145
- {cleanId}
146
- </Badge>
147
- </Copy>
148
- </div>
149
- <div className="flex items-center gap-x-2">
150
- {isFailed && (
151
- <Button
152
- variant="secondary"
153
- size="small"
154
- onClick={handleRetry}
155
- isLoading={isRunning_}
156
- >
157
- <ArrowPathMini className="mr-1" />
158
- {t("workflowExecutions.actions.retry")}
159
- </Button>
160
- )}
161
- {isRunning && (
162
- <Button
163
- variant="danger"
164
- size="small"
165
- onClick={handleCancel}
166
- isLoading={isCancelling}
167
- >
168
- <XMark className="mr-1" />
169
- {t("workflowExecutions.actions.cancel")}
170
- </Button>
171
- )}
172
- {hasWaitingSteps && (
173
- <Button variant="secondary" size="small" asChild>
174
- <Link to="complete-step">
175
- {t("workflowExecutions.actions.completeStep")}
176
- </Link>
177
- </Button>
178
- )}
179
- <ActionMenu
180
- groups={[
181
- {
182
- actions: [
183
- ...(isFailed
184
- ? [
185
- {
186
- label: t(
187
- "workflowExecutions.actions.retryWithNewInput"
188
- ),
189
- icon: <ArrowPathMini />,
190
- to: "rerun",
191
- },
192
- ]
193
- : []),
194
- {
195
- label: t("workflowExecutions.actions.exportJson"),
196
- icon: <EllipsisHorizontal />,
197
- onClick: handleExportJson,
198
- },
199
- {
200
- label: t("workflowExecutions.actions.exportCsv"),
201
- icon: <EllipsisHorizontal />,
202
- onClick: handleExportCsv,
203
- },
204
- ],
205
- },
206
- ]}
207
- />
208
- </div>
209
- </div>
210
- </Container>
211
- )
212
- }
@@ -1 +0,0 @@
1
- export { WorkflowExecutionErrorCard } from "./workflow-execution-error-card"
@@ -1,59 +0,0 @@
1
- import { XCircle } from "@acmekit/icons"
2
- import { HttpTypes } from "@acmekit/types"
3
- import { Container, Heading, Text } from "@acmekit/ui"
4
- import { useTranslation } from "react-i18next"
5
- import { TransactionState } from "../../../types"
6
- import { getFailedSteps } from "../../../utils"
7
-
8
- type WorkflowExecutionErrorCardProps = {
9
- execution: HttpTypes.AdminWorkflowExecution
10
- }
11
-
12
- export const WorkflowExecutionErrorCard = ({
13
- execution,
14
- }: WorkflowExecutionErrorCardProps) => {
15
- const { t } = useTranslation()
16
-
17
- if ((execution.state as TransactionState) !== TransactionState.FAILED) {
18
- return null
19
- }
20
-
21
- const failedSteps = getFailedSteps(execution)
22
- if (failedSteps.length === 0) return null
23
-
24
- const firstFailure = failedSteps[0]
25
- const errorMessage =
26
- firstFailure.error?.error?.message ||
27
- firstFailure.error?.error ||
28
- "Unknown error"
29
- const handlerType = firstFailure.error?.handlerType || "invoke"
30
-
31
- return (
32
- <Container className="border border-ui-tag-red-border bg-ui-tag-red-bg p-0">
33
- <div className="flex items-start gap-x-3 px-6 py-4">
34
- <div className="mt-0.5">
35
- <XCircle className="text-ui-tag-red-icon" />
36
- </div>
37
- <div className="flex flex-1 flex-col gap-y-1">
38
- <Heading level="h3">
39
- {t("workflowExecutions.error.failureAtStep", {
40
- step: firstFailure.stepId,
41
- })}
42
- </Heading>
43
- <Text size="small" className="text-ui-fg-subtle">
44
- {String(errorMessage)}
45
- </Text>
46
- <Text size="xsmall" className="text-ui-fg-muted">
47
- {handlerType === "compensate" ? "Compensation" : "Invoke"} failure
48
- </Text>
49
- </div>
50
- <a
51
- href={`#${firstFailure.stepId}`}
52
- className="text-ui-fg-interactive txt-compact-small-plus shrink-0 hover:underline"
53
- >
54
- {t("workflowExecutions.error.jumpToStep")}
55
- </a>
56
- </div>
57
- </Container>
58
- )
59
- }
@@ -1 +0,0 @@
1
- export { WorkflowExecutionWaitingBanner } from "./workflow-execution-waiting-banner"
@@ -1,63 +0,0 @@
1
- import { ClockSolidMini } from "@acmekit/icons"
2
- import { HttpTypes } from "@acmekit/types"
3
- import { Container, Copy, Heading, Text } from "@acmekit/ui"
4
- import { useTranslation } from "react-i18next"
5
- import { Link } from "react-router-dom"
6
- import { computeIdempotencyKey, getWaitingSteps } from "../../../utils"
7
-
8
- type WorkflowExecutionWaitingBannerProps = {
9
- execution: HttpTypes.AdminWorkflowExecution
10
- }
11
-
12
- export const WorkflowExecutionWaitingBanner = ({
13
- execution,
14
- }: WorkflowExecutionWaitingBannerProps) => {
15
- const { t } = useTranslation()
16
- const waitingSteps = getWaitingSteps(execution)
17
-
18
- if (waitingSteps.length === 0) return null
19
-
20
- const firstStep = waitingSteps[0]
21
- const idempotencyKey = computeIdempotencyKey(
22
- execution.workflow_id,
23
- execution.transaction_id,
24
- firstStep.stepId,
25
- "invoke"
26
- )
27
-
28
- return (
29
- <Container className="border border-ui-tag-purple-border bg-ui-tag-purple-bg p-0">
30
- <div className="flex items-start gap-x-3 px-6 py-4">
31
- <div className="mt-0.5">
32
- <ClockSolidMini className="text-ui-tag-purple-icon" />
33
- </div>
34
- <div className="flex flex-1 flex-col gap-y-1">
35
- <Heading level="h3">
36
- {t("workflowExecutions.asyncStep.waitingBanner")}
37
- </Heading>
38
- <Text size="small" className="text-ui-fg-subtle">
39
- {t("workflowExecutions.asyncStep.waitingDescription", {
40
- step: firstStep.stepId,
41
- })}
42
- </Text>
43
- <div className="mt-1 flex items-center gap-x-2">
44
- <Text size="xsmall" className="text-ui-fg-muted">
45
- {t("workflowExecutions.asyncStep.idempotencyKey")}:
46
- </Text>
47
- <Copy content={idempotencyKey} asChild>
48
- <code className="bg-ui-bg-base txt-compact-xsmall cursor-pointer rounded px-1.5 py-0.5">
49
- {idempotencyKey}
50
- </code>
51
- </Copy>
52
- </div>
53
- </div>
54
- <Link
55
- to="complete-step"
56
- className="text-ui-fg-interactive txt-compact-small-plus shrink-0 hover:underline"
57
- >
58
- {t("workflowExecutions.actions.completeStep")}
59
- </Link>
60
- </div>
61
- </Container>
62
- )
63
- }
@@ -1,73 +0,0 @@
1
- import { ArrowPathMini } from "@acmekit/icons"
2
- import { DropdownMenu, IconButton } from "@acmekit/ui"
3
- import { useQueryClient } from "@tanstack/react-query"
4
- import { useCallback, useEffect, useRef, useState } from "react"
5
- import { workflowExecutionsQueryKeys } from "../../../../../hooks/api/workflow-executions"
6
-
7
- const INTERVALS = [
8
- { label: "Off", value: 0 },
9
- { label: "5s", value: 5000 },
10
- { label: "10s", value: 10000 },
11
- { label: "30s", value: 30000 },
12
- ]
13
-
14
- export const WorkflowExecutionAutoRefresh = () => {
15
- const queryClient = useQueryClient()
16
- const [interval, setInterval_] = useState(0)
17
- const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
18
-
19
- const refresh = useCallback(() => {
20
- queryClient.invalidateQueries({
21
- queryKey: workflowExecutionsQueryKeys.lists(),
22
- })
23
- }, [queryClient])
24
-
25
- useEffect(() => {
26
- if (intervalRef.current) {
27
- clearInterval(intervalRef.current)
28
- intervalRef.current = null
29
- }
30
-
31
- if (interval > 0) {
32
- intervalRef.current = setInterval(refresh, interval)
33
- }
34
-
35
- return () => {
36
- if (intervalRef.current) {
37
- clearInterval(intervalRef.current)
38
- }
39
- }
40
- }, [interval, refresh])
41
-
42
- const activeLabel = INTERVALS.find((i) => i.value === interval)?.label
43
-
44
- return (
45
- <div className="flex items-center gap-x-1">
46
- <IconButton
47
- size="small"
48
- variant="transparent"
49
- onClick={refresh}
50
- >
51
- <ArrowPathMini />
52
- </IconButton>
53
- <DropdownMenu>
54
- <DropdownMenu.Trigger asChild>
55
- <button className="txt-compact-small text-ui-fg-muted hover:text-ui-fg-subtle rounded px-1.5 py-0.5 transition-colors">
56
- {activeLabel}
57
- </button>
58
- </DropdownMenu.Trigger>
59
- <DropdownMenu.Content align="end">
60
- {INTERVALS.map((opt) => (
61
- <DropdownMenu.Item
62
- key={opt.value}
63
- onClick={() => setInterval_(opt.value)}
64
- className={interval === opt.value ? "font-medium" : ""}
65
- >
66
- {opt.label}
67
- </DropdownMenu.Item>
68
- ))}
69
- </DropdownMenu.Content>
70
- </DropdownMenu>
71
- </div>
72
- )
73
- }
@@ -1,116 +0,0 @@
1
- import { ArrowPathMini, Eye, XMark } from "@acmekit/icons"
2
- import { HttpTypes } from "@acmekit/types"
3
- import { toast, usePrompt } from "@acmekit/ui"
4
- import { useTranslation } from "react-i18next"
5
- import {
6
- Action,
7
- ActionMenu,
8
- } from "../../../../../components/common/action-menu"
9
- import {
10
- useCancelWorkflowExecution,
11
- useRunWorkflow,
12
- } from "../../../../../hooks/api/workflow-executions"
13
- import {
14
- TRANSACTION_ERROR_STATES,
15
- TRANSACTION_IN_PROGRESS_STATES,
16
- } from "../../../constants"
17
- import { TransactionState } from "../../../types"
18
-
19
- type WorkflowExecutionRowActionsProps = {
20
- execution: HttpTypes.AdminWorkflowExecutionResponse["workflow_execution"]
21
- }
22
-
23
- export const WorkflowExecutionRowActions = ({
24
- execution,
25
- }: WorkflowExecutionRowActionsProps) => {
26
- const { t } = useTranslation()
27
- const prompt = usePrompt()
28
-
29
- const state = execution.state as TransactionState
30
- const isFailed = TRANSACTION_ERROR_STATES.includes(state)
31
- const isRunning = TRANSACTION_IN_PROGRESS_STATES.includes(state)
32
-
33
- const workflowId = execution.workflow_id
34
- const transactionId = execution.transaction_id
35
-
36
- const { mutateAsync: runAsync } = useRunWorkflow(workflowId)
37
- const { mutateAsync: cancelAsync } = useCancelWorkflowExecution(
38
- workflowId,
39
- transactionId
40
- )
41
-
42
- const handleRetry = async () => {
43
- const payload = (execution as any)?.context?.data?.payload
44
- const input =
45
- payload && typeof payload === "object"
46
- ? (payload as Record<string, unknown>)
47
- : {}
48
- await runAsync(
49
- { input },
50
- {
51
- onSuccess: () => {
52
- toast.success(t("workflowExecutions.actions.retrySuccess"))
53
- },
54
- onError: (err) => {
55
- toast.error(err.message)
56
- },
57
- }
58
- )
59
- }
60
-
61
- const handleCancel = async () => {
62
- const res = await prompt({
63
- title: t("workflowExecutions.actions.cancelConfirmTitle"),
64
- description: t(
65
- "workflowExecutions.actions.cancelConfirmDescription",
66
- { workflow_id: workflowId }
67
- ),
68
- confirmText: t("workflowExecutions.actions.cancel"),
69
- cancelText: t("actions.cancel"),
70
- })
71
-
72
- if (!res) return
73
-
74
- await cancelAsync(undefined, {
75
- onSuccess: () => {
76
- toast.success(t("workflowExecutions.actions.cancelSuccess"))
77
- },
78
- onError: (err) => {
79
- toast.error(err.message)
80
- },
81
- })
82
- }
83
-
84
- const secondaryActions: Action[] = []
85
- if (isFailed) {
86
- secondaryActions.push({
87
- icon: <ArrowPathMini />,
88
- label: t("workflowExecutions.actions.retry"),
89
- onClick: handleRetry,
90
- })
91
- }
92
- if (isRunning) {
93
- secondaryActions.push({
94
- icon: <XMark />,
95
- label: t("workflowExecutions.actions.cancel"),
96
- onClick: handleCancel,
97
- })
98
- }
99
-
100
- const groups = [
101
- {
102
- actions: [
103
- {
104
- icon: <Eye />,
105
- label: t("workflowExecutions.actions.viewDetails"),
106
- to: `${execution.id}`,
107
- } as Action,
108
- ],
109
- },
110
- ...(secondaryActions.length > 0
111
- ? [{ actions: secondaryActions }]
112
- : []),
113
- ]
114
-
115
- return <ActionMenu groups={groups} />
116
- }
@@ -1,84 +0,0 @@
1
- import { Button, clx } from "@acmekit/ui"
2
- import { useCallback, useMemo } from "react"
3
- import { useTranslation } from "react-i18next"
4
- import { useSearchParams } from "react-router-dom"
5
-
6
- type SavedView = {
7
- label: string
8
- params: Record<string, string>
9
- }
10
-
11
- export const WorkflowExecutionSavedViews = () => {
12
- const { t } = useTranslation()
13
- const [searchParams, setSearchParams] = useSearchParams()
14
-
15
- const views: SavedView[] = useMemo(
16
- () => [
17
- {
18
- label: t("workflowExecutions.filters.allExecutions"),
19
- params: {} as Record<string, string>,
20
- },
21
- {
22
- label: t("workflowExecutions.filters.running"),
23
- params: { state: "invoking" } as Record<string, string>,
24
- },
25
- {
26
- label: t("workflowExecutions.filters.failedToday"),
27
- params: {
28
- state: "failed",
29
- created_at: JSON.stringify({
30
- $gte: new Date(
31
- new Date().setHours(0, 0, 0, 0)
32
- ).toISOString(),
33
- }),
34
- } as Record<string, string>,
35
- },
36
- ],
37
- [t]
38
- )
39
-
40
- const isActive = useCallback(
41
- (view: SavedView) => {
42
- const viewKeys = Object.keys(view.params)
43
- if (viewKeys.length === 0) {
44
- return !searchParams.has("state") && !searchParams.has("created_at")
45
- }
46
- return viewKeys.every(
47
- (key) => searchParams.get(key) === view.params[key]
48
- )
49
- },
50
- [searchParams]
51
- )
52
-
53
- const handleClick = useCallback(
54
- (view: SavedView) => {
55
- const newParams = new URLSearchParams()
56
- for (const [key, value] of Object.entries(view.params)) {
57
- newParams.set(key, value)
58
- }
59
- setSearchParams(newParams)
60
- },
61
- [setSearchParams]
62
- )
63
-
64
- return (
65
- <div className="flex items-center gap-x-1">
66
- {views.map((view) => (
67
- <Button
68
- key={view.label}
69
- variant="transparent"
70
- size="small"
71
- onClick={() => handleClick(view)}
72
- className={clx(
73
- "txt-compact-small-plus",
74
- isActive(view)
75
- ? "bg-ui-bg-base shadow-elevation-card-rest text-ui-fg-base"
76
- : "text-ui-fg-muted"
77
- )}
78
- >
79
- {view.label}
80
- </Button>
81
- ))}
82
- </div>
83
- )
84
- }