@acmekit/dashboard 2.13.33 → 2.13.35

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-4AG76FJV.mjs → api-key-management-create-U37VC624.mjs} +3 -3
  2. package/dist/{api-key-management-detail-T2TB4KST.mjs → api-key-management-detail-ZYKL4ATI.mjs} +10 -10
  3. package/dist/{api-key-management-edit-R44OHS7B.mjs → api-key-management-edit-TSZGMIBL.mjs} +3 -3
  4. package/dist/{api-key-management-list-QK4Q7Y5I.mjs → api-key-management-list-HCJFJWWB.mjs} +3 -3
  5. package/dist/app.css +31 -0
  6. package/dist/app.js +3726 -1386
  7. package/dist/app.mjs +240 -38
  8. package/dist/{chunk-GBFVWROS.mjs → chunk-5IEHCYJO.mjs} +1 -1
  9. package/dist/{chunk-DQCEH3X2.mjs → chunk-7F3CWXUH.mjs} +1 -1
  10. package/dist/chunk-A7ULKHDE.mjs +126 -0
  11. package/dist/{chunk-DN3MIYQH.mjs → chunk-FKTMBR44.mjs} +1 -1
  12. package/dist/chunk-GBPAZAJK.mjs +34 -0
  13. package/dist/{chunk-YRWSG3YM.mjs → chunk-HHPPTD3B.mjs} +1 -1
  14. package/dist/chunk-LP6CPB7N.mjs +213 -0
  15. package/dist/{chunk-EFRMWHRX.mjs → chunk-PFZQYK7R.mjs} +1 -1
  16. package/dist/{chunk-XIM7X4FB.mjs → chunk-SYACY6AL.mjs} +1 -1
  17. package/dist/{chunk-2U3RK3JG.mjs → chunk-VEI6HW6L.mjs} +3 -5
  18. package/dist/{chunk-ST2YB7JN.mjs → chunk-WLRJXEKL.mjs} +1 -1
  19. package/dist/{chunk-ULSPL3DR.mjs → chunk-XIP35KXF.mjs} +1 -1
  20. package/dist/{chunk-DTY37DDZ.mjs → chunk-YKIWIMJX.mjs} +1 -0
  21. package/dist/en.json +132 -3
  22. package/dist/{invite-XGPZZBUP.mjs → invite-3JSNOA2B.mjs} +3 -3
  23. package/dist/{login-GNP3QIPI.mjs → login-BEJ5EFGE.mjs} +9 -9
  24. package/dist/{profile-detail-YX27F7N6.mjs → profile-detail-QVTJC4JC.mjs} +3 -3
  25. package/dist/{profile-edit-2VRDU75O.mjs → profile-edit-MIO62TWH.mjs} +3 -3
  26. package/dist/{reset-password-TWRNZO6Z.mjs → reset-password-BN4KAJQL.mjs} +2 -2
  27. package/dist/{settings-3XWLL5LG.mjs → settings-GH5IWXHE.mjs} +3 -3
  28. package/dist/{translation-list-CCEQJNED.mjs → translation-list-JA22BUKN.mjs} +10 -10
  29. package/dist/{translations-edit-E57GVUFV.mjs → translations-edit-STTMANVT.mjs} +11 -11
  30. package/dist/{user-detail-KUSRRVNX.mjs → user-detail-WCXBFRGS.mjs} +3 -3
  31. package/dist/{user-edit-HTN3ZGCL.mjs → user-edit-XDVMJOS4.mjs} +3 -3
  32. package/dist/{user-invite-E3FAAU3V.mjs → user-invite-73ZDSDFC.mjs} +3 -3
  33. package/dist/{user-list-KNJ5S3IM.mjs → user-list-MPJXE3CA.mjs} +5 -5
  34. package/dist/{user-metadata-5GQK75DT.mjs → user-metadata-ADNTL3LT.mjs} +10 -10
  35. package/dist/workflow-analytics-4WCI4ODQ.mjs +152 -0
  36. package/dist/workflow-definition-detail-GI6CFBMG.mjs +94 -0
  37. package/dist/workflow-definition-list-GF3XAEPS.mjs +142 -0
  38. package/dist/workflow-execution-complete-step-WSRLO572.mjs +245 -0
  39. package/dist/workflow-execution-detail-3RH6EQSS.mjs +1411 -0
  40. package/dist/workflow-execution-list-AQEGAME4.mjs +596 -0
  41. package/dist/workflow-execution-rerun-WCYLYL3Q.mjs +138 -0
  42. package/dist/workflow-execution-run-MWN5KWNY.mjs +135 -0
  43. package/dist/workflow-scheduled-list-ZPXR7CZM.mjs +174 -0
  44. package/package.json +9 -9
  45. package/src/components/layout/main-layout/main-layout.tsx +28 -1
  46. package/src/dashboard-app/routes/get-route.map.tsx +71 -0
  47. package/src/hooks/api/workflow-definitions.tsx +79 -0
  48. package/src/hooks/api/workflow-executions.tsx +145 -1
  49. package/src/hooks/api/workflow-metrics.tsx +48 -0
  50. package/src/hooks/use-workflow-sse.tsx +78 -0
  51. package/src/i18n/translations/$schema.json +534 -4
  52. package/src/i18n/translations/en.json +132 -3
  53. package/src/routes/workflow-analytics/workflow-analytics.tsx +167 -0
  54. package/src/routes/workflow-definitions/workflow-definition-detail/workflow-definition-detail.tsx +98 -0
  55. package/src/routes/workflow-definitions/workflow-definition-list/components/workflow-definition-list-table/use-workflow-definition-table-columns.tsx +78 -0
  56. package/src/routes/workflow-definitions/workflow-definition-list/components/workflow-definition-list-table/workflow-definition-list-table.tsx +65 -0
  57. package/src/routes/workflow-definitions/workflow-definition-list/workflow-definition-list.tsx +15 -0
  58. package/src/routes/workflow-executions/constants.ts +16 -0
  59. package/src/routes/workflow-executions/utils.ts +170 -14
  60. package/src/routes/workflow-executions/workflow-execution-complete-step/workflow-execution-complete-step.tsx +270 -0
  61. package/src/routes/workflow-executions/workflow-execution-detail/breadcrumb.tsx +7 -1
  62. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-action-bar/index.ts +1 -0
  63. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-action-bar/workflow-execution-action-bar.tsx +212 -0
  64. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-error-card/index.ts +1 -0
  65. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-error-card/workflow-execution-error-card.tsx +59 -0
  66. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-history-section/workflow-execution-history-section.tsx +157 -6
  67. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-payload-section/workflow-execution-payload-section.tsx +122 -6
  68. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-timeline-section/workflow-execution-timeline-section.tsx +7 -1
  69. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-waiting-banner/index.ts +1 -0
  70. package/src/routes/workflow-executions/workflow-execution-detail/components/workflow-execution-waiting-banner/workflow-execution-waiting-banner.tsx +63 -0
  71. package/src/routes/workflow-executions/workflow-execution-detail/workflow-detail.tsx +46 -1
  72. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/use-workflow-execution-table-columns.tsx +7 -0
  73. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/use-workflow-execution-table-filters.tsx +7 -1
  74. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/use-workflow-execution-table-query.tsx +4 -2
  75. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/workflow-execution-auto-refresh.tsx +73 -0
  76. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/workflow-execution-list-table.tsx +17 -1
  77. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/workflow-execution-row-actions.tsx +116 -0
  78. package/src/routes/workflow-executions/workflow-execution-list/components/workflow-execution-list-table/workflow-execution-saved-views.tsx +84 -0
  79. package/src/routes/workflow-executions/workflow-execution-list/workflow-execution-list.tsx +1 -1
  80. package/src/routes/workflow-executions/workflow-execution-rerun/workflow-execution-rerun.tsx +159 -0
  81. package/src/routes/workflow-executions/workflow-execution-run/workflow-execution-run.tsx +139 -0
  82. package/src/routes/workflow-scheduled/workflow-scheduled-list.tsx +269 -0
  83. package/dist/chunk-LKWTBYYC.mjs +0 -35
  84. package/dist/chunk-RPAL6FHW.mjs +0 -73
  85. package/dist/workflow-execution-detail-5O5VCXL3.mjs +0 -870
  86. package/dist/workflow-execution-list-DETG4MRT.mjs +0 -347
  87. /package/dist/{chunk-22YYMH6M.mjs → chunk-RISX76YT.mjs} +0 -0
