@open-mercato/core 0.4.2-canary-51881f6bf3 → 0.4.2-canary-5f415b8a44

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 (155) hide show
  1. package/dist/generated/entities/workflow_event_trigger/index.js +33 -0
  2. package/dist/generated/entities/workflow_event_trigger/index.js.map +7 -0
  3. package/dist/generated/entities.ids.generated.js +59 -58
  4. package/dist/generated/entities.ids.generated.js.map +2 -2
  5. package/dist/generated/entity-fields-registry.js +2 -0
  6. package/dist/generated/entity-fields-registry.js.map +2 -2
  7. package/dist/modules/auth/events.js +30 -0
  8. package/dist/modules/auth/events.js.map +7 -0
  9. package/dist/modules/business_rules/api/execute/[ruleId]/route.js +145 -0
  10. package/dist/modules/business_rules/api/execute/[ruleId]/route.js.map +7 -0
  11. package/dist/modules/business_rules/data/validators.js +34 -0
  12. package/dist/modules/business_rules/data/validators.js.map +2 -2
  13. package/dist/modules/business_rules/index.js +21 -1
  14. package/dist/modules/business_rules/index.js.map +2 -2
  15. package/dist/modules/business_rules/lib/rule-engine.js +182 -1
  16. package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
  17. package/dist/modules/catalog/events.js +34 -0
  18. package/dist/modules/catalog/events.js.map +7 -0
  19. package/dist/modules/customers/events.js +49 -0
  20. package/dist/modules/customers/events.js.map +7 -0
  21. package/dist/modules/directory/events.js +23 -0
  22. package/dist/modules/directory/events.js.map +7 -0
  23. package/dist/modules/sales/acl.js +1 -0
  24. package/dist/modules/sales/acl.js.map +2 -2
  25. package/dist/modules/sales/backend/sales/documents/[id]/page.js +12 -0
  26. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  27. package/dist/modules/sales/commands/documents.js +62 -0
  28. package/dist/modules/sales/commands/documents.js.map +2 -2
  29. package/dist/modules/sales/events.js +63 -0
  30. package/dist/modules/sales/events.js.map +7 -0
  31. package/dist/modules/sales/lib/dictionaries.js +3 -0
  32. package/dist/modules/sales/lib/dictionaries.js.map +2 -2
  33. package/dist/modules/sales/lib/frontend/documentDataEvents.js +25 -0
  34. package/dist/modules/sales/lib/frontend/documentDataEvents.js.map +7 -0
  35. package/dist/modules/workflows/acl.js +2 -0
  36. package/dist/modules/workflows/acl.js.map +2 -2
  37. package/dist/modules/workflows/api/instances/route.js +18 -6
  38. package/dist/modules/workflows/api/instances/route.js.map +2 -2
  39. package/dist/modules/workflows/api/tasks/route.js +6 -1
  40. package/dist/modules/workflows/api/tasks/route.js.map +2 -2
  41. package/dist/modules/workflows/backend/definitions/[id]/page.js +9 -1
  42. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  43. package/dist/modules/workflows/backend/definitions/[id]/page.meta.js +1 -1
  44. package/dist/modules/workflows/backend/definitions/[id]/page.meta.js.map +2 -2
  45. package/dist/modules/workflows/backend/definitions/create/page.js +24 -15
  46. package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
  47. package/dist/modules/workflows/backend/definitions/create/page.meta.js +1 -1
  48. package/dist/modules/workflows/backend/definitions/create/page.meta.js.map +2 -2
  49. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +150 -132
  50. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  51. package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js +1 -1
  52. package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js.map +2 -2
  53. package/dist/modules/workflows/backend/events/[id]/page.js +1 -1
  54. package/dist/modules/workflows/backend/events/[id]/page.js.map +2 -2
  55. package/dist/modules/workflows/backend/events/[id]/page.meta.js +2 -2
  56. package/dist/modules/workflows/backend/events/[id]/page.meta.js.map +2 -2
  57. package/dist/modules/workflows/backend/instances/[id]/page.meta.js +2 -2
  58. package/dist/modules/workflows/backend/instances/[id]/page.meta.js.map +2 -2
  59. package/dist/modules/workflows/backend/tasks/[id]/page.js +1 -1
  60. package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
  61. package/dist/modules/workflows/backend/tasks/[id]/page.meta.js +2 -2
  62. package/dist/modules/workflows/backend/tasks/[id]/page.meta.js.map +2 -2
  63. package/dist/modules/workflows/backend/tasks/page.js +5 -6
  64. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  65. package/dist/modules/workflows/cli.js +81 -3
  66. package/dist/modules/workflows/cli.js.map +3 -3
  67. package/dist/modules/workflows/components/DefinitionTriggersEditor.js +481 -0
  68. package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +7 -0
  69. package/dist/modules/workflows/components/EventTriggersEditor.js +553 -0
  70. package/dist/modules/workflows/components/EventTriggersEditor.js.map +7 -0
  71. package/dist/modules/workflows/data/entities.js +64 -1
  72. package/dist/modules/workflows/data/entities.js.map +2 -2
  73. package/dist/modules/workflows/data/validators.js +115 -0
  74. package/dist/modules/workflows/data/validators.js.map +2 -2
  75. package/dist/modules/workflows/events.js +38 -0
  76. package/dist/modules/workflows/events.js.map +7 -0
  77. package/dist/modules/workflows/examples/checkout-demo-definition.json +1 -5
  78. package/dist/modules/workflows/examples/order-approval-definition.json +257 -0
  79. package/dist/modules/workflows/examples/order-approval-guard-rules.json +32 -0
  80. package/dist/modules/workflows/lib/activity-executor.js +75 -13
  81. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  82. package/dist/modules/workflows/lib/event-trigger-service.js +308 -0
  83. package/dist/modules/workflows/lib/event-trigger-service.js.map +7 -0
  84. package/dist/modules/workflows/lib/graph-utils.js +71 -2
  85. package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
  86. package/dist/modules/workflows/lib/seeds.js +22 -5
  87. package/dist/modules/workflows/lib/seeds.js.map +2 -2
  88. package/dist/modules/workflows/lib/start-validator.js +33 -23
  89. package/dist/modules/workflows/lib/start-validator.js.map +2 -2
  90. package/dist/modules/workflows/lib/transition-handler.js +157 -45
  91. package/dist/modules/workflows/lib/transition-handler.js.map +3 -3
  92. package/dist/modules/workflows/migrations/Migration20260123143500.js +36 -0
  93. package/dist/modules/workflows/migrations/Migration20260123143500.js.map +7 -0
  94. package/dist/modules/workflows/subscribers/event-trigger.js +78 -0
  95. package/dist/modules/workflows/subscribers/event-trigger.js.map +7 -0
  96. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +323 -0
  97. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +7 -0
  98. package/dist/modules/workflows/widgets/injection/order-approval/widget.js +17 -0
  99. package/dist/modules/workflows/widgets/injection/order-approval/widget.js.map +7 -0
  100. package/dist/modules/workflows/widgets/injection-table.js +19 -0
  101. package/dist/modules/workflows/widgets/injection-table.js.map +7 -0
  102. package/generated/entities/workflow_event_trigger/index.ts +15 -0
  103. package/generated/entities.ids.generated.ts +59 -58
  104. package/generated/entity-fields-registry.ts +2 -0
  105. package/package.json +3 -5
  106. package/src/modules/auth/events.ts +39 -0
  107. package/src/modules/business_rules/api/execute/[ruleId]/route.ts +163 -0
  108. package/src/modules/business_rules/data/validators.ts +40 -0
  109. package/src/modules/business_rules/index.ts +25 -0
  110. package/src/modules/business_rules/lib/rule-engine.ts +281 -1
  111. package/src/modules/catalog/events.ts +45 -0
  112. package/src/modules/customers/events.ts +63 -0
  113. package/src/modules/directory/events.ts +31 -0
  114. package/src/modules/sales/acl.ts +1 -0
  115. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +16 -0
  116. package/src/modules/sales/commands/documents.ts +74 -1
  117. package/src/modules/sales/events.ts +82 -0
  118. package/src/modules/sales/lib/dictionaries.ts +3 -0
  119. package/src/modules/sales/lib/frontend/documentDataEvents.ts +28 -0
  120. package/src/modules/workflows/acl.ts +2 -0
  121. package/src/modules/workflows/api/instances/route.ts +21 -7
  122. package/src/modules/workflows/api/tasks/route.ts +7 -1
  123. package/src/modules/workflows/backend/definitions/[id]/page.meta.ts +1 -1
  124. package/src/modules/workflows/backend/definitions/[id]/page.tsx +9 -0
  125. package/src/modules/workflows/backend/definitions/create/page.meta.ts +1 -1
  126. package/src/modules/workflows/backend/definitions/create/page.tsx +9 -0
  127. package/src/modules/workflows/backend/definitions/visual-editor/page.meta.ts +1 -1
  128. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +21 -3
  129. package/src/modules/workflows/backend/events/[id]/page.meta.ts +2 -2
  130. package/src/modules/workflows/backend/events/[id]/page.tsx +1 -1
  131. package/src/modules/workflows/backend/instances/[id]/page.meta.ts +2 -2
  132. package/src/modules/workflows/backend/tasks/[id]/page.meta.ts +2 -2
  133. package/src/modules/workflows/backend/tasks/[id]/page.tsx +1 -1
  134. package/src/modules/workflows/backend/tasks/page.tsx +5 -6
  135. package/src/modules/workflows/cli.ts +111 -0
  136. package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +581 -0
  137. package/src/modules/workflows/components/EventTriggersEditor.tsx +664 -0
  138. package/src/modules/workflows/data/entities.ts +124 -0
  139. package/src/modules/workflows/data/validators.ts +138 -0
  140. package/src/modules/workflows/events.ts +49 -0
  141. package/src/modules/workflows/examples/checkout-demo-definition.json +1 -5
  142. package/src/modules/workflows/examples/order-approval-definition.json +257 -0
  143. package/src/modules/workflows/examples/order-approval-guard-rules.json +32 -0
  144. package/src/modules/workflows/i18n/en.json +71 -0
  145. package/src/modules/workflows/lib/activity-executor.ts +129 -16
  146. package/src/modules/workflows/lib/event-trigger-service.ts +557 -0
  147. package/src/modules/workflows/lib/graph-utils.ts +117 -2
  148. package/src/modules/workflows/lib/seeds.ts +34 -8
  149. package/src/modules/workflows/lib/start-validator.ts +38 -28
  150. package/src/modules/workflows/lib/transition-handler.ts +208 -55
  151. package/src/modules/workflows/migrations/Migration20260123143500.ts +38 -0
  152. package/src/modules/workflows/subscribers/event-trigger.ts +109 -0
  153. package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +446 -0
  154. package/src/modules/workflows/widgets/injection/order-approval/widget.ts +16 -0
  155. package/src/modules/workflows/widgets/injection-table.ts +21 -0
