@open-mercato/core 0.4.2-canary-5d2c419a9b → 0.4.2-canary-9e0237de8e
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/dist/generated/entities/workflow_event_trigger/index.js +33 -0
- package/dist/generated/entities/workflow_event_trigger/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +1 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/auth/events.js +30 -0
- package/dist/modules/auth/events.js.map +7 -0
- package/dist/modules/business_rules/api/execute/[ruleId]/route.js +145 -0
- package/dist/modules/business_rules/api/execute/[ruleId]/route.js.map +7 -0
- package/dist/modules/business_rules/data/validators.js +34 -0
- package/dist/modules/business_rules/data/validators.js.map +2 -2
- package/dist/modules/business_rules/index.js +21 -1
- package/dist/modules/business_rules/index.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-engine.js +182 -1
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/catalog/events.js +34 -0
- package/dist/modules/catalog/events.js.map +7 -0
- package/dist/modules/customers/events.js +49 -0
- package/dist/modules/customers/events.js.map +7 -0
- package/dist/modules/directory/events.js +23 -0
- package/dist/modules/directory/events.js.map +7 -0
- package/dist/modules/sales/acl.js +1 -0
- package/dist/modules/sales/acl.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +12 -0
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +62 -0
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/events.js +63 -0
- package/dist/modules/sales/events.js.map +7 -0
- package/dist/modules/sales/lib/dictionaries.js +3 -0
- package/dist/modules/sales/lib/dictionaries.js.map +2 -2
- package/dist/modules/sales/lib/frontend/documentDataEvents.js +25 -0
- package/dist/modules/sales/lib/frontend/documentDataEvents.js.map +7 -0
- package/dist/modules/workflows/acl.js +2 -0
- package/dist/modules/workflows/acl.js.map +2 -2
- package/dist/modules/workflows/api/instances/route.js +18 -6
- package/dist/modules/workflows/api/instances/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/route.js +6 -1
- package/dist/modules/workflows/api/tasks/route.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.js +9 -1
- package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.meta.js +1 -1
- package/dist/modules/workflows/backend/definitions/[id]/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/create/page.js +24 -15
- package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/create/page.meta.js +1 -1
- package/dist/modules/workflows/backend/definitions/create/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +150 -132
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js +1 -1
- package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/events/[id]/page.js +1 -1
- package/dist/modules/workflows/backend/events/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/events/[id]/page.meta.js +2 -2
- package/dist/modules/workflows/backend/events/[id]/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/instances/[id]/page.meta.js +2 -2
- package/dist/modules/workflows/backend/instances/[id]/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.js +1 -1
- package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.meta.js +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +5 -6
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/cli.js +81 -3
- package/dist/modules/workflows/cli.js.map +3 -3
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +481 -0
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +7 -0
- package/dist/modules/workflows/components/EventTriggersEditor.js +553 -0
- package/dist/modules/workflows/components/EventTriggersEditor.js.map +7 -0
- package/dist/modules/workflows/data/entities.js +64 -1
- package/dist/modules/workflows/data/entities.js.map +2 -2
- package/dist/modules/workflows/data/validators.js +115 -0
- package/dist/modules/workflows/data/validators.js.map +2 -2
- package/dist/modules/workflows/events.js +38 -0
- package/dist/modules/workflows/events.js.map +7 -0
- package/dist/modules/workflows/examples/checkout-demo-definition.json +1 -5
- package/dist/modules/workflows/examples/order-approval-definition.json +257 -0
- package/dist/modules/workflows/examples/order-approval-guard-rules.json +32 -0
- package/dist/modules/workflows/lib/activity-executor.js +75 -13
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/event-trigger-service.js +308 -0
- package/dist/modules/workflows/lib/event-trigger-service.js.map +7 -0
- package/dist/modules/workflows/lib/graph-utils.js +71 -2
- package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
- package/dist/modules/workflows/lib/seeds.js +17 -4
- package/dist/modules/workflows/lib/seeds.js.map +2 -2
- package/dist/modules/workflows/lib/start-validator.js +33 -23
- package/dist/modules/workflows/lib/start-validator.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +157 -45
- package/dist/modules/workflows/lib/transition-handler.js.map +3 -3
- package/dist/modules/workflows/migrations/Migration20260123143500.js +36 -0
- package/dist/modules/workflows/migrations/Migration20260123143500.js.map +7 -0
- package/dist/modules/workflows/subscribers/event-trigger.js +78 -0
- package/dist/modules/workflows/subscribers/event-trigger.js.map +7 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +323 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +7 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.js +17 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.js.map +7 -0
- package/dist/modules/workflows/widgets/injection-table.js +19 -0
- package/dist/modules/workflows/widgets/injection-table.js.map +7 -0
- package/generated/entities/workflow_event_trigger/index.ts +15 -0
- package/generated/entities.ids.generated.ts +1 -0
- package/generated/entity-fields-registry.ts +2 -0
- package/package.json +2 -2
- package/src/modules/auth/events.ts +39 -0
- package/src/modules/business_rules/api/execute/[ruleId]/route.ts +163 -0
- package/src/modules/business_rules/data/validators.ts +40 -0
- package/src/modules/business_rules/index.ts +25 -0
- package/src/modules/business_rules/lib/rule-engine.ts +281 -1
- package/src/modules/catalog/events.ts +45 -0
- package/src/modules/customers/events.ts +63 -0
- package/src/modules/directory/events.ts +31 -0
- package/src/modules/sales/acl.ts +1 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +16 -0
- package/src/modules/sales/commands/documents.ts +75 -1
- package/src/modules/sales/events.ts +82 -0
- package/src/modules/sales/lib/dictionaries.ts +3 -0
- package/src/modules/sales/lib/frontend/documentDataEvents.ts +28 -0
- package/src/modules/workflows/acl.ts +2 -0
- package/src/modules/workflows/api/__tests__/instances.route.test.ts +5 -2
- package/src/modules/workflows/api/instances/route.ts +21 -7
- package/src/modules/workflows/api/tasks/route.ts +7 -1
- package/src/modules/workflows/backend/definitions/[id]/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/[id]/page.tsx +9 -0
- package/src/modules/workflows/backend/definitions/create/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/create/page.tsx +9 -0
- package/src/modules/workflows/backend/definitions/visual-editor/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +21 -3
- package/src/modules/workflows/backend/events/[id]/page.meta.ts +2 -2
- package/src/modules/workflows/backend/events/[id]/page.tsx +1 -1
- package/src/modules/workflows/backend/instances/[id]/page.meta.ts +2 -2
- package/src/modules/workflows/backend/tasks/[id]/page.meta.ts +2 -2
- package/src/modules/workflows/backend/tasks/[id]/page.tsx +1 -1
- package/src/modules/workflows/backend/tasks/page.tsx +5 -6
- package/src/modules/workflows/cli.ts +111 -0
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +581 -0
- package/src/modules/workflows/components/EventTriggersEditor.tsx +664 -0
- package/src/modules/workflows/data/entities.ts +124 -0
- package/src/modules/workflows/data/validators.ts +138 -0
- package/src/modules/workflows/events.ts +49 -0
- package/src/modules/workflows/examples/checkout-demo-definition.json +1 -5
- package/src/modules/workflows/examples/order-approval-definition.json +257 -0
- package/src/modules/workflows/examples/order-approval-guard-rules.json +32 -0
- package/src/modules/workflows/i18n/en.json +71 -0
- package/src/modules/workflows/lib/__tests__/activity-executor.test.ts +43 -36
- package/src/modules/workflows/lib/__tests__/transition-handler.test.ts +170 -90
- package/src/modules/workflows/lib/activity-executor.ts +129 -16
- package/src/modules/workflows/lib/event-trigger-service.ts +557 -0
- package/src/modules/workflows/lib/graph-utils.ts +117 -2
- package/src/modules/workflows/lib/seeds.ts +29 -8
- package/src/modules/workflows/lib/start-validator.ts +38 -28
- package/src/modules/workflows/lib/transition-handler.ts +208 -55
- package/src/modules/workflows/migrations/Migration20260123143500.ts +38 -0
- package/src/modules/workflows/subscribers/event-trigger.ts +109 -0
- package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +446 -0
- package/src/modules/workflows/widgets/injection/order-approval/widget.ts +16 -0
- package/src/modules/workflows/widgets/injection-table.ts +21 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createModuleEvents } from '@open-mercato/shared/modules/events'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Customers Module Events
|
|
5
|
+
*
|
|
6
|
+
* Declares all events that can be emitted by the customers module.
|
|
7
|
+
*/
|
|
8
|
+
const events = [
|
|
9
|
+
// People
|
|
10
|
+
{ id: 'customers.people.created', label: 'Customer (Person) Created', entity: 'people', category: 'crud' },
|
|
11
|
+
{ id: 'customers.people.updated', label: 'Customer (Person) Updated', entity: 'people', category: 'crud' },
|
|
12
|
+
{ id: 'customers.people.deleted', label: 'Customer (Person) Deleted', entity: 'people', category: 'crud' },
|
|
13
|
+
|
|
14
|
+
// Companies
|
|
15
|
+
{ id: 'customers.companies.created', label: 'Customer (Company) Created', entity: 'companies', category: 'crud' },
|
|
16
|
+
{ id: 'customers.companies.updated', label: 'Customer (Company) Updated', entity: 'companies', category: 'crud' },
|
|
17
|
+
{ id: 'customers.companies.deleted', label: 'Customer (Company) Deleted', entity: 'companies', category: 'crud' },
|
|
18
|
+
|
|
19
|
+
// Deals
|
|
20
|
+
{ id: 'customers.deals.created', label: 'Deal Created', entity: 'deals', category: 'crud' },
|
|
21
|
+
{ id: 'customers.deals.updated', label: 'Deal Updated', entity: 'deals', category: 'crud' },
|
|
22
|
+
{ id: 'customers.deals.deleted', label: 'Deal Deleted', entity: 'deals', category: 'crud' },
|
|
23
|
+
|
|
24
|
+
// Comments
|
|
25
|
+
{ id: 'customers.comments.created', label: 'Comment Created', entity: 'comments', category: 'crud' },
|
|
26
|
+
{ id: 'customers.comments.updated', label: 'Comment Updated', entity: 'comments', category: 'crud' },
|
|
27
|
+
{ id: 'customers.comments.deleted', label: 'Comment Deleted', entity: 'comments', category: 'crud' },
|
|
28
|
+
|
|
29
|
+
// Addresses
|
|
30
|
+
{ id: 'customers.addresses.created', label: 'Address Created', entity: 'addresses', category: 'crud' },
|
|
31
|
+
{ id: 'customers.addresses.updated', label: 'Address Updated', entity: 'addresses', category: 'crud' },
|
|
32
|
+
{ id: 'customers.addresses.deleted', label: 'Address Deleted', entity: 'addresses', category: 'crud' },
|
|
33
|
+
|
|
34
|
+
// Activities
|
|
35
|
+
{ id: 'customers.activities.created', label: 'Activity Created', entity: 'activities', category: 'crud' },
|
|
36
|
+
{ id: 'customers.activities.updated', label: 'Activity Updated', entity: 'activities', category: 'crud' },
|
|
37
|
+
{ id: 'customers.activities.deleted', label: 'Activity Deleted', entity: 'activities', category: 'crud' },
|
|
38
|
+
|
|
39
|
+
// Tags
|
|
40
|
+
{ id: 'customers.tags.created', label: 'Tag Created', entity: 'tags', category: 'crud' },
|
|
41
|
+
{ id: 'customers.tags.updated', label: 'Tag Updated', entity: 'tags', category: 'crud' },
|
|
42
|
+
{ id: 'customers.tags.deleted', label: 'Tag Deleted', entity: 'tags', category: 'crud' },
|
|
43
|
+
{ id: 'customers.tags.assigned', label: 'Tag Assigned', entity: 'tags', category: 'crud' },
|
|
44
|
+
{ id: 'customers.tags.removed', label: 'Tag Removed', entity: 'tags', category: 'crud' },
|
|
45
|
+
|
|
46
|
+
// Todos
|
|
47
|
+
{ id: 'customers.todos.created', label: 'Todo Created', entity: 'todos', category: 'crud' },
|
|
48
|
+
{ id: 'customers.todos.updated', label: 'Todo Updated', entity: 'todos', category: 'crud' },
|
|
49
|
+
{ id: 'customers.todos.deleted', label: 'Todo Deleted', entity: 'todos', category: 'crud' },
|
|
50
|
+
] as const
|
|
51
|
+
|
|
52
|
+
export const eventsConfig = createModuleEvents({
|
|
53
|
+
moduleId: 'customers',
|
|
54
|
+
events,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
/** Type-safe event emitter for customers module */
|
|
58
|
+
export const emitCustomersEvent = eventsConfig.emit
|
|
59
|
+
|
|
60
|
+
/** Event IDs that can be emitted by the customers module */
|
|
61
|
+
export type CustomersEventId = typeof events[number]['id']
|
|
62
|
+
|
|
63
|
+
export default eventsConfig
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createModuleEvents } from '@open-mercato/shared/modules/events'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Directory Module Events
|
|
5
|
+
*
|
|
6
|
+
* Declares all events that can be emitted by the directory module.
|
|
7
|
+
*/
|
|
8
|
+
const events = [
|
|
9
|
+
// Tenants
|
|
10
|
+
{ id: 'directory.tenants.created', label: 'Tenant Created', entity: 'tenants', category: 'crud' },
|
|
11
|
+
{ id: 'directory.tenants.updated', label: 'Tenant Updated', entity: 'tenants', category: 'crud' },
|
|
12
|
+
{ id: 'directory.tenants.deleted', label: 'Tenant Deleted', entity: 'tenants', category: 'crud' },
|
|
13
|
+
|
|
14
|
+
// Organizations
|
|
15
|
+
{ id: 'directory.organizations.created', label: 'Organization Created', entity: 'organizations', category: 'crud' },
|
|
16
|
+
{ id: 'directory.organizations.updated', label: 'Organization Updated', entity: 'organizations', category: 'crud' },
|
|
17
|
+
{ id: 'directory.organizations.deleted', label: 'Organization Deleted', entity: 'organizations', category: 'crud' },
|
|
18
|
+
] as const
|
|
19
|
+
|
|
20
|
+
export const eventsConfig = createModuleEvents({
|
|
21
|
+
moduleId: 'directory',
|
|
22
|
+
events,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
/** Type-safe event emitter for directory module */
|
|
26
|
+
export const emitDirectoryEvent = eventsConfig.emit
|
|
27
|
+
|
|
28
|
+
/** Event IDs that can be emitted by the directory module */
|
|
29
|
+
export type DirectoryEventId = typeof events[number]['id']
|
|
30
|
+
|
|
31
|
+
export default eventsConfig
|
package/src/modules/sales/acl.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export const features = [
|
|
2
2
|
{ id: 'sales.orders.view', title: 'View sales orders', module: 'sales' },
|
|
3
3
|
{ id: 'sales.orders.manage', title: 'Manage sales orders', module: 'sales' },
|
|
4
|
+
{ id: 'sales.orders.approve', title: 'Approve sales orders', module: 'sales' },
|
|
4
5
|
{ id: 'sales.quotes.view', title: 'View sales quotes', module: 'sales' },
|
|
5
6
|
{ id: 'sales.quotes.manage', title: 'Manage sales quotes', module: 'sales' },
|
|
6
7
|
{ id: 'sales.shipments.manage', title: 'Manage order shipments', module: 'sales' },
|
|
@@ -50,6 +50,9 @@ import {
|
|
|
50
50
|
emitSalesDocumentTotalsRefresh,
|
|
51
51
|
subscribeSalesDocumentTotalsRefresh,
|
|
52
52
|
} from '@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents'
|
|
53
|
+
import {
|
|
54
|
+
subscribeSalesDocumentDataRefresh,
|
|
55
|
+
} from '@open-mercato/core/modules/sales/lib/frontend/documentDataEvents'
|
|
53
56
|
import type { CommentSummary, SectionAction } from '@open-mercato/ui/backend/detail'
|
|
54
57
|
import { ICON_SUGGESTIONS } from '@open-mercato/core/modules/customers/lib/dictionaries'
|
|
55
58
|
import { readMarkdownPreferenceCookie, writeMarkdownPreferenceCookie } from '@open-mercato/core/modules/customers/lib/markdownPreference'
|
|
@@ -2601,6 +2604,19 @@ export default function SalesDocumentDetailPage({
|
|
|
2601
2604
|
[kind, record?.id, refreshDocumentTotals],
|
|
2602
2605
|
)
|
|
2603
2606
|
|
|
2607
|
+
// Subscribe to document data refresh events (e.g., from workflow status updates)
|
|
2608
|
+
React.useEffect(
|
|
2609
|
+
() =>
|
|
2610
|
+
subscribeSalesDocumentDataRefresh((detail) => {
|
|
2611
|
+
if (!record?.id) return
|
|
2612
|
+
if (detail.documentId !== record.id) return
|
|
2613
|
+
if (detail.kind && detail.kind !== kind) return
|
|
2614
|
+
// Increment reloadKey to trigger a full document reload
|
|
2615
|
+
setReloadKey((prev) => prev + 1)
|
|
2616
|
+
}),
|
|
2617
|
+
[kind, record?.id],
|
|
2618
|
+
)
|
|
2619
|
+
|
|
2604
2620
|
const statusDictionaryMap = React.useMemo(
|
|
2605
2621
|
() =>
|
|
2606
2622
|
createDictionaryMap(
|
|
@@ -4,7 +4,7 @@ import { randomUUID } from 'crypto'
|
|
|
4
4
|
import { z } from 'zod'
|
|
5
5
|
import { registerCommand } from '@open-mercato/shared/lib/commands'
|
|
6
6
|
import type { CommandHandler } from '@open-mercato/shared/lib/commands'
|
|
7
|
-
import { emitCrudSideEffects, requireId } from '@open-mercato/shared/lib/commands/helpers'
|
|
7
|
+
import { emitCrudSideEffects, requireId, type CrudEventsConfig } from '@open-mercato/shared/lib/commands/helpers'
|
|
8
8
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
9
9
|
import type { EventBus } from '@open-mercato/events'
|
|
10
10
|
import type { DataEngine } from '@open-mercato/shared/lib/data/engine'
|
|
@@ -92,6 +92,29 @@ import { SalesDocumentNumberGenerator } from '../services/salesDocumentNumberGen
|
|
|
92
92
|
import { loadSalesSettings } from './settings'
|
|
93
93
|
import { notificationTypes } from '../notifications'
|
|
94
94
|
|
|
95
|
+
// CRUD events configuration for workflow triggers
|
|
96
|
+
const orderCrudEvents: CrudEventsConfig<SalesOrder> = {
|
|
97
|
+
module: 'sales',
|
|
98
|
+
entity: 'orders',
|
|
99
|
+
persistent: true,
|
|
100
|
+
buildPayload: (ctx) => ({
|
|
101
|
+
id: ctx.identifiers.id,
|
|
102
|
+
organizationId: ctx.identifiers.organizationId,
|
|
103
|
+
tenantId: ctx.identifiers.tenantId,
|
|
104
|
+
}),
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const quoteCrudEvents: CrudEventsConfig<SalesQuote> = {
|
|
108
|
+
module: 'sales',
|
|
109
|
+
entity: 'quotes',
|
|
110
|
+
persistent: true,
|
|
111
|
+
buildPayload: (ctx) => ({
|
|
112
|
+
id: ctx.identifiers.id,
|
|
113
|
+
organizationId: ctx.identifiers.organizationId,
|
|
114
|
+
tenantId: ctx.identifiers.tenantId,
|
|
115
|
+
}),
|
|
116
|
+
}
|
|
117
|
+
|
|
95
118
|
type DocumentAddressSnapshot = {
|
|
96
119
|
id: string
|
|
97
120
|
organizationId: string
|
|
@@ -3145,6 +3168,32 @@ const createQuoteCommand: CommandHandler<QuoteCreateInput, { quoteId: string }>
|
|
|
3145
3168
|
console.error('[sales.quotes.create] Failed to create notification:', err)
|
|
3146
3169
|
}
|
|
3147
3170
|
|
|
3171
|
+
// Emit CRUD side effects to trigger workflow event listeners
|
|
3172
|
+
const dataEngine = ctx.container.resolve('dataEngine') as DataEngine
|
|
3173
|
+
await emitCrudSideEffects({
|
|
3174
|
+
dataEngine,
|
|
3175
|
+
action: 'created',
|
|
3176
|
+
entity: quote,
|
|
3177
|
+
identifiers: {
|
|
3178
|
+
id: quote.id,
|
|
3179
|
+
organizationId: quote.organizationId,
|
|
3180
|
+
tenantId: quote.tenantId,
|
|
3181
|
+
},
|
|
3182
|
+
events: quoteCrudEvents,
|
|
3183
|
+
indexer: { entityType: E.sales.sales_quote },
|
|
3184
|
+
})
|
|
3185
|
+
|
|
3186
|
+
// Invalidate cache
|
|
3187
|
+
const resourceKind = deriveResourceFromCommandId(createQuoteCommand.id) ?? 'sales.quote'
|
|
3188
|
+
await invalidateCrudCache(
|
|
3189
|
+
ctx.container,
|
|
3190
|
+
resourceKind,
|
|
3191
|
+
{ id: quote.id, organizationId: quote.organizationId, tenantId: quote.tenantId },
|
|
3192
|
+
ctx.auth?.tenantId ?? null,
|
|
3193
|
+
'created'
|
|
3194
|
+
)
|
|
3195
|
+
|
|
3196
|
+
|
|
3148
3197
|
return { quoteId: quote.id }
|
|
3149
3198
|
},
|
|
3150
3199
|
captureAfter: async (_input, result, ctx) => {
|
|
@@ -3847,6 +3896,31 @@ const createOrderCommand: CommandHandler<OrderCreateInput, { orderId: string }>
|
|
|
3847
3896
|
console.error('[sales.orders.create] Failed to create notification:', err)
|
|
3848
3897
|
}
|
|
3849
3898
|
|
|
3899
|
+
// Emit CRUD side effects to trigger workflow event listeners
|
|
3900
|
+
const dataEngine = ctx.container.resolve('dataEngine') as DataEngine
|
|
3901
|
+
await emitCrudSideEffects({
|
|
3902
|
+
dataEngine,
|
|
3903
|
+
action: 'created',
|
|
3904
|
+
entity: order,
|
|
3905
|
+
identifiers: {
|
|
3906
|
+
id: order.id,
|
|
3907
|
+
organizationId: order.organizationId,
|
|
3908
|
+
tenantId: order.tenantId,
|
|
3909
|
+
},
|
|
3910
|
+
events: orderCrudEvents,
|
|
3911
|
+
indexer: { entityType: E.sales.sales_order },
|
|
3912
|
+
})
|
|
3913
|
+
|
|
3914
|
+
// Invalidate cache
|
|
3915
|
+
const resourceKind = deriveResourceFromCommandId(createOrderCommand.id) ?? 'sales.order'
|
|
3916
|
+
await invalidateCrudCache(
|
|
3917
|
+
ctx.container,
|
|
3918
|
+
resourceKind,
|
|
3919
|
+
{ id: order.id, organizationId: order.organizationId, tenantId: order.tenantId },
|
|
3920
|
+
ctx.auth?.tenantId ?? null,
|
|
3921
|
+
'created'
|
|
3922
|
+
)
|
|
3923
|
+
|
|
3850
3924
|
return { orderId: order.id }
|
|
3851
3925
|
},
|
|
3852
3926
|
captureAfter: async (_input, result, ctx) => {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { createModuleEvents } from '@open-mercato/shared/modules/events'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sales Module Events
|
|
5
|
+
*
|
|
6
|
+
* Declares all events that can be emitted by the sales module.
|
|
7
|
+
*/
|
|
8
|
+
const events = [
|
|
9
|
+
// Orders
|
|
10
|
+
{ id: 'sales.orders.created', label: 'Sales Order Created', entity: 'orders', category: 'crud' },
|
|
11
|
+
{ id: 'sales.orders.updated', label: 'Sales Order Updated', entity: 'orders', category: 'crud' },
|
|
12
|
+
{ id: 'sales.orders.deleted', label: 'Sales Order Deleted', entity: 'orders', category: 'crud' },
|
|
13
|
+
|
|
14
|
+
// Quotes
|
|
15
|
+
{ id: 'sales.quotes.created', label: 'Quote Created', entity: 'quotes', category: 'crud' },
|
|
16
|
+
{ id: 'sales.quotes.updated', label: 'Quote Updated', entity: 'quotes', category: 'crud' },
|
|
17
|
+
{ id: 'sales.quotes.deleted', label: 'Quote Deleted', entity: 'quotes', category: 'crud' },
|
|
18
|
+
|
|
19
|
+
// Invoices
|
|
20
|
+
{ id: 'sales.invoices.created', label: 'Invoice Created', entity: 'invoices', category: 'crud' },
|
|
21
|
+
{ id: 'sales.invoices.updated', label: 'Invoice Updated', entity: 'invoices', category: 'crud' },
|
|
22
|
+
{ id: 'sales.invoices.deleted', label: 'Invoice Deleted', entity: 'invoices', category: 'crud' },
|
|
23
|
+
|
|
24
|
+
// Order Lines
|
|
25
|
+
{ id: 'sales.lines.created', label: 'Order Line Created', entity: 'lines', category: 'crud' },
|
|
26
|
+
{ id: 'sales.lines.updated', label: 'Order Line Updated', entity: 'lines', category: 'crud' },
|
|
27
|
+
{ id: 'sales.lines.deleted', label: 'Order Line Deleted', entity: 'lines', category: 'crud' },
|
|
28
|
+
|
|
29
|
+
// Payments
|
|
30
|
+
{ id: 'sales.payments.created', label: 'Payment Created', entity: 'payments', category: 'crud' },
|
|
31
|
+
{ id: 'sales.payments.updated', label: 'Payment Updated', entity: 'payments', category: 'crud' },
|
|
32
|
+
{ id: 'sales.payments.deleted', label: 'Payment Deleted', entity: 'payments', category: 'crud' },
|
|
33
|
+
|
|
34
|
+
// Shipments
|
|
35
|
+
{ id: 'sales.shipments.created', label: 'Shipment Created', entity: 'shipments', category: 'crud' },
|
|
36
|
+
{ id: 'sales.shipments.updated', label: 'Shipment Updated', entity: 'shipments', category: 'crud' },
|
|
37
|
+
{ id: 'sales.shipments.deleted', label: 'Shipment Deleted', entity: 'shipments', category: 'crud' },
|
|
38
|
+
|
|
39
|
+
// Notes
|
|
40
|
+
{ id: 'sales.notes.created', label: 'Note Created', entity: 'notes', category: 'crud' },
|
|
41
|
+
{ id: 'sales.notes.updated', label: 'Note Updated', entity: 'notes', category: 'crud' },
|
|
42
|
+
{ id: 'sales.notes.deleted', label: 'Note Deleted', entity: 'notes', category: 'crud' },
|
|
43
|
+
|
|
44
|
+
// Configuration
|
|
45
|
+
{ id: 'sales.configuration.created', label: 'Configuration Created', entity: 'configuration', category: 'crud' },
|
|
46
|
+
{ id: 'sales.configuration.updated', label: 'Configuration Updated', entity: 'configuration', category: 'crud' },
|
|
47
|
+
{ id: 'sales.configuration.deleted', label: 'Configuration Deleted', entity: 'configuration', category: 'crud' },
|
|
48
|
+
|
|
49
|
+
// Lifecycle events - Document calculations
|
|
50
|
+
{ id: 'sales.document.totals.calculated', label: 'Document Totals Calculated', category: 'lifecycle' },
|
|
51
|
+
{ id: 'sales.document.calculate.before', label: 'Before Document Calculate', category: 'lifecycle', excludeFromTriggers: true },
|
|
52
|
+
{ id: 'sales.document.calculate.after', label: 'After Document Calculate', category: 'lifecycle', excludeFromTriggers: true },
|
|
53
|
+
|
|
54
|
+
// Lifecycle events - Line calculations
|
|
55
|
+
{ id: 'sales.line.calculate.before', label: 'Before Line Calculate', category: 'lifecycle', excludeFromTriggers: true },
|
|
56
|
+
{ id: 'sales.line.calculate.after', label: 'After Line Calculate', category: 'lifecycle', excludeFromTriggers: true },
|
|
57
|
+
|
|
58
|
+
// Lifecycle events - Tax calculations
|
|
59
|
+
{ id: 'sales.tax.calculate.before', label: 'Before Tax Calculate', category: 'lifecycle', excludeFromTriggers: true },
|
|
60
|
+
{ id: 'sales.tax.calculate.after', label: 'After Tax Calculate', category: 'lifecycle', excludeFromTriggers: true },
|
|
61
|
+
|
|
62
|
+
// Lifecycle events - Shipping adjustments
|
|
63
|
+
{ id: 'sales.shipping.adjustments.apply.before', label: 'Before Shipping Adjustments', category: 'lifecycle', excludeFromTriggers: true },
|
|
64
|
+
{ id: 'sales.shipping.adjustments.apply.after', label: 'After Shipping Adjustments', category: 'lifecycle', excludeFromTriggers: true },
|
|
65
|
+
|
|
66
|
+
// Lifecycle events - Payment adjustments
|
|
67
|
+
{ id: 'sales.payment.adjustments.apply.before', label: 'Before Payment Adjustments', category: 'lifecycle', excludeFromTriggers: true },
|
|
68
|
+
{ id: 'sales.payment.adjustments.apply.after', label: 'After Payment Adjustments', category: 'lifecycle', excludeFromTriggers: true },
|
|
69
|
+
] as const
|
|
70
|
+
|
|
71
|
+
export const eventsConfig = createModuleEvents({
|
|
72
|
+
moduleId: 'sales',
|
|
73
|
+
events,
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
/** Type-safe event emitter for sales module */
|
|
77
|
+
export const emitSalesEvent = eventsConfig.emit
|
|
78
|
+
|
|
79
|
+
/** Event IDs that can be emitted by the sales module */
|
|
80
|
+
export type SalesEventId = typeof events[number]['id']
|
|
81
|
+
|
|
82
|
+
export default eventsConfig
|
|
@@ -125,6 +125,9 @@ type SeedScope = { tenantId: string; organizationId: string }
|
|
|
125
125
|
|
|
126
126
|
const ORDER_STATUS_DEFAULTS: SalesDictionarySeed[] = [
|
|
127
127
|
{ value: 'draft', label: 'Draft', color: '#94a3b8', icon: 'lucide:file-pen-line' },
|
|
128
|
+
{ value: 'pending_approval', label: 'Pending Approval', color: '#f59e0b', icon: 'lucide:hourglass' },
|
|
129
|
+
{ value: 'approved', label: 'Approved', color: '#16a34a', icon: 'lucide:check-circle' },
|
|
130
|
+
{ value: 'rejected', label: 'Rejected', color: '#ef4444', icon: 'lucide:x-circle' },
|
|
128
131
|
{ value: 'sent', label: 'Sent', color: '#0ea5e9', icon: 'lucide:send' },
|
|
129
132
|
{ value: 'confirmed', label: 'Confirmed', color: '#2563eb', icon: 'lucide:badge-check' },
|
|
130
133
|
{ value: 'in_fulfillment', label: 'In fulfillment', color: '#f59e0b', icon: 'lucide:loader-2' },
|
|
@@ -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
|
|
@@ -194,11 +194,14 @@ describe('Workflow Instances API', () => {
|
|
|
194
194
|
const request = new NextRequest('http://localhost/api/workflows/instances?entityType=order&entityId=order-123')
|
|
195
195
|
await listInstances(request)
|
|
196
196
|
|
|
197
|
+
// The implementation uses JSONB $contains queries for metadata filtering
|
|
197
198
|
expect(mockEm.findAndCount).toHaveBeenCalledWith(
|
|
198
199
|
WorkflowInstance,
|
|
199
200
|
expect.objectContaining({
|
|
200
|
-
|
|
201
|
-
|
|
201
|
+
$and: expect.arrayContaining([
|
|
202
|
+
{ metadata: { $contains: { entityType: 'order' } } },
|
|
203
|
+
{ metadata: { $contains: { entityId: 'order-123' } } },
|
|
204
|
+
]),
|
|
202
205
|
}),
|
|
203
206
|
expect.any(Object)
|
|
204
207
|
)
|
|
@@ -70,19 +70,33 @@ export async function GET(request: NextRequest) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
if (status) {
|
|
73
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
|
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/
|
|
8
|
-
{ label: 'Events', labelKey: 'workflows.events.plural', href: '/backend/
|
|
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/
|
|
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/
|
|
8
|
-
{ label: 'Instances', labelKey: 'workflows.instances.plural', href: '/backend/
|
|
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/
|
|
8
|
-
{ label: 'Tasks', labelKey: 'workflows.tasks.plural', href: '/backend/
|
|
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
|
}
|