@@ -0,0 +1,138 @@
1
+ import {
2
+ useRunWorkflow,
3
+ useWorkflowExecution
4
+ } from "./chunk-A7ULKHDE.mjs";
5
+ import "./chunk-IUCDCPJU.mjs";
6
+ import {
7
+ KeyboundForm,
8
+ RouteDrawer,
9
+ useRouteModal
10
+ } from "./chunk-VEI6HW6L.mjs";
11
+ import {
12
+ Form
13
+ } from "./chunk-ND3ODI36.mjs";
14
+ import "./chunk-FXYH54JP.mjs";
15
+ import "./chunk-774WSTCC.mjs";
16
+ import "./chunk-YKIWIMJX.mjs";
17
+ import "./chunk-QZ7TP4HQ.mjs";
18
+
19
+ // src/routes/workflow-executions/workflow-execution-rerun/workflow-execution-rerun.tsx
20
+ import { zodResolver } from "@hookform/resolvers/zod";
21
+ import { Button, Heading, Textarea, toast } from "@acmekit/ui";
22
+ import { useForm } from "react-hook-form";
23
+ import { useTranslation } from "react-i18next";
24
+ import { useParams } from "react-router-dom";
25
+ import * as zod from "zod";
26
+ import { jsx, jsxs } from "react/jsx-runtime";
27
+ var RerunSchema = zod.object({
28
+ input: zod.string().refine(
29
+ (val) => {
30
+ try {
31
+ JSON.parse(val);
32
+ return true;
33
+ } catch {
34
+ return false;
35
+ }
36
+ },
37
+ { message: "Must be valid JSON" }
38
+ )
39
+ });
40
+ var WorkflowExecutionRerun = () => {
41
+ const { t } = useTranslation();
42
+ const { id } = useParams();
43
+ const { handleSuccess } = useRouteModal();
44
+ const {
45
+ workflow_execution,
46
+ isPending: isLoading,
47
+ isError,
48
+ error
49
+ } = useWorkflowExecution(id);
50
+ if (isError) {
51
+ throw error;
52
+ }
53
+ if (isLoading || !workflow_execution) {
54
+ return /* @__PURE__ */ jsx(RouteDrawer, { children: /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(Heading, { children: t("workflowExecutions.rerun.title") }) }) });
55
+ }
56
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
57
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(Heading, { children: t("workflowExecutions.rerun.title") }) }),
58
+ /* @__PURE__ */ jsx(
59
+ RerunForm,
60
+ {
61
+ workflowId: workflow_execution.workflow_id,
62
+ defaultInput: workflow_execution?.context?.data?.payload || {},
63
+ onSuccess: handleSuccess
64
+ }
65
+ )
66
+ ] });
67
+ };
68
+ var RerunForm = ({
69
+ workflowId,
70
+ defaultInput,
71
+ onSuccess
72
+ }) => {
73
+ const { t } = useTranslation();
74
+ const form = useForm({
75
+ defaultValues: {
76
+ input: JSON.stringify(defaultInput, null, 2)
77
+ },
78
+ resolver: zodResolver(RerunSchema)
79
+ });
80
+ const { mutateAsync, isPending } = useRunWorkflow(workflowId);
81
+ const handleSubmit = form.handleSubmit(async (values) => {
82
+ const parsed = JSON.parse(values.input);
83
+ await mutateAsync(
84
+ { input: parsed },
85
+ {
86
+ onSuccess: () => {
87
+ toast.success(t("workflowExecutions.rerun.success"));
88
+ onSuccess();
89
+ },
90
+ onError: (err) => {
91
+ toast.error(err.message);
92
+ }
93
+ }
94
+ );
95
+ });
96
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
97
+ KeyboundForm,
98
+ {
99
+ onSubmit: handleSubmit,
100
+ className: "flex flex-1 flex-col overflow-hidden",
101
+ children: [
102
+ /* @__PURE__ */ jsxs(RouteDrawer.Body, { className: "flex max-w-full flex-1 flex-col gap-y-4 overflow-y-auto", children: [
103
+ /* @__PURE__ */ jsx("div", { className: "bg-ui-bg-field border-ui-border-base rounded-lg border px-3 py-2", children: /* @__PURE__ */ jsx("span", { className: "txt-compact-small text-ui-fg-muted", children: workflowId }) }),
104
+ /* @__PURE__ */ jsx(
105
+ Form.Field,
106
+ {
107
+ control: form.control,
108
+ name: "input",
109
+ render: ({ field }) => {
110
+ return /* @__PURE__ */ jsxs(Form.Item, { children: [
111
+ /* @__PURE__ */ jsx(Form.Label, { children: t("workflowExecutions.rerun.inputLabel") }),
112
+ /* @__PURE__ */ jsx(Form.Control, { children: /* @__PURE__ */ jsx(
113
+ Textarea,
114
+ {
115
+ ...field,
116
+ className: "font-mono text-xs",
117
+ rows: 16
118
+ }
119
+ ) }),
120
+ /* @__PURE__ */ jsx(Form.ErrorMessage, {})
121
+ ] });
122
+ }
123
+ }
124
+ )
125
+ ] }),
126
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
127
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: t("actions.cancel") }) }),
128
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: t("workflowExecutions.rerun.submit") })
129
+ ] }) })
130
+ ]
131
+ }
132
+ ) });
133
+ };
134
+ var Component = WorkflowExecutionRerun;
135
+ export {
136
+ Component,
137
+ WorkflowExecutionRerun
138
+ };
@@ -0,0 +1,135 @@
1
+ import {
2
+ useRunWorkflow
3
+ } from "./chunk-A7ULKHDE.mjs";
4
+ import "./chunk-IUCDCPJU.mjs";
5
+ import {
6
+ KeyboundForm,
7
+ RouteDrawer,
8
+ useRouteModal
9
+ } from "./chunk-VEI6HW6L.mjs";
10
+ import {
11
+ Form
12
+ } from "./chunk-ND3ODI36.mjs";
13
+ import "./chunk-FXYH54JP.mjs";
14
+ import "./chunk-774WSTCC.mjs";
15
+ import "./chunk-YKIWIMJX.mjs";
16
+ import "./chunk-QZ7TP4HQ.mjs";
17
+
18
+ // src/routes/workflow-executions/workflow-execution-run/workflow-execution-run.tsx
19
+ import { zodResolver } from "@hookform/resolvers/zod";
20
+ import { Button, Heading, Input, Textarea, toast } from "@acmekit/ui";
21
+ import { useForm } from "react-hook-form";
22
+ import { useTranslation } from "react-i18next";
23
+ import * as zod from "zod";
24
+ import { jsx, jsxs } from "react/jsx-runtime";
25
+ var RunWorkflowSchema = zod.object({
26
+ workflow_id: zod.string().min(1, "Workflow ID is required"),
27
+ input: zod.string().refine(
28
+ (val) => {
29
+ if (!val.trim()) return true;
30
+ try {
31
+ JSON.parse(val);
32
+ return true;
33
+ } catch {
34
+ return false;
35
+ }
36
+ },
37
+ { message: "Must be valid JSON" }
38
+ )
39
+ });
40
+ var WorkflowExecutionRun = () => {
41
+ const { t } = useTranslation();
42
+ const { handleSuccess } = useRouteModal();
43
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
44
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(Heading, { children: t("workflowExecutions.actions.runWorkflow") }) }),
45
+ /* @__PURE__ */ jsx(RunWorkflowForm, { onSuccess: handleSuccess })
46
+ ] });
47
+ };
48
+ var RunWorkflowForm = ({ onSuccess }) => {
49
+ const { t } = useTranslation();
50
+ const form = useForm({
51
+ defaultValues: {
52
+ workflow_id: "",
53
+ input: "{}"
54
+ },
55
+ resolver: zodResolver(RunWorkflowSchema)
56
+ });
57
+ const workflowId = form.watch("workflow_id");
58
+ const { mutateAsync, isPending } = useRunWorkflow(workflowId || "_placeholder");
59
+ const handleSubmit = form.handleSubmit(async (values) => {
60
+ const parsed = values.input.trim() ? JSON.parse(values.input) : {};
61
+ await mutateAsync(
62
+ { input: parsed },
63
+ {
64
+ onSuccess: () => {
65
+ toast.success(t("workflowExecutions.rerun.success"));
66
+ onSuccess();
67
+ },
68
+ onError: (err) => {
69
+ toast.error(err.message);
70
+ }
71
+ }
72
+ );
73
+ });
74
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
75
+ KeyboundForm,
76
+ {
77
+ onSubmit: handleSubmit,
78
+ className: "flex flex-1 flex-col overflow-hidden",
79
+ children: [
80
+ /* @__PURE__ */ jsxs(RouteDrawer.Body, { className: "flex max-w-full flex-1 flex-col gap-y-4 overflow-y-auto", children: [
81
+ /* @__PURE__ */ jsx(
82
+ Form.Field,
83
+ {
84
+ control: form.control,
85
+ name: "workflow_id",
86
+ render: ({ field }) => {
87
+ return /* @__PURE__ */ jsxs(Form.Item, { children: [
88
+ /* @__PURE__ */ jsx(Form.Label, { children: t("workflowExecutions.workflowIdLabel") }),
89
+ /* @__PURE__ */ jsx(Form.Control, { children: /* @__PURE__ */ jsx(
90
+ Input,
91
+ {
92
+ ...field,
93
+ placeholder: "my-workflow-id"
94
+ }
95
+ ) }),
96
+ /* @__PURE__ */ jsx(Form.ErrorMessage, {})
97
+ ] });
98
+ }
99
+ }
100
+ ),
101
+ /* @__PURE__ */ jsx(
102
+ Form.Field,
103
+ {
104
+ control: form.control,
105
+ name: "input",
106
+ render: ({ field }) => {
107
+ return /* @__PURE__ */ jsxs(Form.Item, { children: [
108
+ /* @__PURE__ */ jsx(Form.Label, { children: t("workflowExecutions.rerun.inputLabel") }),
109
+ /* @__PURE__ */ jsx(Form.Control, { children: /* @__PURE__ */ jsx(
110
+ Textarea,
111
+ {
112
+ ...field,
113
+ className: "font-mono text-xs",
114
+ rows: 12
115
+ }
116
+ ) }),
117
+ /* @__PURE__ */ jsx(Form.ErrorMessage, {})
118
+ ] });
119
+ }
120
+ }
121
+ )
122
+ ] }),
123
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
124
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: t("actions.cancel") }) }),
125
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: t("workflowExecutions.rerun.submit") })
126
+ ] }) })
127
+ ]
128
+ }
129
+ ) });
130
+ };
131
+ var Component = WorkflowExecutionRun;
132
+ export {
133
+ Component,
134
+ WorkflowExecutionRun
135
+ };
@@ -0,0 +1,174 @@
1
+ import {
2
+ useWorkflowDefinitions
3
+ } from "./chunk-GBPAZAJK.mjs";
4
+ import {
5
+ SingleColumnPage
6
+ } from "./chunk-RISX76YT.mjs";
7
+ import {
8
+ useRunWorkflow
9
+ } from "./chunk-A7ULKHDE.mjs";
10
+ import "./chunk-FXYH54JP.mjs";
11
+ import "./chunk-774WSTCC.mjs";
12
+ import "./chunk-YKIWIMJX.mjs";
13
+ import "./chunk-QZ7TP4HQ.mjs";
14
+
15
+ // src/routes/workflow-scheduled/workflow-scheduled-list.tsx
16
+ import { Badge, Button, Container, Heading, Text, toast } from "@acmekit/ui";
17
+ import { keepPreviousData } from "@tanstack/react-query";
18
+ import { formatDistanceToNow } from "date-fns";
19
+ import { useTranslation } from "react-i18next";
20
+ import { jsx, jsxs } from "react/jsx-runtime";
21
+ function describeCron(cron) {
22
+ const parts = cron.trim().split(/\s+/);
23
+ if (parts.length < 5) return cron;
24
+ const [minute, hour, dom, month, dow] = parts;
25
+ if (minute === "*" && hour === "*" && dom === "*" && month === "*" && dow === "*") {
26
+ return "Every minute";
27
+ }
28
+ if (minute !== "*" && hour === "*" && dom === "*" && month === "*" && dow === "*") {
29
+ return `Every hour at minute ${minute}`;
30
+ }
31
+ if (minute !== "*" && hour !== "*" && dom === "*" && month === "*" && dow === "*") {
32
+ const h = parseInt(hour, 10);
33
+ const m = parseInt(minute, 10);
34
+ const ampm = h >= 12 ? "PM" : "AM";
35
+ const h12 = h % 12 || 12;
36
+ return `Daily at ${h12}:${String(m).padStart(2, "0")} ${ampm}`;
37
+ }
38
+ if (minute !== "*" && hour !== "*" && dom === "*" && month === "*" && dow !== "*") {
39
+ const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
40
+ const dayNames = dow.split(",").map((d) => days[parseInt(d, 10)] ?? d).join(", ");
41
+ const h = parseInt(hour, 10);
42
+ const m = parseInt(minute, 10);
43
+ const ampm = h >= 12 ? "PM" : "AM";
44
+ const h12 = h % 12 || 12;
45
+ return `${dayNames} at ${h12}:${String(m).padStart(2, "0")} ${ampm}`;
46
+ }
47
+ if (minute !== "*" && hour !== "*" && dom !== "*" && month === "*" && dow === "*") {
48
+ return `Monthly on day ${dom} at ${hour}:${String(parseInt(minute, 10)).padStart(2, "0")}`;
49
+ }
50
+ return cron;
51
+ }
52
+ function getNextRunLabel(cron) {
53
+ try {
54
+ const parts = cron.trim().split(/\s+/);
55
+ if (parts.length < 5) return "Unknown";
56
+ const [minuteStr, hourStr] = parts;
57
+ const now = /* @__PURE__ */ new Date();
58
+ const next = new Date(now);
59
+ if (minuteStr === "*") {
60
+ next.setSeconds(0, 0);
61
+ next.setMinutes(now.getMinutes() + 1);
62
+ } else if (hourStr === "*") {
63
+ const m = parseInt(minuteStr, 10);
64
+ next.setMinutes(m, 0, 0);
65
+ if (next <= now) next.setHours(now.getHours() + 1);
66
+ } else {
67
+ const h = parseInt(hourStr, 10);
68
+ const m = parseInt(minuteStr, 10);
69
+ next.setHours(h, m, 0, 0);
70
+ if (next <= now) next.setDate(now.getDate() + 1);
71
+ }
72
+ return formatDistanceToNow(next, { addSuffix: true });
73
+ } catch {
74
+ return "Unknown";
75
+ }
76
+ }
77
+ var ScheduledRow = ({ def }) => {
78
+ const { t } = useTranslation();
79
+ const schedule = def.options?.schedule;
80
+ const cronStr = typeof schedule === "string" ? schedule : typeof schedule === "object" ? schedule?.cron ?? String(schedule?.interval ?? "") : "";
81
+ const humanSchedule = cronStr ? describeCron(cronStr) : "\u2014";
82
+ const nextRun = cronStr ? getNextRunLabel(cronStr) : "\u2014";
83
+ const { mutateAsync: runWorkflow, isPending } = useRunWorkflow(def.id);
84
+ const handleRunNow = async () => {
85
+ await runWorkflow(
86
+ { input: {} },
87
+ {
88
+ onSuccess: () => {
89
+ toast.success(t("workflowExecutions.actions.retrySuccess"));
90
+ }
91
+ }
92
+ );
93
+ };
94
+ return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_1fr_1fr_auto] items-center gap-x-4 px-6 py-3", children: [
95
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-0.5", children: [
96
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: def.id }),
97
+ /* @__PURE__ */ jsxs(Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
98
+ def.handler_count,
99
+ " ",
100
+ t("workflowExecutions.definitions.handlers")
101
+ ] })
102
+ ] }),
103
+ /* @__PURE__ */ jsxs("div", { children: [
104
+ /* @__PURE__ */ jsx(Badge, { size: "2xsmall", className: "font-mono", children: cronStr || "\u2014" }),
105
+ /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-subtle mt-0.5", children: humanSchedule })
106
+ ] }),
107
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: nextRun }),
108
+ /* @__PURE__ */ jsx(
109
+ Button,
110
+ {
111
+ size: "small",
112
+ variant: "secondary",
113
+ isLoading: isPending,
114
+ onClick: handleRunNow,
115
+ children: t("workflowExecutions.scheduled.runNow")
116
+ }
117
+ )
118
+ ] });
119
+ };
120
+ var WorkflowScheduledList = () => {
121
+ const { t } = useTranslation();
122
+ const { workflow_definitions, isPending } = useWorkflowDefinitions(
123
+ void 0,
124
+ { placeholderData: keepPreviousData }
125
+ );
126
+ const scheduled = (workflow_definitions ?? []).filter((def) => {
127
+ const opts = def.options;
128
+ return opts && (opts.schedule || opts.cron);
129
+ });
130
+ return /* @__PURE__ */ jsx(SingleColumnPage, { widgets: { before: [], after: [] }, children: /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
131
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-6 py-4", children: /* @__PURE__ */ jsxs("div", { children: [
132
+ /* @__PURE__ */ jsx(Heading, { children: t("workflowExecutions.scheduled.domain") }),
133
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", size: "small", children: t("workflowExecutions.scheduled.subtitle") })
134
+ ] }) }),
135
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_1fr_1fr_auto] gap-x-4 border-b border-ui-border-base px-6 py-2", children: [
136
+ /* @__PURE__ */ jsx(
137
+ Text,
138
+ {
139
+ size: "xsmall",
140
+ weight: "plus",
141
+ className: "text-ui-fg-subtle uppercase",
142
+ children: "Workflow"
143
+ }
144
+ ),
145
+ /* @__PURE__ */ jsx(
146
+ Text,
147
+ {
148
+ size: "xsmall",
149
+ weight: "plus",
150
+ className: "text-ui-fg-subtle uppercase",
151
+ children: t("workflowExecutions.scheduled.schedule")
152
+ }
153
+ ),
154
+ /* @__PURE__ */ jsx(
155
+ Text,
156
+ {
157
+ size: "xsmall",
158
+ weight: "plus",
159
+ className: "text-ui-fg-subtle uppercase",
160
+ children: t("workflowExecutions.scheduled.nextRun")
161
+ }
162
+ ),
163
+ /* @__PURE__ */ jsx("div", {})
164
+ ] }),
165
+ isPending && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Loading..." }) }),
166
+ !isPending && scheduled.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-6 py-8 text-center", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: t("workflowExecutions.scheduled.noRecordsMessage") }) }),
167
+ scheduled.map((def) => /* @__PURE__ */ jsx(ScheduledRow, { def }, def.id))
168
+ ] }) });
169
+ };
170
+ var Component = WorkflowScheduledList;
171
+ export {
172
+ Component,
173
+ WorkflowScheduledList
174
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acmekit/dashboard",
3
- "version": "2.13.33",
3
+ "version": "2.13.35",
4
4
  "scripts": {
5
5
  "generate:static": "node ./scripts/generate-currencies.js && prettier --write ./src/lib/currencies.ts",
6
6
  "dev": "../../../node_modules/.bin/vite",
@@ -39,10 +39,10 @@
39
39
  "dist"
40
40
  ],
41
41
  "dependencies": {
42
- "@acmekit/admin-shared": "2.13.33",
43
- "@acmekit/icons": "2.13.33",
44
- "@acmekit/js-sdk": "2.13.33",
45
- "@acmekit/ui": "4.1.29",
42
+ "@acmekit/admin-shared": "2.13.35",
43
+ "@acmekit/icons": "2.13.35",
44
+ "@acmekit/js-sdk": "2.13.35",
45
+ "@acmekit/ui": "4.1.31",
46
46
  "@ariakit/react": "^0.4.15",
47
47
  "@babel/runtime": "^7.26.10",
48
48
  "@dnd-kit/core": "^6.1.0",
@@ -80,10 +80,10 @@
80
80
  "zod": "3.25.76"
81
81
  },
82
82
  "devDependencies": {
83
- "@acmekit/admin-shared": "2.13.33",
84
- "@acmekit/admin-vite-plugin": "2.13.33",
85
- "@acmekit/types": "2.13.33",
86
- "@acmekit/ui-preset": "2.13.33"
83
+ "@acmekit/admin-shared": "2.13.35",
84
+ "@acmekit/admin-vite-plugin": "2.13.35",
85
+ "@acmekit/types": "2.13.35",
86
+ "@acmekit/ui-preset": "2.13.35"
87
87
  },
88
88
  "packageManager": "yarn@3.2.1"
89
89
  }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ Bolt,