@@ -0,0 +1,28 @@
1
+ "use client"
2
+
3
+ export const SALES_DOCUMENT_DATA_REFRESH_EVENT = 'sales:document:data:refresh'
4
+
5
+ export type SalesDocumentDataRefreshDetail = {
6
+ documentId: string
7
+ kind?: 'order' | 'quote'
8
+ }
9
+
10
+ export function emitSalesDocumentDataRefresh(detail: SalesDocumentDataRefreshDetail): void {
11
+ if (typeof window === 'undefined' || typeof CustomEvent === 'undefined') return
12
+ window.dispatchEvent(
13
+ new CustomEvent<SalesDocumentDataRefreshDetail>(SALES_DOCUMENT_DATA_REFRESH_EVENT, { detail }),
14
+ )
15
+ }
16
+
17
+ export function subscribeSalesDocumentDataRefresh(
18
+ handler: (detail: SalesDocumentDataRefreshDetail) => void,
19
+ ): () => void {
20
+ if (typeof window === 'undefined') return () => {}
21
+ const listener = (event: Event) => {
22
+ const detail = (event as CustomEvent<SalesDocumentDataRefreshDetail>).detail
23
+ if (!detail) return
24
+ handler(detail)
25
+ }
26
+ window.addEventListener(SALES_DOCUMENT_DATA_REFRESH_EVENT, listener as EventListener)
27
+ return () => window.removeEventListener(SALES_DOCUMENT_DATA_REFRESH_EVENT, listener as EventListener)
28
+ }
@@ -19,6 +19,8 @@ export const features = [
19
19
  { id: 'workflows.tasks.complete', title: 'Complete workflow tasks', module: moduleId },
20
20
  { id: 'workflows.signals.send', title: 'Send workflow signals', module: moduleId },
21
21
  { id: 'workflows.events.view', title: 'View workflow events', module: moduleId },
22
+ // Note: Event triggers are now embedded in workflow definitions.
23
+ // Trigger management permissions are covered by workflows.definitions.edit
22
24
  ]
