@open-mercato/core 0.6.5-develop.4516.1.88e6ab71a9 → 0.6.5-develop.4534.1.b459babe6d
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 +2 -2
- package/dist/generated/entities/step_instance/index.js +2 -0
- package/dist/generated/entities/step_instance/index.js.map +2 -2
- package/dist/generated/entities/user_task/index.js +2 -0
- package/dist/generated/entities/user_task/index.js.map +2 -2
- package/dist/generated/entities/workflow_branch_instance/index.js +39 -0
- package/dist/generated/entities/workflow_branch_instance/index.js.map +7 -0
- package/dist/generated/entities/workflow_event/index.js +2 -0
- package/dist/generated/entities/workflow_event/index.js.map +2 -2
- package/dist/generated/entities/workflow_instance/index.js +2 -0
- package/dist/generated/entities/workflow_instance/index.js.map +2 -2
- 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 +24 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/progress/api/jobs/[id]/route.js +7 -1
- package/dist/modules/progress/api/jobs/[id]/route.js.map +2 -2
- package/dist/modules/shipping_carriers/api/cancel/route.js +2 -2
- package/dist/modules/shipping_carriers/api/cancel/route.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/status-sync.js +8 -1
- package/dist/modules/shipping_carriers/lib/status-sync.js.map +2 -2
- package/dist/modules/workflows/components/NodeEditDialog.js +3 -1
- package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowGraphImpl.js +4 -2
- package/dist/modules/workflows/components/WorkflowGraphImpl.js.map +2 -2
- package/dist/modules/workflows/components/nodes/ParallelForkNode.js +49 -0
- package/dist/modules/workflows/components/nodes/ParallelForkNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/ParallelJoinNode.js +49 -0
- package/dist/modules/workflows/components/nodes/ParallelJoinNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/index.js +4 -0
- package/dist/modules/workflows/components/nodes/index.js.map +2 -2
- package/dist/modules/workflows/data/entities.js +81 -0
- package/dist/modules/workflows/data/entities.js.map +2 -2
- package/dist/modules/workflows/data/validators.js +146 -1
- package/dist/modules/workflows/data/validators.js.map +2 -2
- package/dist/modules/workflows/events.js +7 -1
- package/dist/modules/workflows/events.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +4 -2
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/activity-queue-types.js.map +2 -2
- package/dist/modules/workflows/lib/event-logger.js +2 -0
- package/dist/modules/workflows/lib/event-logger.js.map +2 -2
- package/dist/modules/workflows/lib/execution-token.js +98 -0
- package/dist/modules/workflows/lib/execution-token.js.map +7 -0
- package/dist/modules/workflows/lib/node-type-icons.js +14 -5
- package/dist/modules/workflows/lib/node-type-icons.js.map +2 -2
- package/dist/modules/workflows/lib/parallel-handler.js +364 -0
- package/dist/modules/workflows/lib/parallel-handler.js.map +7 -0
- package/dist/modules/workflows/lib/signal-handler.js +63 -1
- package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +74 -30
- package/dist/modules/workflows/lib/step-handler.js.map +2 -2
- package/dist/modules/workflows/lib/task-handler.js +26 -0
- package/dist/modules/workflows/lib/task-handler.js.map +2 -2
- package/dist/modules/workflows/lib/timer-handler.js +26 -1
- package/dist/modules/workflows/lib/timer-handler.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +33 -21
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js +39 -1
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/dist/modules/workflows/migrations/Migration20260602120000.js +24 -0
- package/dist/modules/workflows/migrations/Migration20260602120000.js.map +7 -0
- package/dist/modules/workflows/workers/workflow-activities.worker.js +8 -4
- package/dist/modules/workflows/workers/workflow-activities.worker.js.map +2 -2
- package/generated/entities/step_instance/index.ts +1 -0
- package/generated/entities/user_task/index.ts +1 -0
- package/generated/entities/workflow_branch_instance/index.ts +18 -0
- package/generated/entities/workflow_event/index.ts +1 -0
- package/generated/entities/workflow_instance/index.ts +1 -0
- package/generated/entities.ids.generated.ts +1 -0
- package/generated/entity-fields-registry.ts +24 -0
- package/package.json +7 -7
- package/src/modules/progress/api/jobs/[id]/route.ts +7 -0
- package/src/modules/shipping_carriers/api/cancel/route.ts +2 -2
- package/src/modules/shipping_carriers/lib/status-sync.ts +19 -0
- package/src/modules/workflows/components/NodeEditDialog.tsx +2 -0
- package/src/modules/workflows/components/WorkflowGraphImpl.tsx +3 -1
- package/src/modules/workflows/components/nodes/ParallelForkNode.tsx +66 -0
- package/src/modules/workflows/components/nodes/ParallelJoinNode.tsx +66 -0
- package/src/modules/workflows/components/nodes/index.ts +6 -0
- package/src/modules/workflows/data/entities.ts +109 -0
- package/src/modules/workflows/data/validators.ts +223 -0
- package/src/modules/workflows/events.ts +7 -0
- package/src/modules/workflows/i18n/de.json +12 -0
- package/src/modules/workflows/i18n/en.json +12 -0
- package/src/modules/workflows/i18n/es.json +12 -0
- package/src/modules/workflows/i18n/pl.json +12 -0
- package/src/modules/workflows/lib/activity-executor.ts +8 -2
- package/src/modules/workflows/lib/activity-queue-types.ts +3 -0
- package/src/modules/workflows/lib/event-logger.ts +3 -0
- package/src/modules/workflows/lib/execution-token.ts +166 -0
- package/src/modules/workflows/lib/node-type-icons.ts +11 -2
- package/src/modules/workflows/lib/parallel-handler.ts +575 -0
- package/src/modules/workflows/lib/signal-handler.ts +72 -1
- package/src/modules/workflows/lib/step-handler.ts +94 -34
- package/src/modules/workflows/lib/task-handler.ts +32 -0
- package/src/modules/workflows/lib/timer-handler.ts +30 -1
- package/src/modules/workflows/lib/transition-handler.ts +56 -24
- package/src/modules/workflows/lib/workflow-executor.ts +53 -1
- package/src/modules/workflows/migrations/.snapshot-open-mercato.json +263 -0
- package/src/modules/workflows/migrations/Migration20260602120000.ts +25 -0
- package/src/modules/workflows/workers/workflow-activities.worker.ts +9 -4
|
@@ -913,6 +913,8 @@
|
|
|
913
913
|
"workflows.nodeTypes.automated": "AUTOMATIZADO",
|
|
914
914
|
"workflows.nodeTypes.decision": "DECISIÓN",
|
|
915
915
|
"workflows.nodeTypes.end": "FIN",
|
|
916
|
+
"workflows.nodeTypes.parallelFork": "Bifurcación paralela",
|
|
917
|
+
"workflows.nodeTypes.parallelJoin": "Unión paralela",
|
|
916
918
|
"workflows.nodeTypes.start": "INICIO",
|
|
917
919
|
"workflows.nodeTypes.subWorkflow": "SUBFLUJO DE TRABAJO",
|
|
918
920
|
"workflows.nodeTypes.userTask": "TAREA DE USUARIO",
|
|
@@ -937,6 +939,16 @@
|
|
|
937
939
|
"workflows.orderApproval.requestApproval": "Solicitar aprobación",
|
|
938
940
|
"workflows.orderApproval.startError": "Error al iniciar el flujo de aprobación.",
|
|
939
941
|
"workflows.orderApproval.submitDecision": "Enviar decisión",
|
|
942
|
+
"workflows.parallel.branch.label": "Rama",
|
|
943
|
+
"workflows.parallel.branch.status.ACTIVE": "Activa",
|
|
944
|
+
"workflows.parallel.branch.status.CANCELLED": "Cancelada",
|
|
945
|
+
"workflows.parallel.branch.status.COMPLETED": "Completada",
|
|
946
|
+
"workflows.parallel.branch.status.FAILED": "Fallida",
|
|
947
|
+
"workflows.parallel.branch.status.PAUSED": "En pausa",
|
|
948
|
+
"workflows.parallel.branch.status.WAITING_FOR_ACTIVITIES": "Esperando actividades",
|
|
949
|
+
"workflows.parallel.fork.label": "Bifurcación paralela",
|
|
950
|
+
"workflows.parallel.join.label": "Unión paralela",
|
|
951
|
+
"workflows.parallel.validation.title": "La validación de la bifurcación/unión paralela falló",
|
|
940
952
|
"workflows.signals.awaiting": "Esperando senal",
|
|
941
953
|
"workflows.signals.correlationKey": "Clave de correlacion",
|
|
942
954
|
"workflows.signals.payload": "Carga de la senal",
|
|
@@ -913,6 +913,8 @@
|
|
|
913
913
|
"workflows.nodeTypes.automated": "AUTOMATYCZNE",
|
|
914
914
|
"workflows.nodeTypes.decision": "DECYZJA",
|
|
915
915
|
"workflows.nodeTypes.end": "KONIEC",
|
|
916
|
+
"workflows.nodeTypes.parallelFork": "Rozgałęzienie równoległe",
|
|
917
|
+
"workflows.nodeTypes.parallelJoin": "Połączenie równoległe",
|
|
916
918
|
"workflows.nodeTypes.start": "START",
|
|
917
919
|
"workflows.nodeTypes.subWorkflow": "PODPRZEPŁYW",
|
|
918
920
|
"workflows.nodeTypes.userTask": "ZADANIE UŻYTKOWNIKA",
|
|
@@ -937,6 +939,16 @@
|
|
|
937
939
|
"workflows.orderApproval.requestApproval": "Poproś o zatwierdzenie",
|
|
938
940
|
"workflows.orderApproval.startError": "Nie udało się uruchomić przepływu zatwierdzania.",
|
|
939
941
|
"workflows.orderApproval.submitDecision": "Zatwierdź decyzję",
|
|
942
|
+
"workflows.parallel.branch.label": "Gałąź",
|
|
943
|
+
"workflows.parallel.branch.status.ACTIVE": "Aktywna",
|
|
944
|
+
"workflows.parallel.branch.status.CANCELLED": "Anulowana",
|
|
945
|
+
"workflows.parallel.branch.status.COMPLETED": "Zakończona",
|
|
946
|
+
"workflows.parallel.branch.status.FAILED": "Niepowodzenie",
|
|
947
|
+
"workflows.parallel.branch.status.PAUSED": "Wstrzymana",
|
|
948
|
+
"workflows.parallel.branch.status.WAITING_FOR_ACTIVITIES": "Oczekuje na aktywności",
|
|
949
|
+
"workflows.parallel.fork.label": "Rozgałęzienie równoległe",
|
|
950
|
+
"workflows.parallel.join.label": "Połączenie równoległe",
|
|
951
|
+
"workflows.parallel.validation.title": "Walidacja równoległego rozgałęzienia/połączenia nie powiodła się",
|
|
940
952
|
"workflows.signals.awaiting": "Oczekiwanie na sygnał",
|
|
941
953
|
"workflows.signals.correlationKey": "Klucz Korelacji",
|
|
942
954
|
"workflows.signals.payload": "Zawartość Sygnału",
|
|
@@ -80,6 +80,9 @@ export interface ActivityContext {
|
|
|
80
80
|
workflowContext: Record<string, any>
|
|
81
81
|
stepContext?: Record<string, any>
|
|
82
82
|
stepInstanceId?: string
|
|
83
|
+
// Set when the activity runs inside a parallel branch; carried on the queue
|
|
84
|
+
// payload so async resume targets the branch rather than the instance.
|
|
85
|
+
branchInstanceId?: string | null
|
|
83
86
|
transitionId?: string
|
|
84
87
|
userId?: string
|
|
85
88
|
}
|
|
@@ -142,7 +145,7 @@ export async function enqueueActivity(
|
|
|
142
145
|
activity: ActivityDefinition,
|
|
143
146
|
context: ActivityContext
|
|
144
147
|
): Promise<string> {
|
|
145
|
-
const { workflowInstance, workflowContext, stepContext, transitionId, stepInstanceId } =
|
|
148
|
+
const { workflowInstance, workflowContext, stepContext, transitionId, stepInstanceId, branchInstanceId } =
|
|
146
149
|
context
|
|
147
150
|
|
|
148
151
|
// Interpolate config variables NOW (before queuing)
|
|
@@ -152,6 +155,7 @@ export async function enqueueActivity(
|
|
|
152
155
|
const job: WorkflowActivityJob = {
|
|
153
156
|
workflowInstanceId: workflowInstance.id,
|
|
154
157
|
stepInstanceId,
|
|
158
|
+
branchInstanceId: branchInstanceId ?? undefined,
|
|
155
159
|
transitionId,
|
|
156
160
|
activityId: activity.activityId,
|
|
157
161
|
activityName: activity.activityName || activity.activityType,
|
|
@@ -201,13 +205,14 @@ export async function enqueueActivity(
|
|
|
201
205
|
export async function enqueueTimerJob(params: {
|
|
202
206
|
workflowInstanceId: string
|
|
203
207
|
stepInstanceId: string
|
|
208
|
+
branchInstanceId?: string | null
|
|
204
209
|
tenantId: string
|
|
205
210
|
organizationId: string
|
|
206
211
|
userId?: string
|
|
207
212
|
fireAt: string
|
|
208
213
|
delayMs: number
|
|
209
214
|
}): Promise<string> {
|
|
210
|
-
const { workflowInstanceId, stepInstanceId, tenantId, organizationId, userId, fireAt, delayMs } =
|
|
215
|
+
const { workflowInstanceId, stepInstanceId, branchInstanceId, tenantId, organizationId, userId, fireAt, delayMs } =
|
|
211
216
|
params
|
|
212
217
|
|
|
213
218
|
const queue = getActivityQueue()
|
|
@@ -216,6 +221,7 @@ export async function enqueueTimerJob(params: {
|
|
|
216
221
|
kind: 'timer',
|
|
217
222
|
workflowInstanceId,
|
|
218
223
|
stepInstanceId,
|
|
224
|
+
branchInstanceId: branchInstanceId ?? undefined,
|
|
219
225
|
tenantId,
|
|
220
226
|
organizationId,
|
|
221
227
|
userId,
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
export interface WorkflowActivityJobBase {
|
|
11
11
|
workflowInstanceId: string
|
|
12
12
|
stepInstanceId?: string
|
|
13
|
+
// Set when the job belongs to a parallel branch; resume targets that branch.
|
|
14
|
+
// Absent on jobs enqueued before parallel support shipped → instance-level resume.
|
|
15
|
+
branchInstanceId?: string | null
|
|
13
16
|
tenantId: string
|
|
14
17
|
organizationId: string
|
|
15
18
|
userId?: string
|
|
@@ -87,6 +87,7 @@ export type WorkflowEventType = typeof WorkflowEventTypes[keyof typeof WorkflowE
|
|
|
87
87
|
export interface WorkflowEventInput {
|
|
88
88
|
workflowInstanceId: string
|
|
89
89
|
stepInstanceId?: string
|
|
90
|
+
branchInstanceId?: string | null
|
|
90
91
|
eventType: WorkflowEventType | string
|
|
91
92
|
eventData: any
|
|
92
93
|
userId?: string
|
|
@@ -128,6 +129,7 @@ export async function logWorkflowEvent(
|
|
|
128
129
|
const workflowEvent = em.create(WorkflowEvent, {
|
|
129
130
|
workflowInstanceId: event.workflowInstanceId,
|
|
130
131
|
stepInstanceId: event.stepInstanceId || null,
|
|
132
|
+
branchInstanceId: event.branchInstanceId ?? null,
|
|
131
133
|
eventType: event.eventType,
|
|
132
134
|
eventData: event.eventData || {},
|
|
133
135
|
userId: event.userId || null,
|
|
@@ -156,6 +158,7 @@ export async function logWorkflowEvents(
|
|
|
156
158
|
em.create(WorkflowEvent, {
|
|
157
159
|
workflowInstanceId: event.workflowInstanceId,
|
|
158
160
|
stepInstanceId: event.stepInstanceId || null,
|
|
161
|
+
branchInstanceId: event.branchInstanceId ?? null,
|
|
159
162
|
eventType: event.eventType,
|
|
160
163
|
eventData: event.eventData || {},
|
|
161
164
|
userId: event.userId || null,
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflows Module - Execution Token Abstraction
|
|
3
|
+
*
|
|
4
|
+
* An execution token is the cursor the engine advances: it holds a
|
|
5
|
+
* `currentStepId`, a read/write context scope, a status, and an optional
|
|
6
|
+
* pending async transition. Today there are two kinds:
|
|
7
|
+
*
|
|
8
|
+
* - **root token** — backed directly by the `WorkflowInstance`. Used for all
|
|
9
|
+
* single-token (FORK-less) execution. Every accessor maps 1:1 onto the
|
|
10
|
+
* instance fields, so the legacy single-token path is behaviourally
|
|
11
|
+
* unchanged.
|
|
12
|
+
* - **branch token** — backed by a `WorkflowBranchInstance` created by a
|
|
13
|
+
* PARALLEL_FORK. The branch shares the parent instance's identity (id,
|
|
14
|
+
* definition, tenant/org) for step-instance/event scoping, but owns its own
|
|
15
|
+
* `currentStepId`, private context namespace, status and pending transition.
|
|
16
|
+
*
|
|
17
|
+
* The handlers operate on tokens via these functional accessors so the same
|
|
18
|
+
* step/transition logic serves both kinds.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type {
|
|
22
|
+
WorkflowInstance,
|
|
23
|
+
WorkflowBranchInstance,
|
|
24
|
+
} from '../data/entities'
|
|
25
|
+
|
|
26
|
+
export interface PendingTransitionState {
|
|
27
|
+
toStepId: string
|
|
28
|
+
activityResults: any[]
|
|
29
|
+
timestamp: Date
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type ExecutionToken =
|
|
33
|
+
| { kind: 'root'; instance: WorkflowInstance }
|
|
34
|
+
| { kind: 'branch'; instance: WorkflowInstance; branch: WorkflowBranchInstance }
|
|
35
|
+
|
|
36
|
+
/** Build a root token backed by the instance (single-token execution). */
|
|
37
|
+
export function rootToken(instance: WorkflowInstance): ExecutionToken {
|
|
38
|
+
return { kind: 'root', instance }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Build a branch token backed by a branch instance of the given parent. */
|
|
42
|
+
export function branchToken(
|
|
43
|
+
instance: WorkflowInstance,
|
|
44
|
+
branch: WorkflowBranchInstance,
|
|
45
|
+
): ExecutionToken {
|
|
46
|
+
return { kind: 'branch', instance, branch }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Identity (shared between root and branch — step instances and events are
|
|
51
|
+
// always scoped to the parent WorkflowInstance, tagged with branchInstanceId).
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
export function tokenInstanceId(token: ExecutionToken): string {
|
|
55
|
+
return token.instance.id
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function tokenDefinitionId(token: ExecutionToken): string {
|
|
59
|
+
return token.instance.definitionId
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function tokenTenantId(token: ExecutionToken): string {
|
|
63
|
+
return token.instance.tenantId
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function tokenOrganizationId(token: ExecutionToken): string {
|
|
67
|
+
return token.instance.organizationId
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** The branch id this token represents, or null for the root token. */
|
|
71
|
+
export function tokenBranchInstanceId(token: ExecutionToken): string | null {
|
|
72
|
+
return token.kind === 'branch' ? token.branch.id : null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// Cursor + context
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
export function tokenCurrentStepId(token: ExecutionToken): string {
|
|
80
|
+
return token.kind === 'branch' ? token.branch.currentStepId : token.instance.currentStepId
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function setTokenCurrentStepId(token: ExecutionToken, stepId: string): void {
|
|
84
|
+
if (token.kind === 'branch') token.branch.currentStepId = stepId
|
|
85
|
+
else token.instance.currentStepId = stepId
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Effective read context: for a branch this is the instance context (snapshot)
|
|
90
|
+
* overlaid with the branch's private namespace, so a branch sees fork-time
|
|
91
|
+
* instance state plus its own writes. For the root it is the instance context.
|
|
92
|
+
*/
|
|
93
|
+
export function tokenReadContext(token: ExecutionToken): Record<string, any> {
|
|
94
|
+
if (token.kind === 'branch') {
|
|
95
|
+
return { ...(token.instance.context || {}), ...(token.branch.contextNamespace || {}) }
|
|
96
|
+
}
|
|
97
|
+
return token.instance.context || {}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Apply context writes after a transition. The root path is identical to the
|
|
102
|
+
* legacy behaviour: merge the passed workflowContext and activity outputs into
|
|
103
|
+
* `instance.context`. A branch writes only activity outputs (and any explicit
|
|
104
|
+
* deltas the caller already folded into its namespace) into its private
|
|
105
|
+
* namespace, never the shared instance snapshot — this prevents cross-branch
|
|
106
|
+
* key collisions.
|
|
107
|
+
*/
|
|
108
|
+
export function applyTokenContextWrites(
|
|
109
|
+
token: ExecutionToken,
|
|
110
|
+
workflowContext: Record<string, any>,
|
|
111
|
+
activityOutputs: Record<string, any>,
|
|
112
|
+
): void {
|
|
113
|
+
if (token.kind === 'branch') {
|
|
114
|
+
token.branch.contextNamespace = {
|
|
115
|
+
...(token.branch.contextNamespace || {}),
|
|
116
|
+
...activityOutputs,
|
|
117
|
+
}
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
token.instance.context = {
|
|
121
|
+
...(token.instance.context || {}),
|
|
122
|
+
...workflowContext,
|
|
123
|
+
...activityOutputs,
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// Status / pause state machine
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
export function setTokenWaitingForActivities(token: ExecutionToken): void {
|
|
132
|
+
if (token.kind === 'branch') token.branch.status = 'WAITING_FOR_ACTIVITIES'
|
|
133
|
+
else token.instance.status = 'WAITING_FOR_ACTIVITIES'
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function setTokenPaused(token: ExecutionToken, at: Date): void {
|
|
137
|
+
if (token.kind === 'branch') {
|
|
138
|
+
token.branch.status = 'PAUSED'
|
|
139
|
+
} else {
|
|
140
|
+
token.instance.status = 'PAUSED'
|
|
141
|
+
token.instance.pausedAt = at
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function getTokenPendingTransition(token: ExecutionToken): PendingTransitionState | null {
|
|
146
|
+
return (token.kind === 'branch' ? token.branch.pendingTransition : token.instance.pendingTransition) ?? null
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function setTokenPendingTransition(token: ExecutionToken, pending: PendingTransitionState | null): void {
|
|
150
|
+
if (token.kind === 'branch') token.branch.pendingTransition = pending
|
|
151
|
+
else token.instance.pendingTransition = pending
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function touchToken(token: ExecutionToken, now: Date): void {
|
|
155
|
+
if (token.kind === 'branch') token.branch.updatedAt = now
|
|
156
|
+
else token.instance.updatedAt = now
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Merge a patch into the token's own write scope (instance.context or branch namespace). */
|
|
160
|
+
export function mergeTokenContext(token: ExecutionToken, patch: Record<string, any>): void {
|
|
161
|
+
if (token.kind === 'branch') {
|
|
162
|
+
token.branch.contextNamespace = { ...(token.branch.contextNamespace || {}), ...patch }
|
|
163
|
+
} else {
|
|
164
|
+
token.instance.context = { ...(token.instance.context || {}), ...patch }
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CircleDot, CircleStop, User, Zap, Workflow, Clock, Timer, LucideIcon } from 'lucide-react'
|
|
1
|
+
import { CircleDot, CircleStop, User, Zap, Workflow, Clock, Timer, Split, Merge, LucideIcon } from 'lucide-react'
|
|
2
2
|
|
|
3
|
-
export type NodeType = 'start' | 'end' | 'userTask' | 'automated' | 'subWorkflow' | 'waitForSignal' | 'waitForTimer'
|
|
3
|
+
export type NodeType = 'start' | 'end' | 'userTask' | 'automated' | 'subWorkflow' | 'waitForSignal' | 'waitForTimer' | 'parallelFork' | 'parallelJoin'
|
|
4
4
|
|
|
5
5
|
export const NODE_TYPE_ICONS: Record<NodeType, LucideIcon> = {
|
|
6
6
|
start: CircleDot,
|
|
@@ -10,6 +10,8 @@ export const NODE_TYPE_ICONS: Record<NodeType, LucideIcon> = {
|
|
|
10
10
|
subWorkflow: Workflow,
|
|
11
11
|
waitForSignal: Clock,
|
|
12
12
|
waitForTimer: Timer,
|
|
13
|
+
parallelFork: Split,
|
|
14
|
+
parallelJoin: Merge,
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export const NODE_TYPE_COLORS: Record<NodeType, string> = {
|
|
@@ -20,6 +22,9 @@ export const NODE_TYPE_COLORS: Record<NodeType, string> = {
|
|
|
20
22
|
subWorkflow: 'text-purple-500',
|
|
21
23
|
waitForSignal: 'text-purple-500',
|
|
22
24
|
waitForTimer: 'text-cyan-500',
|
|
25
|
+
// New nodes use a semantic token (DS rule: no hardcoded color shades).
|
|
26
|
+
parallelFork: 'text-primary',
|
|
27
|
+
parallelJoin: 'text-primary',
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
export const NODE_TYPE_LABELS: Record<NodeType, { title: string; description: string }> = {
|
|
@@ -30,6 +35,8 @@ export const NODE_TYPE_LABELS: Record<NodeType, { title: string; description: st
|
|
|
30
35
|
subWorkflow: { title: 'SUB-WORKFLOW', description: 'Invoke workflow' },
|
|
31
36
|
waitForSignal: { title: 'WAIT FOR SIGNAL', description: 'Pause for external event' },
|
|
32
37
|
waitForTimer: { title: 'WAIT FOR TIMER', description: 'Pause for a duration' },
|
|
38
|
+
parallelFork: { title: 'PARALLEL FORK', description: 'Split into parallel branches' },
|
|
39
|
+
parallelJoin: { title: 'PARALLEL JOIN', description: 'Wait for all branches' },
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
const STEP_TYPE_TO_NODE_TYPE: Record<string, NodeType> = {
|
|
@@ -40,6 +47,8 @@ const STEP_TYPE_TO_NODE_TYPE: Record<string, NodeType> = {
|
|
|
40
47
|
SUB_WORKFLOW: 'subWorkflow',
|
|
41
48
|
WAIT_FOR_SIGNAL: 'waitForSignal',
|
|
42
49
|
WAIT_FOR_TIMER: 'waitForTimer',
|
|
50
|
+
PARALLEL_FORK: 'parallelFork',
|
|
51
|
+
PARALLEL_JOIN: 'parallelJoin',
|
|
43
52
|
}
|
|
44
53
|
|
|
45
54
|
export function stepTypeToNodeType(stepType: string): NodeType {
|