@open-mercato/core 0.6.2-develop.3400.2.d948268f50 → 0.6.2-develop.3406.1.2b403f40da
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
|
@@ -106,6 +106,10 @@ export default function VisualEditorPage() {
|
|
|
106
106
|
const [effectiveFrom, setEffectiveFrom] = useState('')
|
|
107
107
|
const [effectiveTo, setEffectiveTo] = useState('')
|
|
108
108
|
const [triggers, setTriggers] = useState<WorkflowDefinitionTrigger[]>([])
|
|
109
|
+
const [source, setSource] = useState<'code' | 'code_override' | 'user' | null>(null)
|
|
110
|
+
|
|
111
|
+
const isCodeOnly = source === 'code'
|
|
112
|
+
const isCodeOverride = source === 'code_override'
|
|
109
113
|
|
|
110
114
|
// Load existing definition if ID is provided
|
|
111
115
|
useEffect(() => {
|
|
@@ -146,7 +150,10 @@ export default function VisualEditorPage() {
|
|
|
146
150
|
// Load embedded triggers from definition
|
|
147
151
|
setTriggers(definition.definition?.triggers || [])
|
|
148
152
|
|
|
149
|
-
|
|
153
|
+
// Track source so the editor mirrors the non-visual edit page UX:
|
|
154
|
+
// code → read-only with Customize button; code_override → editable
|
|
155
|
+
// with Reset to code; user → editable, no banner.
|
|
156
|
+
setSource((definition.source as 'code' | 'code_override' | 'user') ?? null)
|
|
150
157
|
} catch (error) {
|
|
151
158
|
console.error('Error loading workflow definition:', error)
|
|
152
159
|
flash('Failed to load workflow definition', 'error')
|
|
@@ -160,16 +167,19 @@ export default function VisualEditorPage() {
|
|
|
160
167
|
|
|
161
168
|
// Handle node changes from ReactFlow
|
|
162
169
|
const handleNodesChange = useCallback((changes: NodeChange[]) => {
|
|
170
|
+
if (isCodeOnly) return
|
|
163
171
|
setNodes((nds) => applyNodeChanges(changes, nds))
|
|
164
|
-
}, [])
|
|
172
|
+
}, [isCodeOnly])
|
|
165
173
|
|
|
166
174
|
// Handle edge changes from ReactFlow
|
|
167
175
|
const handleEdgesChange = useCallback((changes: EdgeChange[]) => {
|
|
176
|
+
if (isCodeOnly) return
|
|
168
177
|
setEdges((eds) => applyEdgeChanges(changes, eds))
|
|
169
|
-
}, [])
|
|
178
|
+
}, [isCodeOnly])
|
|
170
179
|
|
|
171
180
|
// Handle adding new node from palette
|
|
172
181
|
const handleAddNode = useCallback((nodeType: string) => {
|
|
182
|
+
if (isCodeOnly) return
|
|
173
183
|
const newNode: Node = {
|
|
174
184
|
id: generateStepId(nodeType),
|
|
175
185
|
type: nodeType,
|
|
@@ -186,21 +196,24 @@ export default function VisualEditorPage() {
|
|
|
186
196
|
}
|
|
187
197
|
|
|
188
198
|
setNodes((nds) => [...nds, newNode])
|
|
189
|
-
}, [nodes.length])
|
|
199
|
+
}, [nodes.length, isCodeOnly])
|
|
190
200
|
|
|
191
|
-
// Handle node selection - open edit dialog
|
|
201
|
+
// Handle node selection - open edit dialog (suppressed in read-only mode
|
|
202
|
+
// so users can't open the node editor on a code-defined workflow).
|
|
192
203
|
const handleNodeClick = useCallback((_event: React.MouseEvent, node: Node) => {
|
|
204
|
+
if (isCodeOnly) return
|
|
193
205
|
setSelectedNode(node)
|
|
194
206
|
setSelectedEdge(null)
|
|
195
207
|
setShowNodeDialog(true)
|
|
196
|
-
}, [])
|
|
208
|
+
}, [isCodeOnly])
|
|
197
209
|
|
|
198
210
|
// Handle edge selection - open edit dialog
|
|
199
211
|
const handleEdgeClick = useCallback((_event: React.MouseEvent, edge: Edge) => {
|
|
212
|
+
if (isCodeOnly) return
|
|
200
213
|
setSelectedEdge(edge)
|
|
201
214
|
setSelectedNode(null)
|
|
202
215
|
setShowEdgeDialog(true)
|
|
203
|
-
}, [])
|
|
216
|
+
}, [isCodeOnly])
|
|
204
217
|
|
|
205
218
|
// Save node updates
|
|
206
219
|
const handleSaveNode = useCallback((nodeId: string, updates: Partial<Node['data']>) => {
|
|
@@ -355,13 +368,22 @@ export default function VisualEditorPage() {
|
|
|
355
368
|
|
|
356
369
|
let result
|
|
357
370
|
if (isUpdate) {
|
|
358
|
-
// Update existing definition
|
|
371
|
+
// Update existing definition — send the full editable payload so metadata
|
|
372
|
+
// edits (name, description, version, category, tags, icon, effective
|
|
373
|
+
// dates) actually persist. Previously only `definition` + `enabled`
|
|
374
|
+
// were sent, silently dropping every other field.
|
|
359
375
|
result = await apiCall<{ data: any; error?: string }>(`/api/workflows/definitions/${definitionId}`, {
|
|
360
376
|
method: 'PUT',
|
|
361
377
|
headers: { 'Content-Type': 'application/json' },
|
|
362
378
|
body: JSON.stringify({
|
|
379
|
+
workflowName,
|
|
380
|
+
description: description || null,
|
|
381
|
+
version,
|
|
363
382
|
definition: definitionData,
|
|
383
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : null,
|
|
364
384
|
enabled,
|
|
385
|
+
effectiveFrom: effectiveFrom || null,
|
|
386
|
+
effectiveTo: effectiveTo || null,
|
|
365
387
|
}),
|
|
366
388
|
})
|
|
367
389
|
} else {
|
|
@@ -405,6 +427,60 @@ export default function VisualEditorPage() {
|
|
|
405
427
|
}
|
|
406
428
|
}, [nodes, edges, workflowId, workflowName, description, version, enabled, category, tags, icon, effectiveFrom, effectiveTo, triggers, definitionId, router])
|
|
407
429
|
|
|
430
|
+
// Customize a code-defined workflow → creates an override and reloads the
|
|
431
|
+
// editor pointed at the new UUID. Mirrors the non-visual edit page button.
|
|
432
|
+
const handleCustomize = useCallback(async () => {
|
|
433
|
+
if (!definitionId) return
|
|
434
|
+
setIsSaving(true)
|
|
435
|
+
try {
|
|
436
|
+
const result = await apiCall<{ data?: { id?: string }; error?: string }>(
|
|
437
|
+
`/api/workflows/definitions/${definitionId}/customize`,
|
|
438
|
+
{ method: 'POST' },
|
|
439
|
+
)
|
|
440
|
+
if (!result.ok) {
|
|
441
|
+
flash(result.result?.error || 'Failed to customize workflow', 'error')
|
|
442
|
+
return
|
|
443
|
+
}
|
|
444
|
+
const newId = result.result?.data?.id
|
|
445
|
+
if (!newId) return
|
|
446
|
+
router.push(`/backend/definitions/visual-editor?id=${encodeURIComponent(newId)}`)
|
|
447
|
+
router.refresh()
|
|
448
|
+
} finally {
|
|
449
|
+
setIsSaving(false)
|
|
450
|
+
}
|
|
451
|
+
}, [definitionId, router])
|
|
452
|
+
|
|
453
|
+
// Reset a code-override back to its code definition. Mirrors the
|
|
454
|
+
// non-visual edit page action, with the same confirm dialog.
|
|
455
|
+
const handleResetToCode = useCallback(async () => {
|
|
456
|
+
if (!definitionId) return
|
|
457
|
+
const confirmed = await confirm({
|
|
458
|
+
title: t('workflows.actions.resetToCode'),
|
|
459
|
+
description: t('workflows.actions.resetConfirm'),
|
|
460
|
+
confirmText: t('workflows.actions.resetToCode'),
|
|
461
|
+
variant: 'destructive',
|
|
462
|
+
})
|
|
463
|
+
if (!confirmed) return
|
|
464
|
+
|
|
465
|
+
setIsSaving(true)
|
|
466
|
+
try {
|
|
467
|
+
const result = await apiCall<{ data?: { id?: string }; error?: string }>(
|
|
468
|
+
`/api/workflows/definitions/${definitionId}/reset-to-code`,
|
|
469
|
+
{ method: 'POST' },
|
|
470
|
+
)
|
|
471
|
+
if (!result.ok) {
|
|
472
|
+
flash(result.result?.error || 'Failed to reset workflow', 'error')
|
|
473
|
+
return
|
|
474
|
+
}
|
|
475
|
+
const codeId = result.result?.data?.id || (workflowId ? `code:${workflowId}` : null)
|
|
476
|
+
if (!codeId) return
|
|
477
|
+
router.push(`/backend/definitions/visual-editor?id=${encodeURIComponent(codeId)}`)
|
|
478
|
+
router.refresh()
|
|
479
|
+
} finally {
|
|
480
|
+
setIsSaving(false)
|
|
481
|
+
}
|
|
482
|
+
}, [definitionId, workflowId, router, confirm, t])
|
|
483
|
+
|
|
408
484
|
// Test workflow
|
|
409
485
|
const handleTest = useCallback(() => {
|
|
410
486
|
// First validate
|
|
@@ -628,26 +704,30 @@ export default function VisualEditorPage() {
|
|
|
628
704
|
{showMetadata ? <PanelTopClose className="mr-1.5 h-4 w-4" /> : <PanelTopOpen className="mr-1.5 h-4 w-4" />}
|
|
629
705
|
{showMetadata ? t('workflows.visualEditor.hideMetadata') : t('workflows.visualEditor.showMetadata')}
|
|
630
706
|
</Button>
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
707
|
+
{!isCodeOnly && (
|
|
708
|
+
<Button
|
|
709
|
+
variant="outline"
|
|
710
|
+
size="sm"
|
|
711
|
+
onClick={handleLoadExample}
|
|
712
|
+
disabled={isSaving}
|
|
713
|
+
className="h-8 text-xs"
|
|
714
|
+
>
|
|
715
|
+
{t('workflows.visualEditor.loadExample')}
|
|
716
|
+
</Button>
|
|
717
|
+
)}
|
|
718
|
+
{!isCodeOnly && (
|
|
719
|
+
<Button
|
|
720
|
+
variant="destructive"
|
|
721
|
+
size="sm"
|
|
722
|
+
onClick={handleClear}
|
|
723
|
+
disabled={isSaving}
|
|
724
|
+
className="h-8 px-2 text-xs"
|
|
725
|
+
aria-label={t('workflows.visualEditor.clear')}
|
|
726
|
+
>
|
|
727
|
+
<Trash2 className="mr-1.5 h-4 w-4" />
|
|
728
|
+
{t('workflows.visualEditor.clear')}
|
|
729
|
+
</Button>
|
|
730
|
+
)}
|
|
651
731
|
<Button
|
|
652
732
|
variant="outline"
|
|
653
733
|
size="sm"
|
|
@@ -659,43 +739,83 @@ export default function VisualEditorPage() {
|
|
|
659
739
|
<CircleQuestionMark className="mr-1.5 h-4 w-4" />
|
|
660
740
|
{t('workflows.visualEditor.validate')}
|
|
661
741
|
</Button>
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
742
|
+
{!isCodeOnly && (
|
|
743
|
+
<Button
|
|
744
|
+
variant="outline"
|
|
745
|
+
size="sm"
|
|
746
|
+
onClick={handleTest}
|
|
747
|
+
disabled={isSaving}
|
|
748
|
+
className="h-8 text-xs"
|
|
749
|
+
>
|
|
750
|
+
<Play className="mr-1.5 h-4 w-4" />
|
|
751
|
+
{t('workflows.visualEditor.runTest')}
|
|
752
|
+
</Button>
|
|
753
|
+
)}
|
|
754
|
+
{isCodeOverride && (
|
|
755
|
+
<Button
|
|
756
|
+
variant="outline"
|
|
757
|
+
size="sm"
|
|
758
|
+
onClick={handleResetToCode}
|
|
759
|
+
disabled={isSaving}
|
|
760
|
+
className="h-8 text-xs"
|
|
761
|
+
>
|
|
762
|
+
{t('workflows.actions.resetToCode')}
|
|
763
|
+
</Button>
|
|
764
|
+
)}
|
|
765
|
+
{isCodeOnly ? (
|
|
766
|
+
<Button
|
|
767
|
+
size="sm"
|
|
768
|
+
onClick={handleCustomize}
|
|
769
|
+
disabled={isSaving}
|
|
770
|
+
className="h-8 px-2 text-xs md:px-3"
|
|
771
|
+
>
|
|
772
|
+
{t('workflows.actions.customize')}
|
|
773
|
+
</Button>
|
|
774
|
+
) : (
|
|
775
|
+
<Button
|
|
776
|
+
size="sm"
|
|
777
|
+
onClick={handleSave}
|
|
778
|
+
disabled={isSaving}
|
|
779
|
+
className="h-8 px-2 text-xs md:px-3"
|
|
780
|
+
aria-label={isSaving ? t('workflows.mobile.saving') : definitionId ? t('workflows.common.update') : t('workflows.common.save')}
|
|
781
|
+
>
|
|
782
|
+
<Save className="mr-1.5 h-4 w-4" />
|
|
783
|
+
{isSaving ? t('workflows.mobile.saving') : definitionId ? t('workflows.common.update') : t('workflows.common.save')}
|
|
784
|
+
</Button>
|
|
785
|
+
)}
|
|
682
786
|
</div>
|
|
683
787
|
}
|
|
684
788
|
/>
|
|
685
789
|
</div>
|
|
686
790
|
|
|
791
|
+
{/* Source banner (code-defined / customized) */}
|
|
792
|
+
{(isCodeOnly || isCodeOverride) && (
|
|
793
|
+
<div className="shrink-0 border-b border-border bg-background px-3 py-2 md:px-6 md:py-3">
|
|
794
|
+
{isCodeOnly && (
|
|
795
|
+
<Alert variant="info">
|
|
796
|
+
<AlertTitle>{t('workflows.source.code.readonlyBanner')}</AlertTitle>
|
|
797
|
+
</Alert>
|
|
798
|
+
)}
|
|
799
|
+
{isCodeOverride && (
|
|
800
|
+
<Alert variant="warning">
|
|
801
|
+
<AlertTitle>{t('workflows.source.code_override.banner')}</AlertTitle>
|
|
802
|
+
</Alert>
|
|
803
|
+
)}
|
|
804
|
+
</div>
|
|
805
|
+
)}
|
|
806
|
+
|
|
687
807
|
{/* Workflow Metadata Form */}
|
|
688
808
|
{showMetadata && (
|
|
689
809
|
<div className={isCompactViewport
|
|
690
810
|
? 'shrink-0 border-b border-border bg-background px-3 py-2 max-h-[60svh] overflow-y-auto overscroll-contain md:px-6 md:py-3'
|
|
691
811
|
: 'shrink-0 border-b border-border bg-background px-3 py-2 md:px-6 md:py-3'
|
|
692
812
|
}>
|
|
693
|
-
<
|
|
813
|
+
<fieldset disabled={isCodeOnly} className="rounded-lg border bg-card p-3 disabled:opacity-70 md:p-4">
|
|
694
814
|
<h2 className="mb-3 text-xs font-semibold uppercase text-muted-foreground">{t('workflows.visualEditor.workflowMetadata')}</h2>
|
|
695
815
|
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3 md:gap-4">
|
|
696
816
|
{/* Workflow ID */}
|
|
697
817
|
<div className="min-w-0 space-y-1">
|
|
698
|
-
<Label htmlFor="workflowId" className="text-xs">
|
|
818
|
+
<Label htmlFor="workflowId" className="text-xs">{t('workflows.form.workflowId')} *</Label>
|
|
699
819
|
<Input
|
|
700
820
|
id="workflowId"
|
|
701
821
|
value={workflowId}
|
|
@@ -704,12 +824,12 @@ export default function VisualEditorPage() {
|
|
|
704
824
|
disabled={!!definitionId}
|
|
705
825
|
className="h-8 text-sm"
|
|
706
826
|
/>
|
|
707
|
-
{definitionId && <p className="text-overline text-muted-foreground">
|
|
827
|
+
{definitionId && <p className="text-overline text-muted-foreground">{t('workflows.visualEditor.readOnly')}</p>}
|
|
708
828
|
</div>
|
|
709
829
|
|
|
710
830
|
{/* Workflow Name */}
|
|
711
831
|
<div className="min-w-0 space-y-1">
|
|
712
|
-
<Label htmlFor="workflowName" className="text-xs">
|
|
832
|
+
<Label htmlFor="workflowName" className="text-xs">{t('workflows.form.workflowName')} *</Label>
|
|
713
833
|
<Input
|
|
714
834
|
id="workflowName"
|
|
715
835
|
value={workflowName}
|
|
@@ -721,7 +841,7 @@ export default function VisualEditorPage() {
|
|
|
721
841
|
|
|
722
842
|
{/* Category */}
|
|
723
843
|
<div className="min-w-0 space-y-1">
|
|
724
|
-
<Label htmlFor="category" className="text-xs">
|
|
844
|
+
<Label htmlFor="category" className="text-xs">{t('workflows.form.category')}</Label>
|
|
725
845
|
<Input
|
|
726
846
|
id="category"
|
|
727
847
|
value={category}
|
|
@@ -733,12 +853,12 @@ export default function VisualEditorPage() {
|
|
|
733
853
|
|
|
734
854
|
{/* Description */}
|
|
735
855
|
<div className="min-w-0 space-y-1 sm:col-span-2 lg:col-span-3">
|
|
736
|
-
<Label htmlFor="description" className="text-xs">
|
|
856
|
+
<Label htmlFor="description" className="text-xs">{t('workflows.form.description')}</Label>
|
|
737
857
|
<Textarea
|
|
738
858
|
id="description"
|
|
739
859
|
value={description}
|
|
740
860
|
onChange={(e) => setDescription(e.target.value)}
|
|
741
|
-
placeholder=
|
|
861
|
+
placeholder={t('workflows.form.placeholders.description')}
|
|
742
862
|
rows={2}
|
|
743
863
|
className="min-h-[60px] text-sm"
|
|
744
864
|
/>
|
|
@@ -746,7 +866,7 @@ export default function VisualEditorPage() {
|
|
|
746
866
|
|
|
747
867
|
{/* Version */}
|
|
748
868
|
<div className="min-w-0 space-y-1">
|
|
749
|
-
<Label htmlFor="version" className="text-xs">
|
|
869
|
+
<Label htmlFor="version" className="text-xs">{t('workflows.form.version')} *</Label>
|
|
750
870
|
<Input
|
|
751
871
|
id="version"
|
|
752
872
|
type="number"
|
|
@@ -775,7 +895,7 @@ export default function VisualEditorPage() {
|
|
|
775
895
|
|
|
776
896
|
{/* Tags */}
|
|
777
897
|
<div className="min-w-0 space-y-1">
|
|
778
|
-
<Label className="text-xs">
|
|
898
|
+
<Label className="text-xs">{t('workflows.form.tags')}</Label>
|
|
779
899
|
<TagsInput
|
|
780
900
|
value={tags}
|
|
781
901
|
onChange={setTags}
|
|
@@ -785,7 +905,7 @@ export default function VisualEditorPage() {
|
|
|
785
905
|
|
|
786
906
|
{/* Icon */}
|
|
787
907
|
<div className="min-w-0 space-y-1">
|
|
788
|
-
<Label htmlFor="icon" className="text-xs">
|
|
908
|
+
<Label htmlFor="icon" className="text-xs">{t('workflows.form.icon')}</Label>
|
|
789
909
|
<Input
|
|
790
910
|
id="icon"
|
|
791
911
|
value={icon}
|
|
@@ -796,7 +916,7 @@ export default function VisualEditorPage() {
|
|
|
796
916
|
</div>
|
|
797
917
|
|
|
798
918
|
<div className="min-w-0 space-y-1">
|
|
799
|
-
<Label htmlFor="effectiveFrom" className="text-xs">
|
|
919
|
+
<Label htmlFor="effectiveFrom" className="text-xs">{t('workflows.form.effectiveFrom')}</Label>
|
|
800
920
|
<Input
|
|
801
921
|
id="effectiveFrom"
|
|
802
922
|
type="date"
|
|
@@ -807,7 +927,7 @@ export default function VisualEditorPage() {
|
|
|
807
927
|
</div>
|
|
808
928
|
|
|
809
929
|
<div className="min-w-0 space-y-1">
|
|
810
|
-
<Label htmlFor="effectiveTo" className="text-xs">
|
|
930
|
+
<Label htmlFor="effectiveTo" className="text-xs">{t('workflows.form.effectiveTo')}</Label>
|
|
811
931
|
<Input
|
|
812
932
|
id="effectiveTo"
|
|
813
933
|
type="date"
|
|
@@ -817,14 +937,15 @@ export default function VisualEditorPage() {
|
|
|
817
937
|
/>
|
|
818
938
|
</div>
|
|
819
939
|
</div>
|
|
820
|
-
</
|
|
821
|
-
|
|
822
|
-
{/* Event Triggers */}
|
|
823
|
-
<
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
940
|
+
</fieldset>
|
|
941
|
+
|
|
942
|
+
{/* Event Triggers — also locked when the workflow is code-defined */}
|
|
943
|
+
<fieldset disabled={isCodeOnly} className="mt-3 disabled:opacity-70">
|
|
944
|
+
<DefinitionTriggersEditor
|
|
945
|
+
value={triggers}
|
|
946
|
+
onChange={setTriggers}
|
|
947
|
+
/>
|
|
948
|
+
</fieldset>
|
|
828
949
|
</div>
|
|
829
950
|
)}
|
|
830
951
|
|
|
@@ -841,7 +962,7 @@ export default function VisualEditorPage() {
|
|
|
841
962
|
onNodeClick={handleNodeClick}
|
|
842
963
|
onEdgeClick={handleEdgeClick}
|
|
843
964
|
onConnect={handleConnect}
|
|
844
|
-
editable={
|
|
965
|
+
editable={!isCodeOnly}
|
|
845
966
|
height="100%"
|
|
846
967
|
/>
|
|
847
968
|
</div>
|
|
@@ -849,48 +970,51 @@ export default function VisualEditorPage() {
|
|
|
849
970
|
{nodes.length === 0 && (
|
|
850
971
|
<div className="pointer-events-none absolute inset-0 flex items-center justify-center px-4">
|
|
851
972
|
<div className="text-center">
|
|
852
|
-
<h2 className="mb-2 text-lg font-semibold text-foreground">
|
|
853
|
-
<p className="mb-4 text-sm text-muted-foreground">
|
|
973
|
+
<h2 className="mb-2 text-lg font-semibold text-foreground">{t('workflows.visualEditor.startBuilding')}</h2>
|
|
974
|
+
<p className="mb-4 text-sm text-muted-foreground">{t('workflows.visualEditor.tapToAddBelow')}</p>
|
|
854
975
|
<button
|
|
855
976
|
onClick={handleLoadExample}
|
|
856
977
|
className="pointer-events-auto text-sm text-primary hover:underline"
|
|
857
978
|
>
|
|
858
|
-
|
|
979
|
+
{t('workflows.visualEditor.loadExampleWorkflow')}
|
|
859
980
|
</button>
|
|
860
981
|
</div>
|
|
861
982
|
</div>
|
|
862
983
|
)}
|
|
863
984
|
</div>
|
|
864
985
|
|
|
865
|
-
|
|
866
|
-
<
|
|
867
|
-
|
|
986
|
+
{!isCodeOnly && (
|
|
987
|
+
<div className="mt-3 rounded-lg border bg-card p-3">
|
|
988
|
+
<h2 className="mb-2 text-xs font-semibold uppercase text-muted-foreground">{t('workflows.visualEditor.stepPalette')}</h2>
|
|
989
|
+
<p className="mb-3 text-xs text-muted-foreground">{t('workflows.visualEditor.tapToAdd')}</p>
|
|
868
990
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
991
|
+
<div className="flex gap-2 overflow-x-auto pb-1">
|
|
992
|
+
{(['start', 'userTask', 'automated', 'waitForSignal', 'subWorkflow', 'end'] as const).map((nodeType) => {
|
|
993
|
+
const Icon = NODE_TYPE_ICONS[nodeType]
|
|
994
|
+
return (
|
|
995
|
+
<button
|
|
996
|
+
key={nodeType}
|
|
997
|
+
onClick={() => handleAddNode(nodeType)}
|
|
998
|
+
className="flex shrink-0 items-center gap-1 rounded-md border bg-background px-2 py-1 text-xs hover:bg-muted active:bg-muted/50"
|
|
999
|
+
>
|
|
1000
|
+
<Icon className="h-3.5 w-3.5" />
|
|
1001
|
+
<span>{NODE_TYPE_LABELS[nodeType].title}</span>
|
|
1002
|
+
</button>
|
|
1003
|
+
)
|
|
1004
|
+
})}
|
|
1005
|
+
</div>
|
|
883
1006
|
</div>
|
|
884
|
-
|
|
1007
|
+
)}
|
|
885
1008
|
</div>
|
|
886
1009
|
) : (
|
|
887
1010
|
<div className="flex min-h-[72svh] min-w-0 flex-1 border-t border-border">
|
|
888
|
-
{/* Left Sidebar - Step Palette */}
|
|
1011
|
+
{/* Left Sidebar - Step Palette (hidden in read-only mode) */}
|
|
1012
|
+
{!isCodeOnly && (
|
|
889
1013
|
<div className="w-[24rem] shrink-0 overflow-y-auto border-r border-border bg-background p-6">
|
|
890
1014
|
<div className="rounded-lg border bg-card p-4">
|
|
891
|
-
<h2 className="mb-2 text-sm font-semibold uppercase text-muted-foreground">
|
|
1015
|
+
<h2 className="mb-2 text-sm font-semibold uppercase text-muted-foreground">{t('workflows.visualEditor.stepPalette')}</h2>
|
|
892
1016
|
<p className="mb-4 text-xs text-muted-foreground">
|
|
893
|
-
|
|
1017
|
+
{t('workflows.visualEditor.clickToAdd')}
|
|
894
1018
|
</p>
|
|
895
1019
|
|
|
896
1020
|
<div className="space-y-3">
|
|
@@ -1001,6 +1125,7 @@ export default function VisualEditorPage() {
|
|
|
1001
1125
|
</Alert>
|
|
1002
1126
|
</div>
|
|
1003
1127
|
</div>
|
|
1128
|
+
)}
|
|
1004
1129
|
|
|
1005
1130
|
{/* Main Canvas */}
|
|
1006
1131
|
<div className="min-w-0 flex-1 p-6">
|
|
@@ -1014,7 +1139,7 @@ export default function VisualEditorPage() {
|
|
|
1014
1139
|
onNodeClick={handleNodeClick}
|
|
1015
1140
|
onEdgeClick={handleEdgeClick}
|
|
1016
1141
|
onConnect={handleConnect}
|
|
1017
|
-
editable={
|
|
1142
|
+
editable={!isCodeOnly}
|
|
1018
1143
|
height="100%"
|
|
1019
1144
|
/>
|
|
1020
1145
|
</div>
|
|
@@ -1024,16 +1149,16 @@ export default function VisualEditorPage() {
|
|
|
1024
1149
|
<div className="pointer-events-none absolute inset-0 flex items-center justify-center px-4">
|
|
1025
1150
|
<div className="text-center">
|
|
1026
1151
|
<h2 className="mb-2 text-xl font-semibold text-foreground">
|
|
1027
|
-
|
|
1152
|
+
{t('workflows.visualEditor.startBuilding')}
|
|
1028
1153
|
</h2>
|
|
1029
1154
|
<p className="mb-4 text-muted-foreground">
|
|
1030
|
-
|
|
1155
|
+
{t('workflows.visualEditor.clickToAddFromPalette')}
|
|
1031
1156
|
</p>
|
|
1032
1157
|
<button
|
|
1033
1158
|
onClick={handleLoadExample}
|
|
1034
1159
|
className="pointer-events-auto text-sm text-primary hover:underline"
|
|
1035
1160
|
>
|
|
1036
|
-
|
|
1161
|
+
{t('workflows.visualEditor.loadExampleWorkflow')}
|
|
1037
1162
|
</button>
|
|
1038
1163
|
</div>
|
|
1039
1164
|
</div>
|