23
25
 
24
26
  export default features
@@ -70,19 +70,33 @@ export async function GET(request: NextRequest) {
70
70
  }
71
71
 
72
72
  if (status) {
73
- where.status = status
73
+ // Support comma-separated status values (e.g., "RUNNING,PAUSED,WAITING_FOR_ACTIVITIES")
74
+ const statuses = status.split(',').map(s => s.trim()).filter(Boolean)
75
+ if (statuses.length === 1) {
76
+ where.status = statuses[0]
77
+ } else if (statuses.length > 1) {
78
+ where.status = { $in: statuses }
79
+ }
74
80
  }
75
81
 
76
82
  if (correlationKey) {
77
83
  where.correlationKey = correlationKey
78
84
  }
79
85
 
80
- if (entityType) {
81
- where['metadata.entityType'] = entityType
82
- }
83
-
84
- if (entityId) {
85
- where['metadata.entityId'] = entityId
86
+ // For JSONB metadata filtering, use $contains with explicit key-value pairs
87
+ // MikroORM's dot notation creates table joins, not JSON access
88
+ if (entityType || entityId) {
89
+ where.$and = where.$and || []
90
+ if (entityType) {
91
+ where.$and.push({
92
+ metadata: { $contains: { entityType: entityType } }
93
+ })
94
+ }
95
+ if (entityId) {
96
+ where.$and.push({
97
+ metadata: { $contains: { entityId: entityId } }
98
+ })
99
+ }
86
100
  }
87
101
 
88
102
  const [instances, total] = await em.findAndCount(
@@ -67,7 +67,13 @@ export async function GET(request: NextRequest) {
67
67
  }
68
68
 
69
69
  if (status) {
70
- where.status = status
70
+ // Handle comma-separated status values
71
+ const statusValues = status.split(',').map(s => s.trim()).filter(Boolean)
72
+ if (statusValues.length === 1) {
73
+ where.status = statusValues[0]
74
+ } else if (statusValues.length > 1) {
75
+ where.status = { $in: statusValues }
76
+ }
71
77
  }
72
78
 
73
79
  if (assignedTo) {
@@ -4,7 +4,7 @@ export const metadata = {
4
4
  pageTitle: 'Edit Workflow Definition',
5
5
  pageTitleKey: 'workflows.edit.title',
6
6
  breadcrumb: [
7
- { label: 'Workflows', labelKey: 'workflows.module.name', href: '/backend/workflows/definitions' },
7
+ { label: 'Workflows', labelKey: 'workflows.module.name', href: '/backend/definitions' },
8
8
  { label: 'Edit', labelKey: 'workflows.common.edit' },
9
9
  ],
10
10
  }
@@ -19,6 +19,7 @@ import {
19
19
  } from '../../../components/formConfig'
20
20
  import { StepsEditor } from '../../../components/StepsEditor'
21
21
  import { TransitionsEditor } from '../../../components/TransitionsEditor'
22
+ import { EventTriggersEditor } from '../../../components/EventTriggersEditor'
22
23
 
23
24
  export default function EditWorkflowDefinitionPage() {
24
25
  const router = useRouter()
@@ -145,6 +146,14 @@ export default function EditWorkflowDefinitionPage() {
145
146
  groups={formGroups}
146
147
  submitLabel={t('workflows.form.update')}
147
148
  />
149
+
150
+ {/* Event Triggers Section */}
151
+ <div className="mt-8">
152
+ <EventTriggersEditor
153
+ workflowDefinitionId={definitionId!}
154
+ workflowId={definition?.workflowId}
155
+ />
156
+ </div>
148
157
  </PageBody>
149
158
  </Page>
150
159
  )
@@ -20,7 +20,7 @@ export const metadata = {
20
20
  pageOrder: 100,
21
21
  icon: createIcon,
22
22
  breadcrumb: [
23
- { label: 'Workflows', labelKey: 'workflows.module.name', href: '/backend/workflows/definitions' },
23
+ { label: 'Workflows', labelKey: 'workflows.module.name', href: '/backend/definitions' },
24
24
  { label: 'Create', labelKey: 'workflows.common.create' },
25
25
  ],
26
26
  }
@@ -16,6 +16,8 @@ import {
16
16
  } from '../../../components/formConfig'
17
17
  import { StepsEditor } from '../../../components/StepsEditor'
18
18
  import { TransitionsEditor } from '../../../components/TransitionsEditor'
19
+ import { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'
20
+ import { Zap } from 'lucide-react'
19
21
 
20
22
  export default function CreateWorkflowDefinitionPage() {
21
23
  const router = useRouter()
@@ -50,6 +52,13 @@ export default function CreateWorkflowDefinitionPage() {
50
52
  return (
51
53
  <Page>
52
54
  <PageBody>
55
+ <Alert variant="info" className="mb-6">
56
+ <Zap className="w-4 h-4" />
57
+ <AlertTitle>Event Triggers</AlertTitle>
58
+ <AlertDescription>
59
+ After creating this workflow definition, you can configure event triggers to automatically start the workflow when specific events occur in the system.
60
+ </AlertDescription>
61
+ </Alert>
53
62
  <CrudForm
54
63
  title={t('workflows.create.title')}
55
64
  backHref="/backend/definitions"
@@ -19,7 +19,7 @@ export const metadata = {
19
19
  pageOrder: 150,
20
20
  icon: visualEditorIcon,
21
21
  breadcrumb: [
22
- { label: 'Workflows', labelKey: 'workflows.module.name', href: '/backend/workflows/definitions' },
22
+ { label: 'Workflows', labelKey: 'workflows.module.name', href: '/backend/definitions' },
23
23
  { label: 'Visual Editor', labelKey: 'workflows.backend.definitions.visual_editor.title' },
24
24
  ],
25
25
  }
@@ -34,6 +34,8 @@ import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
34
34
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
35
35
  import {CircleQuestionMark, Info, PanelTopClose, PanelTopOpen, Play, Save, Trash2} from 'lucide-react'
36
36
  import { NODE_TYPE_ICONS, NODE_TYPE_COLORS, NODE_TYPE_LABELS } from '../../../lib/node-type-icons'
37
+ import { DefinitionTriggersEditor } from '../../../components/DefinitionTriggersEditor'
38
+ import type { WorkflowDefinitionTrigger } from '../../../data/entities'
37
39
  import * as React from "react";
38
40
 
39
41
  /**
@@ -76,6 +78,7 @@ export default function VisualEditorPage() {
76
78
  const [icon, setIcon] = useState('')
77
79
  const [effectiveFrom, setEffectiveFrom] = useState('')
78
80
  const [effectiveTo, setEffectiveTo] = useState('')
81
+ const [triggers, setTriggers] = useState<WorkflowDefinitionTrigger[]>([])
79
82
 
80
83
  // Load existing definition if ID is provided
81
84
  useEffect(() => {
@@ -113,6 +116,9 @@ export default function VisualEditorPage() {
113
116
  setNodes(graph.nodes)
114
117
  setEdges(graph.edges)
115
118
 
119
+ // Load embedded triggers from definition
120
+ setTriggers(definition.definition?.triggers || [])
121
+
116
122
  flash('Workflow loaded successfully', 'success')
117
123
  } catch (error) {
118
124
  console.error('Error loading workflow definition:', error)
@@ -284,8 +290,12 @@ export default function VisualEditorPage() {
284
290
  return
285
291
  }
286
292
 
287
- // Generate definition data
288
- const definitionData = graphToDefinition(nodes, edges, { includePositions: true })
293
+ // Generate definition data and include triggers
294
+ const graphDefinition = graphToDefinition(nodes, edges, { includePositions: true })
295
+ const definitionData = {
296
+ ...graphDefinition,
297
+ triggers: triggers.length > 0 ? triggers : undefined,
298
+ }
289
299
 
290
300
  // Run Zod schema validation before saving
291
301
  const schemaResult = workflowDefinitionDataSchema.safeParse(definitionData)
@@ -357,7 +367,7 @@ export default function VisualEditorPage() {
357
367
  } finally {
358
368
  setIsSaving(false)
359
369
  }
360
- }, [nodes, edges, workflowId, workflowName, description, version, enabled, category, tags, definitionId, router])
370
+ }, [nodes, edges, workflowId, workflowName, description, version, enabled, category, tags, triggers, definitionId, router])
361
371
 
362
372
  // Test workflow
363
373
  const handleTest = useCallback(() => {
@@ -475,6 +485,7 @@ export default function VisualEditorPage() {
475
485
  setIcon('')
476
486
  setEffectiveFrom('')
477
487
  setEffectiveTo('')
488
+ setTriggers([])
478
489
  setShowClearConfirm(false)
479
490
  flash('Canvas cleared', 'success')
480
491
  }, [])
@@ -709,6 +720,13 @@ export default function VisualEditorPage() {
709
720
  </div>
710
721
  </div>
711
722
  </div>
723
+
724
+ {/* Event Triggers - Always visible, managed as part of definition */}
725
+ <DefinitionTriggersEditor
726
+ value={triggers}
727
+ onChange={setTriggers}
728
+ className="mt-4"
729
+ />
712
730
  </div>
713
731
  )}
714
732
 
@@ -4,8 +4,8 @@ export const metadata = {
4
4
  pageTitle: 'Event Details',
5
5
  pageTitleKey: 'workflows.events.detail.title',
6
6
  breadcrumb: [
7
- { label: 'Workflows', labelKey: 'workflows.module.name', href: '/backend/workflows/definitions' },
8
- { label: 'Events', labelKey: 'workflows.events.plural', href: '/backend/workflows/events' },
7
+ { label: 'Workflows', labelKey: 'workflows.module.name', href: '/backend/definitions' },
8
+ { label: 'Events', labelKey: 'workflows.events.plural', href: '/backend/events' },
9
9
  { label: 'Details', labelKey: 'common.details' },
10
10
  ],
11
11
  }
@@ -212,7 +212,7 @@ export default function WorkflowEventDetailPage() {
212
212
  </dt>
213
213
  <dd className="mt-1">
214
214
  <Link
215
- href={`/backend/workflows/instances/${event.workflowInstance.id}`}
215
+ href={`/backend/instances/${event.workflowInstance.id}`}
216
216
  className="text-sm text-primary hover:underline font-mono"
217
217
  >
218
218
  {event.workflowInstance.id}
@@ -4,8 +4,8 @@ export const metadata = {
4
4
  pageTitle: 'Workflow Instance Details',
5
5
  pageTitleKey: 'workflows.instances.singular',
6
6
  breadcrumb: [
7
- { label: 'Workflows', labelKey: 'workflows.module.name', href: '/backend/workflows/definitions' },
8
- { label: 'Instances', labelKey: 'workflows.instances.plural', href: '/backend/workflows/instances' },
7
+ { label: 'Workflows', labelKey: 'workflows.module.name', href: '/backend/definitions' },
8
+ { label: 'Instances', labelKey: 'workflows.instances.plural', href: '/backend/instances' },
9
9
  { label: 'Details', labelKey: 'common.details' },
10
10
  ],
11
11
  }
@@ -4,8 +4,8 @@ export const metadata = {
4
4
  pageTitle: 'Task Details',
5
5
  pageTitleKey: 'workflows.tasks.singular',
6
6
  breadcrumb: [
7
- { label: 'Workflows', labelKey: 'workflows.module.name', href: '/backend/workflows/definitions' },
8
- { label: 'Tasks', labelKey: 'workflows.tasks.plural', href: '/backend/workflows/tasks' },
7
+ { label: 'Workflows', labelKey: 'workflows.module.name', href: '/backend/definitions' },
8
+ { label: 'Tasks', labelKey: 'workflows.tasks.plural', href: '/backend/tasks' },
9
9
  { label: 'Details', labelKey: 'common.details' },
10
10
  ],
11
11
  }
@@ -381,7 +381,7 @@ export default function UserTaskDetailPage({ params }: { params: { id: string }
381
381
  task.status
382
382
  )}`}
383
383
  >
384
- {t(`workflows.tasks.status.${task.status}`)}
384
+ {t(`workflows.tasks.statuses.${task.status}`)}
385
385
  </span>
386
386
  </div>
387
387
 
@@ -72,7 +72,6 @@ export default function UserTasksListPage() {
72
72
  params.set('offset', offset.toString())
73
73
 
74
74
  if (filterValues.status) params.set('status', filterValues.status as string)
75
- if (filterValues.myTasks === 'true') params.set('myTasks', 'true')
76
75
  if (filterValues.overdue === 'true') params.set('overdue', 'true')
77
76
  if (filterValues.workflowInstanceId) params.set('workflowInstanceId', filterValues.workflowInstanceId as string)
78
77
 
@@ -155,10 +154,10 @@ export default function UserTasksListPage() {
155
154
  label: t('workflows.tasks.filters.status'),
156
155
  options: [
157
156
  { label: t('common.all'), value: '' },
158
- { label: t('workflows.tasks.status.PENDING'), value: 'PENDING' },
159
- { label: t('workflows.tasks.status.IN_PROGRESS'), value: 'IN_PROGRESS' },
160
- { label: t('workflows.tasks.status.COMPLETED'), value: 'COMPLETED' },
161
- { label: t('workflows.tasks.status.CANCELLED'), value: 'CANCELLED' },
157
+ { label: t('workflows.tasks.statuses.PENDING'), value: 'PENDING' },
158
+ { label: t('workflows.tasks.statuses.IN_PROGRESS'), value: 'IN_PROGRESS' },
159
+ { label: t('workflows.tasks.statuses.COMPLETED'), value: 'COMPLETED' },
160
+ { label: t('workflows.tasks.statuses.CANCELLED'), value: 'CANCELLED' },
162
161
  ],
163
162
  },
164
163
  {
@@ -214,7 +213,7 @@ export default function UserTasksListPage() {
214
213
  accessorKey: 'status',
215
214
  cell: ({ row }) => (
216
215
  <span className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium ${getStatusBadgeClass(row.original.status)}`}>
217
- {t(`workflows.tasks.status.${row.original.status}`)}
216
+ {t(`workflows.tasks.statuses.${row.original.status}`)}
218
217
  </span>
219
218
  ),
220
219
  },
@@ -2,6 +2,7 @@ import type { ModuleCli } from '@open-mercato/shared/modules/registry'
2
2
  import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
3
3
  import type { EntityManager } from '@mikro-orm/postgresql'
4
4
  import { WorkflowDefinition } from './data/entities'
5
+ import { BusinessRule, type RuleType } from '@open-mercato/core/modules/business_rules/data/entities'
5
6
  import * as fs from 'fs'
6
7
  import * as path from 'path'
7
8
  import { fileURLToPath } from 'url'
@@ -283,6 +284,111 @@ const seedSimpleApproval: ModuleCli = {
283
284
  },
284
285
  }
285
286
 
287
+ /**
288
+ * Seed order approval example
289
+ */
290
+ const seedOrderApproval: ModuleCli = {
291
+ command: 'seed-order-approval',
292
+ async run(rest: string[]) {
293
+ const args = parseArgs(rest)
294
+ const tenantId = String(args.tenantId ?? args.tenant ?? args.t ?? '')
295
+ const organizationId = String(args.organizationId ?? args.orgId ?? args.org ?? args.o ?? '')
296
+
297
+ if (!tenantId || !organizationId) {
298
+ console.error('Usage: mercato workflows seed-order-approval --tenant <tenantId> --org <organizationId>')
299
+ return
300
+ }
301
+
302
+ try {
303
+ const { resolve } = await createRequestContainer()
304
+ const em = resolve<EntityManager>('em')
305
+
306
+ // 1. Seed order approval guard rules first
307
+ const guardRulesPath = path.join(__dirname, 'examples', 'order-approval-guard-rules.json')
308
+ const guardRulesData = JSON.parse(fs.readFileSync(guardRulesPath, 'utf8')) as Array<{
309
+ ruleId: string
310
+ ruleName: string
311
+ ruleType: RuleType
312
+ entityType: string
313
+ description?: string
314
+ eventType?: string
315
+ conditionExpression?: Record<string, unknown>
316
+ enabled?: boolean
317
+ priority?: number
318
+ }>
319
+
320
+ let rulesSeeded = 0
321
+ let rulesSkipped = 0
322
+ for (const rule of guardRulesData) {
323
+ const existingRule = await em.findOne(BusinessRule, {
324
+ ruleId: rule.ruleId,
325
+ tenantId,
326
+ organizationId,
327
+ })
328
+
329
+ if (existingRule) {
330
+ rulesSkipped++
331
+ continue
332
+ }
333
+
334
+ const newRule = em.create(BusinessRule, {
335
+ ...rule,
336
+ tenantId,
337
+ organizationId,
338
+ })
339
+ em.persist(newRule)
340
+ console.log(` ✓ Seeded guard rule: ${rule.ruleName}`)
341
+ rulesSeeded++
342
+ }
343
+
344
+ if (rulesSeeded > 0) {
345
+ await em.flush()
346
+ }
347
+
348
+ // 2. Read the order approval workflow definition
349
+ const approvalPath = path.join(__dirname, 'examples', 'order-approval-definition.json')
350
+ const approvalData = JSON.parse(fs.readFileSync(approvalPath, 'utf8'))
351
+
352
+ // Check if it already exists
353
+ const existing = await em.findOne(WorkflowDefinition, {
354
+ workflowId: approvalData.workflowId,
355
+ tenantId,
356
+ organizationId,
357
+ })
358
+
359
+ if (existing) {
360
+ console.log(`✓ Order approval workflow '${approvalData.workflowId}' already exists (ID: ${existing.id})`)
361
+ console.log(` - Guard rules seeded: ${rulesSeeded}`)
362
+ console.log(` - Guard rules skipped: ${rulesSkipped}`)
363
+ return
364
+ }
365
+
366
+ // Create the workflow definition
367
+ const workflow = em.create(WorkflowDefinition, {
368
+ ...approvalData,
369
+ tenantId,
370
+ organizationId,
371
+ })
372
+
373
+ await em.persistAndFlush(workflow)
374
+
375
+ console.log(`✓ Seeded order approval workflow: ${workflow.workflowName}`)
376
+ console.log(` - ID: ${workflow.id}`)
377
+ console.log(` - Workflow ID: ${workflow.workflowId}`)
378
+ console.log(` - Version: ${workflow.version}`)
379
+ console.log(` - Steps: ${workflow.definition.steps.length}`)
380
+ console.log(` - Transitions: ${workflow.definition.transitions.length}`)
381
+ console.log(` - Guard rules seeded: ${rulesSeeded}`)
382
+ console.log(` - Guard rules skipped: ${rulesSkipped}`)
383
+ console.log('')
384
+ console.log('Order approval workflow is ready!')
385
+ } catch (error) {
386
+ console.error('Error seeding order approval workflow:', error)
387
+ throw error
388
+ }
389
+ },
390
+ }
391
+
286
392
  /**
287
393
  * Start workflow activity worker
288
394
  */
@@ -366,6 +472,10 @@ const seedAll: ModuleCli = {
366
472
  await seedSimpleApproval.run(rest)
367
473
  console.log('')
368
474
 
475
+ // Seed order approval
476
+ await seedOrderApproval.run(rest)
477
+ console.log('')
478
+
369
479
  console.log('✓ All example workflows seeded successfully!')
370
480
  } catch (error) {
371
481
  console.error('Error seeding workflows:', error)
@@ -444,6 +554,7 @@ const workflowsCliCommands = [
444
554
  seedDemoWithRules,
445
555
  seedSalesPipeline,
446
556
  seedSimpleApproval,
557
+ seedOrderApproval,
447
558
  seedAll,
448
559
  ]
449
560