2
3
  ChevronDownMini,
3
4
  CogSixTooth,
4
5
  EllipsisHorizontal,
@@ -128,7 +129,33 @@ const Header = () => {
128
129
  }
129
130
 
130
131
  const useCoreRoutes = (): Omit<INavItem, "pathname">[] => {
131
- return []
132
+ const { t } = useTranslation()
133
+
134
+ return [
135
+ {
136
+ icon: <Bolt />,
137
+ label: t("workflowExecutions.domain"),
138
+ to: "/settings/workflows",
139
+ items: [
140
+ {
141
+ label: t("workflowExecutions.tabs.executions"),
142
+ to: "/settings/workflows",
143
+ },
144
+ {
145
+ label: t("workflowExecutions.tabs.definitions"),
146
+ to: "/settings/workflows/definitions",
147
+ },
148
+ {
149
+ label: t("workflowExecutions.tabs.scheduled"),
150
+ to: "/settings/workflows/scheduled",
151
+ },
152
+ {
153
+ label: t("workflowExecutions.tabs.analytics"),
154
+ to: "/settings/workflows/analytics",
155
+ },
156
+ ],
157
+ },
158
+ ]
132
159
  }
133
160
 
134
161
  const Searchbar = () => {
@@ -186,6 +186,15 @@ const defaultSettingsRouteChildren: RouteObject[] = [
186
186
  path: "",
187
187
  lazy: () =>
188
188
  import("../../routes/workflow-executions/workflow-execution-list"),
189
+ children: [
190
+ {
191
+ path: "run",
192
+ lazy: () =>
193
+ import(
194
+ "../../routes/workflow-executions/workflow-execution-run/workflow-execution-run"
195
+ ),
196
+ },
197
+ ],
189
198
  },
190
199
  {
191
200
  path: ":id",
@@ -203,6 +212,68 @@ const defaultSettingsRouteChildren: RouteObject[] = [
203
212
  },
204
213
  }
205
214
  },
