@open-mercato/core 0.6.2-develop.3400.2.d948268f50 → 0.6.2-develop.3439.1.94b9d9733c
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/.turbo/turbo-build.log +1 -1
- package/dist/generated/entities/workflow_definition/index.js +2 -0
- package/dist/generated/entities/workflow_definition/index.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +1 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/sales/workflows.js +180 -0
- package/dist/modules/sales/workflows.js.map +7 -0
- package/dist/modules/workflows/api/definitions/[id]/customize/route.js +172 -0
- package/dist/modules/workflows/api/definitions/[id]/customize/route.js.map +7 -0
- package/dist/modules/workflows/api/definitions/[id]/reset-to-code/route.js +205 -0
- package/dist/modules/workflows/api/definitions/[id]/reset-to-code/route.js.map +7 -0
- package/dist/modules/workflows/api/definitions/[id]/route.js +91 -2
- package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/route.js +32 -9
- package/dist/modules/workflows/api/definitions/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/serialize.js +36 -1
- package/dist/modules/workflows/api/definitions/serialize.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.js +161 -52
- package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/page.js +37 -34
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +134 -41
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/cli.js +19 -121
- package/dist/modules/workflows/cli.js.map +2 -2
- package/dist/modules/workflows/components/formConfig.js +1 -1
- package/dist/modules/workflows/components/formConfig.js.map +2 -2
- package/dist/modules/workflows/data/entities.js +3 -0
- package/dist/modules/workflows/data/entities.js.map +2 -2
- package/dist/modules/workflows/data/validators.js +2 -2
- package/dist/modules/workflows/data/validators.js.map +2 -2
- package/dist/modules/workflows/events.js +2 -0
- package/dist/modules/workflows/events.js.map +2 -2
- package/dist/modules/workflows/examples/guard-rules-example.json +6 -6
- package/dist/modules/workflows/examples/order-approval-guard-rules.json +2 -2
- package/dist/modules/workflows/frontend/checkout-demo/page.js +4 -4
- package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
- package/dist/modules/workflows/lib/code-registry.js +40 -0
- package/dist/modules/workflows/lib/code-registry.js.map +7 -0
- package/dist/modules/workflows/lib/find-definition.js +58 -0
- package/dist/modules/workflows/lib/find-definition.js.map +7 -0
- package/dist/modules/workflows/lib/seeds.js +0 -3
- package/dist/modules/workflows/lib/seeds.js.map +2 -2
- package/dist/modules/workflows/lib/start-validator.js +1 -20
- package/dist/modules/workflows/lib/start-validator.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js +1 -19
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/dist/modules/workflows/migrations/Migration20260414120000.js +13 -0
- package/dist/modules/workflows/migrations/Migration20260414120000.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260428102318.js +32 -0
- package/dist/modules/workflows/migrations/Migration20260428102318.js.map +7 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +1 -1
- package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +1 -1
- package/dist/modules/workflows/workflows.js +260 -0
- package/dist/modules/workflows/workflows.js.map +7 -0
- package/generated/entities/workflow_definition/index.ts +1 -0
- package/generated/entity-fields-registry.ts +1 -0
- package/package.json +7 -7
- package/src/modules/sales/workflows.ts +184 -0
- package/src/modules/workflows/api/definitions/[id]/customize/route.ts +197 -0
- package/src/modules/workflows/api/definitions/[id]/reset-to-code/route.ts +252 -0
- package/src/modules/workflows/api/definitions/[id]/route.ts +108 -4
- package/src/modules/workflows/api/definitions/route.ts +54 -10
- package/src/modules/workflows/api/definitions/serialize.ts +42 -0
- package/src/modules/workflows/backend/definitions/[id]/page.tsx +135 -11
- package/src/modules/workflows/backend/definitions/page.tsx +45 -33
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +222 -97
- package/src/modules/workflows/cli.ts +32 -155
- package/src/modules/workflows/components/formConfig.tsx +2 -2
- package/src/modules/workflows/data/entities.ts +4 -1
- package/src/modules/workflows/data/validators.ts +4 -3
- package/src/modules/workflows/events.ts +2 -0
- package/src/modules/workflows/examples/guard-rules-example.json +6 -6
- package/src/modules/workflows/examples/order-approval-guard-rules.json +2 -2
- package/src/modules/workflows/frontend/checkout-demo/page.tsx +4 -4
- package/src/modules/workflows/i18n/de.json +16 -0
- package/src/modules/workflows/i18n/en.json +16 -0
- package/src/modules/workflows/i18n/es.json +16 -0
- package/src/modules/workflows/i18n/pl.json +16 -0
- package/src/modules/workflows/lib/code-registry.ts +65 -0
- package/src/modules/workflows/lib/find-definition.ts +100 -0
- package/src/modules/workflows/lib/seeds.ts +4 -3
- package/src/modules/workflows/lib/start-validator.ts +2 -35
- package/src/modules/workflows/lib/workflow-executor.ts +2 -39
- package/src/modules/workflows/migrations/.snapshot-open-mercato.json +10 -0
- package/src/modules/workflows/migrations/Migration20260414120000.ts +13 -0
- package/src/modules/workflows/migrations/Migration20260428102318.ts +57 -0
- package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +1 -1
- package/src/modules/workflows/workflows.ts +278 -0
- package/dist/modules/workflows/examples/checkout-demo-definition.json +0 -486
- package/dist/modules/workflows/examples/order-approval-definition.json +0 -257
- package/dist/modules/workflows/examples/simple-approval-definition.json +0 -134
- package/src/modules/workflows/examples/checkout-demo-definition.json +0 -486
- package/src/modules/workflows/examples/order-approval-definition.json +0 -257
- package/src/modules/workflows/examples/simple-approval-definition.json +0 -134
|
@@ -7,8 +7,13 @@ import { Page, PageBody } from "@open-mercato/ui/backend/Page";
|
|
|
7
7
|
import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
|
|
8
8
|
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
9
9
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
10
|
+
import { Alert, AlertDescription } from "@open-mercato/ui/primitives/alert";
|
|
10
11
|
import { apiFetch } from "@open-mercato/ui/backend/utils/api";
|
|
12
|
+
import { readJsonSafe } from "@open-mercato/ui/backend/utils/serverErrors";
|
|
13
|
+
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
11
14
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
15
|
+
import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
|
|
16
|
+
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
|
|
12
17
|
import {
|
|
13
18
|
workflowDefinitionFormSchema,
|
|
14
19
|
createFormGroups,
|
|
@@ -54,20 +59,112 @@ function EditWorkflowDefinitionPage() {
|
|
|
54
59
|
React.useEffect(() => {
|
|
55
60
|
setTriggers(initialValues?.triggers ?? []);
|
|
56
61
|
}, [initialValues]);
|
|
62
|
+
const source = definition?.source;
|
|
63
|
+
const isCodeOnly = source === "code";
|
|
64
|
+
const isCodeOverride = source === "code_override";
|
|
65
|
+
const { confirm, ConfirmDialogElement } = useConfirmDialog();
|
|
66
|
+
const mutationContextId = React.useMemo(
|
|
67
|
+
() => `workflows.definitions.detail:${definitionId ?? "unknown"}`,
|
|
68
|
+
[definitionId]
|
|
69
|
+
);
|
|
70
|
+
const { runMutation, retryLastMutation } = useGuardedMutation({
|
|
71
|
+
contextId: mutationContextId
|
|
72
|
+
});
|
|
57
73
|
const handleSubmit = async (values) => {
|
|
58
74
|
const payload = buildWorkflowPayload({ ...values, triggers });
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
await runMutation({
|
|
76
|
+
operation: async () => {
|
|
77
|
+
const response = await apiFetch(`/api/workflows/definitions/${definitionId}`, {
|
|
78
|
+
method: "PUT",
|
|
79
|
+
headers: { "Content-Type": "application/json" },
|
|
80
|
+
body: JSON.stringify(payload)
|
|
81
|
+
});
|
|
82
|
+
if (!response.ok) {
|
|
83
|
+
const errorBody = await readJsonSafe(response, null);
|
|
84
|
+
throw new Error(errorBody?.error || t("workflows.errors.updateFailed"));
|
|
85
|
+
}
|
|
86
|
+
return response;
|
|
87
|
+
},
|
|
88
|
+
mutationPayload: { resourceId: definitionId, operation: "update" },
|
|
89
|
+
context: {
|
|
90
|
+
formId: mutationContextId,
|
|
91
|
+
resourceKind: "workflows.definition",
|
|
92
|
+
resourceId: definitionId,
|
|
93
|
+
operation: "update",
|
|
94
|
+
retryLastMutation
|
|
95
|
+
}
|
|
63
96
|
});
|
|
64
|
-
if (!response.ok) {
|
|
65
|
-
const error2 = await response.json();
|
|
66
|
-
throw new Error(error2.error || t("workflows.errors.updateFailed"));
|
|
67
|
-
}
|
|
68
97
|
router.push("/backend/definitions");
|
|
69
98
|
router.refresh();
|
|
70
99
|
};
|
|
100
|
+
const handleCustomize = async () => {
|
|
101
|
+
try {
|
|
102
|
+
const result = await runMutation({
|
|
103
|
+
operation: async () => {
|
|
104
|
+
const response = await apiFetch(`/api/workflows/definitions/${definitionId}/customize`, {
|
|
105
|
+
method: "POST"
|
|
106
|
+
});
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
const errorBody = await readJsonSafe(response, null);
|
|
109
|
+
throw new Error(errorBody?.error || t("workflows.errors.updateFailed"));
|
|
110
|
+
}
|
|
111
|
+
return readJsonSafe(response, null);
|
|
112
|
+
},
|
|
113
|
+
mutationPayload: { resourceId: definitionId, operation: "customize" },
|
|
114
|
+
context: {
|
|
115
|
+
formId: mutationContextId,
|
|
116
|
+
resourceKind: "workflows.definition",
|
|
117
|
+
resourceId: definitionId,
|
|
118
|
+
operation: "customize",
|
|
119
|
+
retryLastMutation
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
if (result?.data?.id) {
|
|
123
|
+
router.push(`/backend/definitions/${result.data.id}`);
|
|
124
|
+
router.refresh();
|
|
125
|
+
}
|
|
126
|
+
} catch (error2) {
|
|
127
|
+
const message = error2 instanceof Error ? error2.message : t("workflows.errors.updateFailed");
|
|
128
|
+
flash(message, "error");
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const handleResetToCode = async () => {
|
|
132
|
+
const confirmed = await confirm({
|
|
133
|
+
title: t("workflows.actions.resetToCode"),
|
|
134
|
+
description: t("workflows.actions.resetConfirm"),
|
|
135
|
+
confirmText: t("workflows.actions.resetToCode"),
|
|
136
|
+
variant: "destructive"
|
|
137
|
+
});
|
|
138
|
+
if (!confirmed) return;
|
|
139
|
+
try {
|
|
140
|
+
const result = await runMutation({
|
|
141
|
+
operation: async () => {
|
|
142
|
+
const response = await apiFetch(`/api/workflows/definitions/${definitionId}/reset-to-code`, {
|
|
143
|
+
method: "POST"
|
|
144
|
+
});
|
|
145
|
+
if (!response.ok) {
|
|
146
|
+
const errorBody = await readJsonSafe(response, null);
|
|
147
|
+
throw new Error(errorBody?.error || t("workflows.messages.updateFailed"));
|
|
148
|
+
}
|
|
149
|
+
return readJsonSafe(response, null);
|
|
150
|
+
},
|
|
151
|
+
mutationPayload: { resourceId: definitionId, operation: "reset-to-code" },
|
|
152
|
+
context: {
|
|
153
|
+
formId: mutationContextId,
|
|
154
|
+
resourceKind: "workflows.definition",
|
|
155
|
+
resourceId: definitionId,
|
|
156
|
+
operation: "reset-to-code",
|
|
157
|
+
retryLastMutation
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
flash(t("workflows.messages.updated"), "success");
|
|
161
|
+
const codeId = result?.data?.id || `code:${definition?.workflowId}`;
|
|
162
|
+
router.push(`/backend/definitions/${codeId}`);
|
|
163
|
+
router.refresh();
|
|
164
|
+
} catch {
|
|
165
|
+
flash(t("workflows.messages.updateFailed"), "error");
|
|
166
|
+
}
|
|
167
|
+
};
|
|
71
168
|
const fields = React.useMemo(() => createFieldDefinitions(t), [t]);
|
|
72
169
|
const formGroups = React.useMemo(
|
|
73
170
|
() => isMobile ? [] : createFormGroups(t, StepsEditor, TransitionsEditor),
|
|
@@ -91,52 +188,64 @@ function EditWorkflowDefinitionPage() {
|
|
|
91
188
|
if (!initialValues) {
|
|
92
189
|
return null;
|
|
93
190
|
}
|
|
94
|
-
return /* @__PURE__ */
|
|
95
|
-
/* @__PURE__ */ jsxs(
|
|
96
|
-
/* @__PURE__ */
|
|
97
|
-
/* @__PURE__ */ jsx("
|
|
98
|
-
/* @__PURE__ */
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
191
|
+
return /* @__PURE__ */ jsxs(Page, { children: [
|
|
192
|
+
/* @__PURE__ */ jsxs(PageBody, { children: [
|
|
193
|
+
isCodeOnly && /* @__PURE__ */ jsx(Alert, { variant: "info", className: "mb-4", children: /* @__PURE__ */ jsxs(AlertDescription, { className: "flex items-center justify-between", children: [
|
|
194
|
+
/* @__PURE__ */ jsx("span", { children: t("workflows.source.code.readonlyBanner") }),
|
|
195
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: handleCustomize, children: t("workflows.actions.customize") })
|
|
196
|
+
] }) }),
|
|
197
|
+
isCodeOverride && /* @__PURE__ */ jsx(Alert, { variant: "warning", className: "mb-4", children: /* @__PURE__ */ jsxs(AlertDescription, { className: "flex items-center justify-between", children: [
|
|
198
|
+
/* @__PURE__ */ jsx("span", { children: t("workflows.source.code_override.banner") }),
|
|
199
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: handleResetToCode, children: t("workflows.actions.resetToCode") })
|
|
200
|
+
] }) }),
|
|
201
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4 p-4 bg-status-info-bg border border-status-info-border rounded-lg flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
202
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
203
|
+
/* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-status-info-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 10V3L4 14h7v7l9-11h-7z" }) }),
|
|
204
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
205
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-status-info-text", children: t("workflows.edit.visualEditorAvailable") }),
|
|
206
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-status-info-text mt-0.5", children: t("workflows.edit.visualEditorDescription") })
|
|
207
|
+
] })
|
|
208
|
+
] }),
|
|
209
|
+
/* @__PURE__ */ jsx(Button, { asChild: true, variant: "outline", size: "sm", className: "w-full sm:w-auto border-status-info-border text-status-info-text hover:bg-status-info-bg", children: /* @__PURE__ */ jsx("a", { href: `/backend/definitions/visual-editor?id=${definitionId}`, children: t("workflows.actions.openVisualEditor") }) })
|
|
102
210
|
] }),
|
|
103
|
-
/* @__PURE__ */ jsx(
|
|
211
|
+
/* @__PURE__ */ jsx(
|
|
212
|
+
CrudForm,
|
|
213
|
+
{
|
|
214
|
+
title: isCodeOnly ? definition?.workflowName || t("workflows.edit.title") : t("workflows.edit.title"),
|
|
215
|
+
backHref: "/backend/definitions",
|
|
216
|
+
schema: workflowDefinitionFormSchema,
|
|
217
|
+
fields,
|
|
218
|
+
initialValues,
|
|
219
|
+
onSubmit: handleSubmit,
|
|
220
|
+
cancelHref: "/backend/definitions",
|
|
221
|
+
groups: formGroups,
|
|
222
|
+
submitLabel: isCodeOnly ? t("workflows.actions.customize") : t("workflows.form.update"),
|
|
223
|
+
...isCodeOnly ? { readOnly: true } : {}
|
|
224
|
+
},
|
|
225
|
+
definitionId
|
|
226
|
+
),
|
|
227
|
+
isMobile && initialValues && /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(
|
|
228
|
+
MobileDefinitionDetail,
|
|
229
|
+
{
|
|
230
|
+
values: initialValues,
|
|
231
|
+
onEditStep: navigateToVisualEditor,
|
|
232
|
+
onDeleteStep: navigateToVisualEditor,
|
|
233
|
+
onAddStep: navigateToVisualEditor,
|
|
234
|
+
onEditTransition: navigateToVisualEditor,
|
|
235
|
+
onDeleteTransition: navigateToVisualEditor,
|
|
236
|
+
onAddTransition: navigateToVisualEditor
|
|
237
|
+
}
|
|
238
|
+
) }),
|
|
239
|
+
/* @__PURE__ */ jsx("div", { className: "mt-8", children: /* @__PURE__ */ jsx(
|
|
240
|
+
DefinitionTriggersEditor,
|
|
241
|
+
{
|
|
242
|
+
value: triggers,
|
|
243
|
+
onChange: setTriggers
|
|
244
|
+
}
|
|
245
|
+
) })
|
|
104
246
|
] }),
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
{
|
|
108
|
-
title: t("workflows.edit.title"),
|
|
109
|
-
backHref: "/backend/definitions",
|
|
110
|
-
schema: workflowDefinitionFormSchema,
|
|
111
|
-
fields,
|
|
112
|
-
initialValues,
|
|
113
|
-
onSubmit: handleSubmit,
|
|
114
|
-
cancelHref: "/backend/definitions",
|
|
115
|
-
groups: formGroups,
|
|
116
|
-
submitLabel: t("workflows.form.update")
|
|
117
|
-
},
|
|
118
|
-
definitionId
|
|
119
|
-
),
|
|
120
|
-
isMobile && initialValues && /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(
|
|
121
|
-
MobileDefinitionDetail,
|
|
122
|
-
{
|
|
123
|
-
values: initialValues,
|
|
124
|
-
onEditStep: navigateToVisualEditor,
|
|
125
|
-
onDeleteStep: navigateToVisualEditor,
|
|
126
|
-
onAddStep: navigateToVisualEditor,
|
|
127
|
-
onEditTransition: navigateToVisualEditor,
|
|
128
|
-
onDeleteTransition: navigateToVisualEditor,
|
|
129
|
-
onAddTransition: navigateToVisualEditor
|
|
130
|
-
}
|
|
131
|
-
) }),
|
|
132
|
-
/* @__PURE__ */ jsx("div", { className: "mt-8", children: /* @__PURE__ */ jsx(
|
|
133
|
-
DefinitionTriggersEditor,
|
|
134
|
-
{
|
|
135
|
-
value: triggers,
|
|
136
|
-
onChange: setTriggers
|
|
137
|
-
}
|
|
138
|
-
) })
|
|
139
|
-
] }) });
|
|
247
|
+
ConfirmDialogElement
|
|
248
|
+
] });
|
|
140
249
|
}
|
|
141
250
|
export {
|
|
142
251
|
EditWorkflowDefinitionPage as default
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/workflows/backend/definitions/%5Bid%5D/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter, useParams } from 'next/navigation'\nimport { useQuery } from '@tanstack/react-query'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiFetch } from '@open-mercato/ui/backend/utils/api'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n workflowDefinitionFormSchema,\n createFormGroups,\n createFieldDefinitions,\n parseWorkflowToFormValues,\n buildWorkflowPayload,\n type WorkflowDefinitionFormValues,\n} from '../../../components/formConfig'\nimport { StepsEditor } from '../../../components/StepsEditor'\nimport { TransitionsEditor } from '../../../components/TransitionsEditor'\nimport { DefinitionTriggersEditor } from '../../../components/DefinitionTriggersEditor'\nimport { MobileDefinitionDetail } from '../../../components/mobile/MobileDefinitionDetail'\nimport { useIsMobile } from '@open-mercato/ui/hooks/useIsMobile'\nimport type { WorkflowDefinitionTrigger } from '../../../data/entities'\n\nexport default function EditWorkflowDefinitionPage() {\n const router = useRouter()\n const params = useParams()\n const t = useT()\n const isMobile = useIsMobile()\n\n // Handle catch-all route: params.slug = ['definitions', 'uuid']\n let definitionId: string | undefined\n if (params?.slug && Array.isArray(params.slug)) {\n definitionId = params.slug[1] // Second element is the ID\n } else if (params?.id) {\n definitionId = Array.isArray(params.id) ? params.id[0] : params.id\n }\n\n const { data: definition, isLoading, error } = useQuery({\n queryKey: ['workflow-definition', definitionId],\n queryFn: async () => {\n const response = await apiFetch(`/api/workflows/definitions/${definitionId}`)\n if (!response.ok) {\n throw new Error(t('workflows.errors.fetchFailed'))\n }\n const result = await response.json()\n return result.data\n },\n enabled: !!definitionId,\n })\n\n const initialValues = React.useMemo(() => {\n if (definition) {\n return parseWorkflowToFormValues(definition)\n }\n return null\n }, [definition])\n\n const [triggers, setTriggers] = React.useState<WorkflowDefinitionTrigger[]>([])\n\n React.useEffect(() => {\n setTriggers(initialValues?.triggers ?? [])\n }, [initialValues])\n\n const handleSubmit = async (values: WorkflowDefinitionFormValues) => {\n const payload = buildWorkflowPayload({ ...values, triggers })\n\n const response = await apiFetch(`/api/workflows/definitions/${definitionId}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) {\n const error = await response.json()\n throw new Error(error.error || t('workflows.errors.updateFailed'))\n }\n\n router.push('/backend/definitions')\n router.refresh()\n }\n\n const fields = React.useMemo(() => createFieldDefinitions(t), [t])\n\n const formGroups = React.useMemo(\n () => isMobile ? [] : createFormGroups(t, StepsEditor, TransitionsEditor),\n [t, isMobile]\n )\n\n const navigateToVisualEditor = React.useCallback(() => {\n router.push(`/backend/definitions/visual-editor?id=${definitionId}`)\n }, [router, definitionId])\n\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground\">\n <Spinner className=\"h-6 w-6\" />\n <span>{t('workflows.edit.loading')}</span>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (error || !definition) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground\">\n <p>{t('workflows.errors.loadFailed')}</p>\n <Button asChild variant=\"outline\">\n <a href=\"/backend/definitions\">{t('workflows.backToList')}</a>\n </Button>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (!initialValues) {\n return null\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"mb-4 p-4 bg-status-info-bg border border-status-info-border rounded-lg flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-start gap-3\">\n <svg className=\"w-5 h-5 text-status-info-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M13 10V3L4 14h7v7l9-11h-7z\" />\n </svg>\n <div>\n <p className=\"text-sm font-medium text-status-info-text\">\n {t('workflows.edit.visualEditorAvailable')}\n </p>\n <p className=\"text-xs text-status-info-text mt-0.5\">\n {t('workflows.edit.visualEditorDescription')}\n </p>\n </div>\n </div>\n <Button asChild variant=\"outline\" size=\"sm\" className=\"w-full sm:w-auto border-status-info-border text-status-info-text hover:bg-status-info-bg\">\n <a href={`/backend/definitions/visual-editor?id=${definitionId}`}>\n {t('workflows.actions.openVisualEditor')}\n </a>\n </Button>\n </div>\n <CrudForm\n key={definitionId}\n title={t('workflows.edit.title')}\n backHref=\"/backend/definitions\"\n schema={workflowDefinitionFormSchema}\n fields={fields}\n initialValues={initialValues}\n onSubmit={handleSubmit}\n cancelHref=\"/backend/definitions\"\n groups={formGroups}\n submitLabel={t('workflows.form.update')}\n />\n\n {/* Mobile Steps & Transitions View */}\n {isMobile && initialValues && (\n <div className=\"mt-4\">\n <MobileDefinitionDetail\n values={initialValues}\n onEditStep={navigateToVisualEditor}\n onDeleteStep={navigateToVisualEditor}\n onAddStep={navigateToVisualEditor}\n onEditTransition={navigateToVisualEditor}\n onDeleteTransition={navigateToVisualEditor}\n onAddTransition={navigateToVisualEditor}\n />\n </div>\n )}\n\n {/* Event Triggers Section */}\n <div className=\"mt-8\">\n <DefinitionTriggersEditor\n value={triggers}\n onChange={setTriggers}\n />\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter, useParams } from 'next/navigation'\nimport { useQuery } from '@tanstack/react-query'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { apiFetch } from '@open-mercato/ui/backend/utils/api'\nimport { readJsonSafe } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport {\n workflowDefinitionFormSchema,\n createFormGroups,\n createFieldDefinitions,\n parseWorkflowToFormValues,\n buildWorkflowPayload,\n type WorkflowDefinitionFormValues,\n} from '../../../components/formConfig'\nimport { StepsEditor } from '../../../components/StepsEditor'\nimport { TransitionsEditor } from '../../../components/TransitionsEditor'\nimport { DefinitionTriggersEditor } from '../../../components/DefinitionTriggersEditor'\nimport { MobileDefinitionDetail } from '../../../components/mobile/MobileDefinitionDetail'\nimport { useIsMobile } from '@open-mercato/ui/hooks/useIsMobile'\nimport type { WorkflowDefinitionTrigger } from '../../../data/entities'\n\nexport default function EditWorkflowDefinitionPage() {\n const router = useRouter()\n const params = useParams()\n const t = useT()\n const isMobile = useIsMobile()\n\n // Handle catch-all route: params.slug = ['definitions', 'uuid']\n let definitionId: string | undefined\n if (params?.slug && Array.isArray(params.slug)) {\n definitionId = params.slug[1] // Second element is the ID\n } else if (params?.id) {\n definitionId = Array.isArray(params.id) ? params.id[0] : params.id\n }\n\n const { data: definition, isLoading, error } = useQuery({\n queryKey: ['workflow-definition', definitionId],\n queryFn: async () => {\n const response = await apiFetch(`/api/workflows/definitions/${definitionId}`)\n if (!response.ok) {\n throw new Error(t('workflows.errors.fetchFailed'))\n }\n const result = await response.json()\n return result.data\n },\n enabled: !!definitionId,\n })\n\n const initialValues = React.useMemo(() => {\n if (definition) {\n return parseWorkflowToFormValues(definition)\n }\n return null\n }, [definition])\n\n const [triggers, setTriggers] = React.useState<WorkflowDefinitionTrigger[]>([])\n\n React.useEffect(() => {\n setTriggers(initialValues?.triggers ?? [])\n }, [initialValues])\n\n const source = definition?.source as 'code' | 'code_override' | 'user' | undefined\n const isCodeOnly = source === 'code'\n const isCodeOverride = source === 'code_override'\n\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const mutationContextId = React.useMemo(\n () => `workflows.definitions.detail:${definitionId ?? 'unknown'}`,\n [definitionId],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: mutationContextId,\n })\n\n const handleSubmit = async (values: WorkflowDefinitionFormValues) => {\n const payload = buildWorkflowPayload({ ...values, triggers })\n\n await runMutation({\n operation: async () => {\n const response = await apiFetch(`/api/workflows/definitions/${definitionId}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!response.ok) {\n const errorBody = await readJsonSafe<{ error?: string }>(response, null)\n throw new Error(errorBody?.error || t('workflows.errors.updateFailed'))\n }\n return response\n },\n mutationPayload: { resourceId: definitionId, operation: 'update' },\n context: {\n formId: mutationContextId,\n resourceKind: 'workflows.definition',\n resourceId: definitionId,\n operation: 'update',\n retryLastMutation,\n },\n })\n\n router.push('/backend/definitions')\n router.refresh()\n }\n\n const handleCustomize = async () => {\n try {\n const result = await runMutation({\n operation: async () => {\n const response = await apiFetch(`/api/workflows/definitions/${definitionId}/customize`, {\n method: 'POST',\n })\n if (!response.ok) {\n const errorBody = await readJsonSafe<{ error?: string }>(response, null)\n throw new Error(errorBody?.error || t('workflows.errors.updateFailed'))\n }\n return readJsonSafe<{ data?: { id?: string } }>(response, null)\n },\n mutationPayload: { resourceId: definitionId, operation: 'customize' },\n context: {\n formId: mutationContextId,\n resourceKind: 'workflows.definition',\n resourceId: definitionId,\n operation: 'customize',\n retryLastMutation,\n },\n })\n if (result?.data?.id) {\n router.push(`/backend/definitions/${result.data.id}`)\n router.refresh()\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : t('workflows.errors.updateFailed')\n flash(message, 'error')\n }\n }\n\n const handleResetToCode = async () => {\n const confirmed = await confirm({\n title: t('workflows.actions.resetToCode'),\n description: t('workflows.actions.resetConfirm'),\n confirmText: t('workflows.actions.resetToCode'),\n variant: 'destructive',\n })\n if (!confirmed) return\n\n try {\n const result = await runMutation({\n operation: async () => {\n const response = await apiFetch(`/api/workflows/definitions/${definitionId}/reset-to-code`, {\n method: 'POST',\n })\n if (!response.ok) {\n const errorBody = await readJsonSafe<{ error?: string }>(response, null)\n throw new Error(errorBody?.error || t('workflows.messages.updateFailed'))\n }\n return readJsonSafe<{ data?: { id?: string } }>(response, null)\n },\n mutationPayload: { resourceId: definitionId, operation: 'reset-to-code' },\n context: {\n formId: mutationContextId,\n resourceKind: 'workflows.definition',\n resourceId: definitionId,\n operation: 'reset-to-code',\n retryLastMutation,\n },\n })\n flash(t('workflows.messages.updated'), 'success')\n const codeId = result?.data?.id || `code:${definition?.workflowId}`\n router.push(`/backend/definitions/${codeId}`)\n router.refresh()\n } catch {\n flash(t('workflows.messages.updateFailed'), 'error')\n }\n }\n\n const fields = React.useMemo(() => createFieldDefinitions(t), [t])\n\n const formGroups = React.useMemo(\n () => isMobile ? [] : createFormGroups(t, StepsEditor, TransitionsEditor),\n [t, isMobile]\n )\n\n const navigateToVisualEditor = React.useCallback(() => {\n router.push(`/backend/definitions/visual-editor?id=${definitionId}`)\n }, [router, definitionId])\n\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground\">\n <Spinner className=\"h-6 w-6\" />\n <span>{t('workflows.edit.loading')}</span>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (error || !definition) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground\">\n <p>{t('workflows.errors.loadFailed')}</p>\n <Button asChild variant=\"outline\">\n <a href=\"/backend/definitions\">{t('workflows.backToList')}</a>\n </Button>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (!initialValues) {\n return null\n }\n\n return (\n <Page>\n <PageBody>\n {isCodeOnly && (\n <Alert variant=\"info\" className=\"mb-4\">\n <AlertDescription className=\"flex items-center justify-between\">\n <span>{t('workflows.source.code.readonlyBanner')}</span>\n <Button variant=\"outline\" size=\"sm\" onClick={handleCustomize}>\n {t('workflows.actions.customize')}\n </Button>\n </AlertDescription>\n </Alert>\n )}\n {isCodeOverride && (\n <Alert variant=\"warning\" className=\"mb-4\">\n <AlertDescription className=\"flex items-center justify-between\">\n <span>{t('workflows.source.code_override.banner')}</span>\n <Button variant=\"outline\" size=\"sm\" onClick={handleResetToCode}>\n {t('workflows.actions.resetToCode')}\n </Button>\n </AlertDescription>\n </Alert>\n )}\n <div className=\"mb-4 p-4 bg-status-info-bg border border-status-info-border rounded-lg flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-start gap-3\">\n <svg className=\"w-5 h-5 text-status-info-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M13 10V3L4 14h7v7l9-11h-7z\" />\n </svg>\n <div>\n <p className=\"text-sm font-medium text-status-info-text\">\n {t('workflows.edit.visualEditorAvailable')}\n </p>\n <p className=\"text-xs text-status-info-text mt-0.5\">\n {t('workflows.edit.visualEditorDescription')}\n </p>\n </div>\n </div>\n <Button asChild variant=\"outline\" size=\"sm\" className=\"w-full sm:w-auto border-status-info-border text-status-info-text hover:bg-status-info-bg\">\n <a href={`/backend/definitions/visual-editor?id=${definitionId}`}>\n {t('workflows.actions.openVisualEditor')}\n </a>\n </Button>\n </div>\n <CrudForm\n key={definitionId}\n title={isCodeOnly ? definition?.workflowName || t('workflows.edit.title') : t('workflows.edit.title')}\n backHref=\"/backend/definitions\"\n schema={workflowDefinitionFormSchema}\n fields={fields}\n initialValues={initialValues}\n onSubmit={handleSubmit}\n cancelHref=\"/backend/definitions\"\n groups={formGroups}\n submitLabel={isCodeOnly ? t('workflows.actions.customize') : t('workflows.form.update')}\n {...(isCodeOnly ? { readOnly: true } : {})}\n />\n\n {/* Mobile Steps & Transitions View */}\n {isMobile && initialValues && (\n <div className=\"mt-4\">\n <MobileDefinitionDetail\n values={initialValues}\n onEditStep={navigateToVisualEditor}\n onDeleteStep={navigateToVisualEditor}\n onAddStep={navigateToVisualEditor}\n onEditTransition={navigateToVisualEditor}\n onDeleteTransition={navigateToVisualEditor}\n onAddTransition={navigateToVisualEditor}\n />\n </div>\n )}\n\n {/* Event Triggers Section */}\n <div className=\"mt-8\">\n <DefinitionTriggersEditor\n value={triggers}\n onChange={setTriggers}\n />\n </div>\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["error"]
|
|
7
7
|
}
|
|
@@ -174,7 +174,11 @@ function WorkflowDefinitionsListPage() {
|
|
|
174
174
|
accessorKey: "workflowName",
|
|
175
175
|
meta: { truncate: false },
|
|
176
176
|
cell: ({ row }) => /* @__PURE__ */ jsxs("div", { children: [
|
|
177
|
-
/* @__PURE__ */
|
|
177
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
178
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: row.original.workflowName }),
|
|
179
|
+
row.original.source === "code" && /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: t("workflows.source.code") }),
|
|
180
|
+
row.original.source === "code_override" && /* @__PURE__ */ jsx(Badge, { variant: "outline", children: t("workflows.source.code_override") })
|
|
181
|
+
] }),
|
|
178
182
|
row.original.description && /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: row.original.description }),
|
|
179
183
|
row.original.metadata?.category && /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-400 mt-0.5", children: row.original.metadata.category })
|
|
180
184
|
] })
|
|
@@ -230,39 +234,38 @@ function WorkflowDefinitionsListPage() {
|
|
|
230
234
|
{
|
|
231
235
|
id: "actions",
|
|
232
236
|
header: "",
|
|
233
|
-
cell: ({ row }) =>
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
)
|
|
237
|
+
cell: ({ row }) => {
|
|
238
|
+
const isCodeOnly = row.original.source === "code";
|
|
239
|
+
const items = [
|
|
240
|
+
{
|
|
241
|
+
id: "edit",
|
|
242
|
+
label: isCodeOnly ? t("common.view") : t("common.edit"),
|
|
243
|
+
href: `/backend/definitions/${row.original.id}`
|
|
244
|
+
},
|
|
245
|
+
...!isCodeOnly ? [{
|
|
246
|
+
id: "edit-visual",
|
|
247
|
+
label: t("workflows.actions.editVisually"),
|
|
248
|
+
href: `/backend/definitions/visual-editor?id=${row.original.id}`
|
|
249
|
+
}] : [],
|
|
250
|
+
...!isCodeOnly ? [{
|
|
251
|
+
id: row.original.enabled ? "disable" : "enable",
|
|
252
|
+
label: row.original.enabled ? t("common.disable") : t("common.enable"),
|
|
253
|
+
onSelect: () => handleToggleEnabled(row.original.id, row.original.enabled)
|
|
254
|
+
}] : [],
|
|
255
|
+
...!isCodeOnly ? [{
|
|
256
|
+
id: "duplicate",
|
|
257
|
+
label: t("common.duplicate"),
|
|
258
|
+
onSelect: () => handleDuplicate(row.original)
|
|
259
|
+
}] : [],
|
|
260
|
+
...!isCodeOnly ? [{
|
|
261
|
+
id: "delete",
|
|
262
|
+
label: t("common.delete"),
|
|
263
|
+
onSelect: () => handleDelete(row.original.id, row.original.workflowName),
|
|
264
|
+
destructive: true
|
|
265
|
+
}] : []
|
|
266
|
+
];
|
|
267
|
+
return /* @__PURE__ */ jsx(RowActions, { items });
|
|
268
|
+
}
|
|
266
269
|
}
|
|
267
270
|
];
|
|
268
271
|
if (error) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/workflows/backend/definitions/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Trash2 } from 'lucide-react'\n\ntype WorkflowDefinition = {\n id: string\n workflowId: string\n workflowName: string\n description: string | null\n version: number\n definition: Record<string, unknown>\n enabled: boolean\n effectiveFrom: string | null\n effectiveTo: string | null\n metadata: {\n tags?: string[]\n category?: string\n icon?: string\n } | null\n tenantId: string\n organizationId: string\n createdAt: string\n updatedAt: string\n createdBy: string | null\n}\n\ntype DefinitionsResponse = {\n data: WorkflowDefinition[]\n pagination: {\n total: number\n limit: number\n offset: number\n hasMore: boolean\n }\n}\n\ntype CreateDefinitionResponse = {\n data?: {\n id?: string\n }\n error?: string\n}\n\nconst WORKFLOW_ID_MAX_LENGTH = 100\n\nfunction buildDuplicateWorkflowId(sourceWorkflowId: string, attempt: number): string {\n const suffix = attempt === 0 ? '_copy' : `_copy_${attempt + 1}`\n const maxBaseLength = Math.max(1, WORKFLOW_ID_MAX_LENGTH - suffix.length)\n const base = sourceWorkflowId.slice(0, maxBaseLength)\n return `${base}${suffix}`\n}\n\nexport default function WorkflowDefinitionsListPage() {\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(20)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const t = useT()\n const router = useRouter()\n const queryClient = useQueryClient()\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [deleteTarget, setDeleteTarget] = React.useState<{ id: string; name: string } | null>(null)\n\n const { data, isLoading, error } = useQuery({\n queryKey: ['workflow-definitions', 'list', filterValues, page],\n queryFn: async () => {\n const params = new URLSearchParams()\n const offset = (page - 1) * pageSize\n params.set('limit', pageSize.toString())\n params.set('offset', offset.toString())\n\n if (filterValues.enabled !== undefined && filterValues.enabled !== '') {\n params.set('enabled', filterValues.enabled as string)\n }\n if (filterValues.workflowId) params.set('workflowId', filterValues.workflowId as string)\n if (filterValues.search) params.set('search', filterValues.search as string)\n\n const result = await apiCall<DefinitionsResponse>(\n `/api/workflows/definitions?${params.toString()}`\n )\n\n if (!result.ok) {\n throw new Error('Failed to fetch workflow definitions')\n }\n\n const response = result.result\n if (response?.pagination) {\n setTotal(response.pagination.total || 0)\n const calculatedPages = Math.ceil((response.pagination.total || 0) / pageSize)\n setTotalPages(calculatedPages || 1)\n }\n\n return response?.data || []\n },\n })\n\n const handleDelete = (id: string, workflowName: string) => {\n setDeleteTarget({ id, name: workflowName })\n }\n\n const confirmDelete = async () => {\n if (!deleteTarget) return\n\n const result = await apiCall(`/api/workflows/definitions/${deleteTarget.id}`, {\n method: 'DELETE',\n })\n\n if (result.ok) {\n flash(t('workflows.messages.deleted'), 'success')\n queryClient.invalidateQueries({ queryKey: ['workflow-definitions'] })\n } else {\n flash(t('workflows.messages.deleteFailed'), 'error')\n }\n setDeleteTarget(null)\n }\n\n const handleToggleEnabled = async (id: string, currentEnabled: boolean) => {\n const result = await apiCall(`/api/workflows/definitions/${id}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n enabled: !currentEnabled,\n }),\n })\n\n if (result.ok) {\n flash(t('workflows.messages.updated'), 'success')\n queryClient.invalidateQueries({ queryKey: ['workflow-definitions'] })\n } else {\n flash(t('workflows.messages.updateFailed'), 'error')\n }\n }\n\n const handleDuplicate = async (definition: WorkflowDefinition) => {\n for (let attempt = 0; attempt < 10; attempt += 1) {\n const duplicateWorkflowId = buildDuplicateWorkflowId(definition.workflowId, attempt)\n const result = await apiCall<CreateDefinitionResponse>('/api/workflows/definitions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n workflowId: duplicateWorkflowId,\n workflowName: definition.workflowName,\n description: definition.description,\n version: definition.version,\n definition: definition.definition,\n metadata: definition.metadata,\n enabled: definition.enabled,\n }),\n })\n\n if (result.ok) {\n flash(t('workflows.messages.workflowDuplicated'), 'success')\n queryClient.invalidateQueries({ queryKey: ['workflow-definitions'] })\n return\n }\n\n if (result.status !== 409) {\n break\n }\n }\n\n flash(t('workflows.errors.createFailed'), 'error')\n }\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n const next: FilterValues = {}\n Object.entries(values).forEach(([key, value]) => {\n if (value !== undefined && value !== '') next[key] = value\n })\n setFilterValues(next)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const filters: FilterDef[] = [\n {\n id: 'search',\n type: 'text',\n label: t('workflows.filters.search'),\n placeholder: t('workflows.filters.searchPlaceholder'),\n },\n {\n id: 'enabled',\n type: 'select',\n label: t('workflows.filters.status'),\n options: [\n { label: t('common.all'), value: '' },\n { label: t('common.enabled'), value: 'true' },\n { label: t('common.disabled'), value: 'false' },\n ],\n },\n {\n id: 'workflowId',\n type: 'text',\n label: t('workflows.filters.workflowId'),\n placeholder: t('workflows.filters.workflowIdPlaceholder'),\n },\n ]\n\n const columns: ColumnDef<WorkflowDefinition>[] = [\n {\n id: 'workflowId',\n header: t('workflows.fields.workflowId'),\n accessorKey: 'workflowId',\n meta: { truncate: false },\n cell: ({ row }) => (\n <span className=\"font-mono text-sm\">{row.original.workflowId}</span>\n ),\n },\n {\n id: 'workflowName',\n header: t('workflows.fields.workflowName'),\n accessorKey: 'workflowName',\n meta: { truncate: false },\n cell: ({ row }) => (\n <div>\n <div className=\"font-medium\">{row.original.workflowName}</div>\n {row.original.description && (\n <div className=\"text-xs text-gray-500\">\n {row.original.description}\n </div>\n )}\n {row.original.metadata?.category && (\n <div className=\"text-xs text-gray-400 mt-0.5\">\n {row.original.metadata.category}\n </div>\n )}\n </div>\n ),\n },\n {\n id: 'version',\n header: t('workflows.fields.version'),\n accessorKey: 'version',\n meta: { truncate: false },\n cell: ({ row }) => (\n <Badge variant=\"secondary\" className=\"font-mono\">\n v{row.original.version}\n </Badge>\n ),\n },\n {\n id: 'enabled',\n header: t('workflows.fields.enabled'),\n accessorKey: 'enabled',\n cell: ({ row }) => (\n <button\n onClick={() => handleToggleEnabled(row.original.id, row.original.enabled)}\n className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium cursor-pointer ${\n row.original.enabled\n ? 'bg-green-100 text-green-800 hover:bg-green-200'\n : 'bg-gray-100 text-gray-600 hover:bg-gray-200'\n }`}\n title={t('workflows.actions.toggleEnabled')}\n >\n {row.original.enabled ? t('common.yes') : t('common.no')}\n </button>\n ),\n },\n {\n id: 'tags',\n header: t('workflows.fields.tags'),\n cell: ({ row }) => {\n const tags = row.original.metadata?.tags || []\n if (tags.length === 0) return <span className=\"text-gray-400\">-</span>\n return (\n <div className=\"flex flex-wrap gap-1\">\n {tags.slice(0, 2).map((tag, idx) => (\n <Badge key={idx} variant=\"secondary\">\n {tag}\n </Badge>\n ))}\n {tags.length > 2 && (\n <Badge variant=\"outline\">+{tags.length - 2}</Badge>\n )}\n </div>\n )\n },\n },\n {\n id: 'createdAt',\n header: t('workflows.fields.createdAt'),\n accessorKey: 'createdAt',\n cell: ({ row }) => {\n const date = new Date(row.original.createdAt)\n return <span className=\"text-sm text-gray-600\">{date.toLocaleDateString()}</span>\n },\n },\n {\n id: 'actions',\n header: '',\n cell: ({ row }) => (\n <RowActions\n items={[\n {\n id: 'edit',\n label: t('common.edit'),\n href: `/backend/definitions/${row.original.id}`,\n },\n {\n id: 'edit-visual',\n label: t('workflows.actions.editVisually'),\n href: `/backend/definitions/visual-editor?id=${row.original.id}`,\n },\n {\n id: row.original.enabled ? 'disable' : 'enable',\n label: row.original.enabled ? t('common.disable') : t('common.enable'),\n onSelect: () => handleToggleEnabled(row.original.id, row.original.enabled),\n },\n {\n id: 'duplicate',\n label: t('common.duplicate'),\n onSelect: () => handleDuplicate(row.original),\n },\n {\n id: 'delete',\n label: t('common.delete'),\n onSelect: () => handleDelete(row.original.id, row.original.workflowName),\n destructive: true,\n },\n ]}\n />\n ),\n },\n ]\n\n if (error) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={t('workflows.messages.loadFailed')}\n description={error.message}\n action={(\n <Button variant=\"outline\" size=\"sm\" onClick={() => queryClient.invalidateQueries({ queryKey: ['workflow-definitions'] })}>\n {t('common.retry', 'Retry')}\n </Button>\n )}\n />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('workflows.list.title')}\n actions={(\n <div className=\"flex items-center gap-2\">\n <Button asChild variant=\"outline\">\n <Link href=\"/backend/definitions/visual-editor\">\n {t('workflows.actions.createVisual')}\n </Link>\n </Button>\n <Button asChild>\n <Link href=\"/backend/definitions/create\">\n {t('workflows.actions.create')}\n </Link>\n </Button>\n </div>\n )}\n columns={columns}\n data={data || []}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n onRowClick={(row) => router.push(`/backend/definitions/visual-editor?id=${row.id}`)}\n perspective={{\n tableId: 'workflows.definitions.list',\n }}\n pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}\n />\n <Dialog open={!!deleteTarget} onOpenChange={(open) => !open && setDeleteTarget(null)}>\n <DialogContent className=\"sm:max-w-md\">\n <DialogHeader>\n <DialogTitle>{t('workflows.confirm.deleteTitle')}</DialogTitle>\n <DialogDescription>\n {t('workflows.confirm.delete', { name: deleteTarget?.name ?? '' })}\n </DialogDescription>\n </DialogHeader>\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setDeleteTarget(null)}>\n {t('common.cancel')}\n </Button>\n <Button variant=\"destructive\" onClick={confirmDelete}>\n <Trash2/>\n {t('common.delete')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Trash2 } from 'lucide-react'\n\ntype WorkflowDefinitionSource = 'code' | 'code_override' | 'user'\n\ntype WorkflowDefinition = {\n id: string\n workflowId: string\n workflowName: string\n description: string | null\n version: number\n definition: Record<string, unknown>\n enabled: boolean\n effectiveFrom: string | null\n effectiveTo: string | null\n metadata: {\n tags?: string[]\n category?: string\n icon?: string\n } | null\n tenantId: string\n organizationId: string\n createdAt: string\n updatedAt: string\n createdBy: string | null\n source?: WorkflowDefinitionSource\n isCodeBased?: boolean\n}\n\ntype DefinitionsResponse = {\n data: WorkflowDefinition[]\n pagination: {\n total: number\n limit: number\n offset: number\n hasMore: boolean\n }\n}\n\ntype CreateDefinitionResponse = {\n data?: {\n id?: string\n }\n error?: string\n}\n\nconst WORKFLOW_ID_MAX_LENGTH = 100\n\nfunction buildDuplicateWorkflowId(sourceWorkflowId: string, attempt: number): string {\n const suffix = attempt === 0 ? '_copy' : `_copy_${attempt + 1}`\n const maxBaseLength = Math.max(1, WORKFLOW_ID_MAX_LENGTH - suffix.length)\n const base = sourceWorkflowId.slice(0, maxBaseLength)\n return `${base}${suffix}`\n}\n\nexport default function WorkflowDefinitionsListPage() {\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(20)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const t = useT()\n const router = useRouter()\n const queryClient = useQueryClient()\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [deleteTarget, setDeleteTarget] = React.useState<{ id: string; name: string } | null>(null)\n\n const { data, isLoading, error } = useQuery({\n queryKey: ['workflow-definitions', 'list', filterValues, page],\n queryFn: async () => {\n const params = new URLSearchParams()\n const offset = (page - 1) * pageSize\n params.set('limit', pageSize.toString())\n params.set('offset', offset.toString())\n\n if (filterValues.enabled !== undefined && filterValues.enabled !== '') {\n params.set('enabled', filterValues.enabled as string)\n }\n if (filterValues.workflowId) params.set('workflowId', filterValues.workflowId as string)\n if (filterValues.search) params.set('search', filterValues.search as string)\n\n const result = await apiCall<DefinitionsResponse>(\n `/api/workflows/definitions?${params.toString()}`\n )\n\n if (!result.ok) {\n throw new Error('Failed to fetch workflow definitions')\n }\n\n const response = result.result\n if (response?.pagination) {\n setTotal(response.pagination.total || 0)\n const calculatedPages = Math.ceil((response.pagination.total || 0) / pageSize)\n setTotalPages(calculatedPages || 1)\n }\n\n return response?.data || []\n },\n })\n\n const handleDelete = (id: string, workflowName: string) => {\n setDeleteTarget({ id, name: workflowName })\n }\n\n const confirmDelete = async () => {\n if (!deleteTarget) return\n\n const result = await apiCall(`/api/workflows/definitions/${deleteTarget.id}`, {\n method: 'DELETE',\n })\n\n if (result.ok) {\n flash(t('workflows.messages.deleted'), 'success')\n queryClient.invalidateQueries({ queryKey: ['workflow-definitions'] })\n } else {\n flash(t('workflows.messages.deleteFailed'), 'error')\n }\n setDeleteTarget(null)\n }\n\n const handleToggleEnabled = async (id: string, currentEnabled: boolean) => {\n const result = await apiCall(`/api/workflows/definitions/${id}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n enabled: !currentEnabled,\n }),\n })\n\n if (result.ok) {\n flash(t('workflows.messages.updated'), 'success')\n queryClient.invalidateQueries({ queryKey: ['workflow-definitions'] })\n } else {\n flash(t('workflows.messages.updateFailed'), 'error')\n }\n }\n\n const handleDuplicate = async (definition: WorkflowDefinition) => {\n for (let attempt = 0; attempt < 10; attempt += 1) {\n const duplicateWorkflowId = buildDuplicateWorkflowId(definition.workflowId, attempt)\n const result = await apiCall<CreateDefinitionResponse>('/api/workflows/definitions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n workflowId: duplicateWorkflowId,\n workflowName: definition.workflowName,\n description: definition.description,\n version: definition.version,\n definition: definition.definition,\n metadata: definition.metadata,\n enabled: definition.enabled,\n }),\n })\n\n if (result.ok) {\n flash(t('workflows.messages.workflowDuplicated'), 'success')\n queryClient.invalidateQueries({ queryKey: ['workflow-definitions'] })\n return\n }\n\n if (result.status !== 409) {\n break\n }\n }\n\n flash(t('workflows.errors.createFailed'), 'error')\n }\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n const next: FilterValues = {}\n Object.entries(values).forEach(([key, value]) => {\n if (value !== undefined && value !== '') next[key] = value\n })\n setFilterValues(next)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const filters: FilterDef[] = [\n {\n id: 'search',\n type: 'text',\n label: t('workflows.filters.search'),\n placeholder: t('workflows.filters.searchPlaceholder'),\n },\n {\n id: 'enabled',\n type: 'select',\n label: t('workflows.filters.status'),\n options: [\n { label: t('common.all'), value: '' },\n { label: t('common.enabled'), value: 'true' },\n { label: t('common.disabled'), value: 'false' },\n ],\n },\n {\n id: 'workflowId',\n type: 'text',\n label: t('workflows.filters.workflowId'),\n placeholder: t('workflows.filters.workflowIdPlaceholder'),\n },\n ]\n\n const columns: ColumnDef<WorkflowDefinition>[] = [\n {\n id: 'workflowId',\n header: t('workflows.fields.workflowId'),\n accessorKey: 'workflowId',\n meta: { truncate: false },\n cell: ({ row }) => (\n <span className=\"font-mono text-sm\">{row.original.workflowId}</span>\n ),\n },\n {\n id: 'workflowName',\n header: t('workflows.fields.workflowName'),\n accessorKey: 'workflowName',\n meta: { truncate: false },\n cell: ({ row }) => (\n <div>\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">{row.original.workflowName}</span>\n {row.original.source === 'code' && (\n <Badge variant=\"secondary\">{t('workflows.source.code')}</Badge>\n )}\n {row.original.source === 'code_override' && (\n <Badge variant=\"outline\">{t('workflows.source.code_override')}</Badge>\n )}\n </div>\n {row.original.description && (\n <div className=\"text-xs text-gray-500\">\n {row.original.description}\n </div>\n )}\n {row.original.metadata?.category && (\n <div className=\"text-xs text-gray-400 mt-0.5\">\n {row.original.metadata.category}\n </div>\n )}\n </div>\n ),\n },\n {\n id: 'version',\n header: t('workflows.fields.version'),\n accessorKey: 'version',\n meta: { truncate: false },\n cell: ({ row }) => (\n <Badge variant=\"secondary\" className=\"font-mono\">\n v{row.original.version}\n </Badge>\n ),\n },\n {\n id: 'enabled',\n header: t('workflows.fields.enabled'),\n accessorKey: 'enabled',\n cell: ({ row }) => (\n <button\n onClick={() => handleToggleEnabled(row.original.id, row.original.enabled)}\n className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium cursor-pointer ${\n row.original.enabled\n ? 'bg-green-100 text-green-800 hover:bg-green-200'\n : 'bg-gray-100 text-gray-600 hover:bg-gray-200'\n }`}\n title={t('workflows.actions.toggleEnabled')}\n >\n {row.original.enabled ? t('common.yes') : t('common.no')}\n </button>\n ),\n },\n {\n id: 'tags',\n header: t('workflows.fields.tags'),\n cell: ({ row }) => {\n const tags = row.original.metadata?.tags || []\n if (tags.length === 0) return <span className=\"text-gray-400\">-</span>\n return (\n <div className=\"flex flex-wrap gap-1\">\n {tags.slice(0, 2).map((tag, idx) => (\n <Badge key={idx} variant=\"secondary\">\n {tag}\n </Badge>\n ))}\n {tags.length > 2 && (\n <Badge variant=\"outline\">+{tags.length - 2}</Badge>\n )}\n </div>\n )\n },\n },\n {\n id: 'createdAt',\n header: t('workflows.fields.createdAt'),\n accessorKey: 'createdAt',\n cell: ({ row }) => {\n const date = new Date(row.original.createdAt)\n return <span className=\"text-sm text-gray-600\">{date.toLocaleDateString()}</span>\n },\n },\n {\n id: 'actions',\n header: '',\n cell: ({ row }) => {\n const isCodeOnly = row.original.source === 'code'\n const items = [\n {\n id: 'edit',\n label: isCodeOnly ? t('common.view') : t('common.edit'),\n href: `/backend/definitions/${row.original.id}`,\n },\n ...(!isCodeOnly ? [{\n id: 'edit-visual',\n label: t('workflows.actions.editVisually'),\n href: `/backend/definitions/visual-editor?id=${row.original.id}`,\n }] : []),\n ...(!isCodeOnly ? [{\n id: row.original.enabled ? 'disable' : 'enable',\n label: row.original.enabled ? t('common.disable') : t('common.enable'),\n onSelect: () => handleToggleEnabled(row.original.id, row.original.enabled),\n }] : []),\n ...(!isCodeOnly ? [{\n id: 'duplicate',\n label: t('common.duplicate'),\n onSelect: () => handleDuplicate(row.original),\n }] : []),\n ...(!isCodeOnly ? [{\n id: 'delete',\n label: t('common.delete'),\n onSelect: () => handleDelete(row.original.id, row.original.workflowName),\n destructive: true,\n }] : []),\n ]\n return <RowActions items={items} />\n },\n },\n ]\n\n if (error) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={t('workflows.messages.loadFailed')}\n description={error.message}\n action={(\n <Button variant=\"outline\" size=\"sm\" onClick={() => queryClient.invalidateQueries({ queryKey: ['workflow-definitions'] })}>\n {t('common.retry', 'Retry')}\n </Button>\n )}\n />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('workflows.list.title')}\n actions={(\n <div className=\"flex items-center gap-2\">\n <Button asChild variant=\"outline\">\n <Link href=\"/backend/definitions/visual-editor\">\n {t('workflows.actions.createVisual')}\n </Link>\n </Button>\n <Button asChild>\n <Link href=\"/backend/definitions/create\">\n {t('workflows.actions.create')}\n </Link>\n </Button>\n </div>\n )}\n columns={columns}\n data={data || []}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n onRowClick={(row) => router.push(`/backend/definitions/visual-editor?id=${row.id}`)}\n perspective={{\n tableId: 'workflows.definitions.list',\n }}\n pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}\n />\n <Dialog open={!!deleteTarget} onOpenChange={(open) => !open && setDeleteTarget(null)}>\n <DialogContent className=\"sm:max-w-md\">\n <DialogHeader>\n <DialogTitle>{t('workflows.confirm.deleteTitle')}</DialogTitle>\n <DialogDescription>\n {t('workflows.confirm.delete', { name: deleteTarget?.name ?? '' })}\n </DialogDescription>\n </DialogHeader>\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setDeleteTarget(null)}>\n {t('common.cancel')}\n </Button>\n <Button variant=\"destructive\" onClick={confirmDelete}>\n <Trash2/>\n {t('common.delete')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|