215
+ children: [
216
+ {
217
+ path: "rerun",
218
+ lazy: () =>
219
+ import(
220
+ "../../routes/workflow-executions/workflow-execution-rerun/workflow-execution-rerun"
221
+ ),
222
+ },
223
+ {
224
+ path: "complete-step",
225
+ lazy: () =>
226
+ import(
227
+ "../../routes/workflow-executions/workflow-execution-complete-step/workflow-execution-complete-step"
228
+ ),
229
+ },
230
+ ],
231
+ },
232
+ {
233
+ path: "definitions",
234
+ element: <Outlet />,
235
+ handle: {
236
+ breadcrumb: () => t("workflowExecutions.definitions.domain"),
237
+ },
238
+ children: [
239
+ {
240
+ path: "",
241
+ lazy: () =>
242
+ import(
243
+ "../../routes/workflow-definitions/workflow-definition-list/workflow-definition-list"
244
+ ),
245
+ },
246
+ {
247
+ path: ":id",
248
+ lazy: () =>
249
+ import(
250
+ "../../routes/workflow-definitions/workflow-definition-detail/workflow-definition-detail"
251
+ ),
252
+ children: [
253
+ {
254
+ path: "run",
255
+ lazy: () =>
256
+ import(
257
+ "../../routes/workflow-executions/workflow-execution-run/workflow-execution-run"
258
+ ),
259
+ },
260
+ ],
261
+ },
262
+ ],
263
+ },
264
+ {
265
+ path: "analytics",
266
+ lazy: () =>
267
+ import(
268
+ "../../routes/workflow-analytics/workflow-analytics"
269
+ ),
270
+ },
271
+ {
272
+ path: "scheduled",
273
+ lazy: () =>
274
+ import(
275
+ "../../routes/workflow-scheduled/workflow-scheduled-list"
276
+ ),
206
277
  },
207
278
  ],
208
279
  },
@@ -0,0 +1,79 @@
1
+ import { QueryKey, UseQueryOptions, useQuery } from "@tanstack/react-query"
2
+ import { sdk } from "../../lib/client"
3
+ import { queryKeysFactory } from "../../lib/query-key-factory"
4
+ import { FetchError } from "@acmekit/js-sdk"
5
+
6
+ export type WorkflowDefinitionResponse = {
7
+ workflow_definitions: Array<{
8
+ id: string
9
+ handler_count: number
10
+ steps: Array<{
11
+ action: string
12
+ depth: number
13
+ noCompensation: boolean
14
+ }>
15
+ options: Record<string, unknown>
16
+ }>
17
+ count: number
18
+ }
19
+
20
+ export type WorkflowDefinitionDetailResponse = {
21
+ workflow_definition: {
22
+ id: string
23
+ handler_count: number
24
+ steps: Array<{
25
+ action: string
26
+ depth: number
27
+ noCompensation: boolean
28
+ }>
29
+ flow: Record<string, unknown> | null
30
+ options: Record<string, unknown>
31
+ }
32
+ }
33
+
34
+ const WORKFLOW_DEFINITIONS_QUERY_KEY = "workflow_definitions" as const
35
+ export const workflowDefinitionsQueryKeys = queryKeysFactory(
36
+ WORKFLOW_DEFINITIONS_QUERY_KEY
37
+ )
38
+
39
+ export const useWorkflowDefinitions = (
40
+ query?: Record<string, unknown>,
41
+ options?: Omit<
42
+ UseQueryOptions<
43
+ WorkflowDefinitionResponse,
44
+ FetchError,
45
+ WorkflowDefinitionResponse,
46
+ QueryKey
47
+ >,
48
+ "queryKey" | "queryFn"
49
+ >
50
+ ) => {
51
+ const { data, ...rest } = useQuery({
52
+ queryFn: () => sdk.admin.workflowDefinition.list(query),
53
+ queryKey: workflowDefinitionsQueryKeys.list(query),
54
+ ...options,
55
+ })
56
+
57
+ return { ...data, ...rest }
58
+ }
59
+
60
+ export const useWorkflowDefinition = (
61
+ id: string,
62
+ options?: Omit<
63
+ UseQueryOptions<
64
+ WorkflowDefinitionDetailResponse,
65
+ FetchError,
66
+ WorkflowDefinitionDetailResponse,
67
+ QueryKey
68
+ >,
69
+ "queryKey" | "queryFn"
70
+ >
71
+ ) => {
72
+ const { data, ...rest } = useQuery({
73
+ queryFn: () => sdk.admin.workflowDefinition.retrieve(id),
74
+ queryKey: workflowDefinitionsQueryKeys.detail(id),
75
+ ...options,
76
+ })
77
+
78
+ return { ...data, ...rest }
79
+ }