@acorex/connectivity 20.7.4 → 20.7.5
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.
|
@@ -12019,10 +12019,19 @@ class AXCWorkflowEngine {
|
|
|
12019
12019
|
const firstStepId = firstActivity?.id || 'root';
|
|
12020
12020
|
// Extract correlationId from input if provided (remove it from input to avoid pollution)
|
|
12021
12021
|
const correlationId = request.input?.['correlationId'] || null;
|
|
12022
|
+
const entityRefId = request.input?.['refId'] || null;
|
|
12023
|
+
const entityRefType = request.input?.['refType'] || null;
|
|
12022
12024
|
const workflowInput = { ...request.input };
|
|
12023
12025
|
if (correlationId && workflowInput['correlationId']) {
|
|
12024
12026
|
delete workflowInput['correlationId'];
|
|
12025
12027
|
}
|
|
12028
|
+
// Remove refId and refType from workflow input (they're stored in instance metadata)
|
|
12029
|
+
if (entityRefId && workflowInput['refId']) {
|
|
12030
|
+
delete workflowInput['refId'];
|
|
12031
|
+
}
|
|
12032
|
+
if (entityRefType && workflowInput['refType']) {
|
|
12033
|
+
delete workflowInput['refType'];
|
|
12034
|
+
}
|
|
12026
12035
|
// Create workflow state
|
|
12027
12036
|
const workflowState = {
|
|
12028
12037
|
id: `state-${instanceId}`,
|
|
@@ -12076,10 +12085,23 @@ class AXCWorkflowEngine {
|
|
|
12076
12085
|
incidentCount: 0,
|
|
12077
12086
|
createdAt: now,
|
|
12078
12087
|
updatedAt: now,
|
|
12079
|
-
finishedAt: null
|
|
12088
|
+
finishedAt: null,
|
|
12089
|
+
// Store entity reference for work item creation
|
|
12090
|
+
entityRefId: entityRefId || null,
|
|
12091
|
+
entityRefType: entityRefType || null,
|
|
12080
12092
|
};
|
|
12081
12093
|
// Store instance in IndexedDB
|
|
12082
12094
|
await this.db.instances.add(instance, instance.id);
|
|
12095
|
+
console.log(`[AXCWorkflowEngine] 💾 Stored workflow instance:`, {
|
|
12096
|
+
id: instance.id,
|
|
12097
|
+
definitionId: instance.definitionId,
|
|
12098
|
+
name: instance.name,
|
|
12099
|
+
correlationId: instance.correlationId,
|
|
12100
|
+
entityRefId: instance.entityRefId,
|
|
12101
|
+
entityRefType: instance.entityRefType,
|
|
12102
|
+
status: instance.status,
|
|
12103
|
+
subStatus: instance.subStatus,
|
|
12104
|
+
});
|
|
12083
12105
|
// 🎯 Also store in entity service for entity-based access
|
|
12084
12106
|
await this.saveInstanceToEntityService(instance);
|
|
12085
12107
|
// Convert to instance state for response (async - needs bookmark lookup)
|
|
@@ -12088,7 +12110,8 @@ class AXCWorkflowEngine {
|
|
|
12088
12110
|
let currentActivity = firstActivity;
|
|
12089
12111
|
let executionCount = 0;
|
|
12090
12112
|
const maxExecutions = 500; // Prevent infinite loops
|
|
12091
|
-
let lastActivityOutput =
|
|
12113
|
+
let lastActivityOutput = state.lastActivityOutput;
|
|
12114
|
+
let activityOutputs = { ...(state.activityOutputs || {}) };
|
|
12092
12115
|
while (currentActivity && executionCount < maxExecutions) {
|
|
12093
12116
|
executionCount++;
|
|
12094
12117
|
// Activity name is the registry key (e.g., 'workflow-activity:show-toast')
|
|
@@ -12111,11 +12134,24 @@ class AXCWorkflowEngine {
|
|
|
12111
12134
|
});
|
|
12112
12135
|
// Only create workitem for human-task
|
|
12113
12136
|
if (pendingTask.taskType === 'human-task') {
|
|
12137
|
+
console.log(`[AXCWorkflowEngine] 👤 Creating work item for human-task activity:`, {
|
|
12138
|
+
instanceId,
|
|
12139
|
+
activityId: currentActivity.id,
|
|
12140
|
+
bookmarkId,
|
|
12141
|
+
activityName: activityDef?.name,
|
|
12142
|
+
instanceEntityRefId: instance.entityRefId,
|
|
12143
|
+
instanceEntityRefType: instance.entityRefType,
|
|
12144
|
+
});
|
|
12114
12145
|
await this.createWorkItemFromBookmark(instanceId, currentActivity.id, bookmarkId, activityDef);
|
|
12115
12146
|
}
|
|
12147
|
+
else {
|
|
12148
|
+
console.log(`[AXCWorkflowEngine] ⏭️ Skipping work item creation (taskType: ${pendingTask.taskType}, not human-task)`);
|
|
12149
|
+
}
|
|
12116
12150
|
// Update state to suspended (waiting for frontend)
|
|
12117
12151
|
state = {
|
|
12118
12152
|
...state,
|
|
12153
|
+
activityOutputs,
|
|
12154
|
+
lastActivityOutput,
|
|
12119
12155
|
status: pendingTask.taskType == 'human-task' ? 'suspended' : 'running',
|
|
12120
12156
|
currentStepId: currentActivity.id,
|
|
12121
12157
|
};
|
|
@@ -12125,13 +12161,18 @@ class AXCWorkflowEngine {
|
|
|
12125
12161
|
instanceId: instanceId,
|
|
12126
12162
|
state,
|
|
12127
12163
|
pendingTask,
|
|
12128
|
-
|
|
12164
|
+
activityOutputs,
|
|
12165
|
+
lastActivityOutput,
|
|
12129
12166
|
};
|
|
12130
12167
|
}
|
|
12131
12168
|
// Backend activity → execute it
|
|
12132
12169
|
console.log(`[AXCWorkflowEngine] ⚙️ Executing backend activity '${currentActivity.name || currentActivity.id}' (${activityType})`);
|
|
12133
12170
|
const executionResult = await this.executeBackendActivityLocally(currentActivity, { ...state.variables, ...state.input }, state);
|
|
12134
12171
|
lastActivityOutput = executionResult.output;
|
|
12172
|
+
activityOutputs = {
|
|
12173
|
+
...activityOutputs,
|
|
12174
|
+
[currentActivity.id]: executionResult.output,
|
|
12175
|
+
};
|
|
12135
12176
|
// Update variables with output
|
|
12136
12177
|
state = {
|
|
12137
12178
|
...state,
|
|
@@ -12140,6 +12181,8 @@ class AXCWorkflowEngine {
|
|
|
12140
12181
|
//TODO need here!
|
|
12141
12182
|
...executionResult.output
|
|
12142
12183
|
},
|
|
12184
|
+
activityOutputs,
|
|
12185
|
+
lastActivityOutput,
|
|
12143
12186
|
currentStepId: currentActivity.id,
|
|
12144
12187
|
lastUpdated: new Date()
|
|
12145
12188
|
};
|
|
@@ -12160,7 +12203,9 @@ class AXCWorkflowEngine {
|
|
|
12160
12203
|
return {
|
|
12161
12204
|
instanceId: instanceId,
|
|
12162
12205
|
state,
|
|
12163
|
-
pendingTask: null
|
|
12206
|
+
pendingTask: null,
|
|
12207
|
+
activityOutputs,
|
|
12208
|
+
lastActivityOutput,
|
|
12164
12209
|
};
|
|
12165
12210
|
}
|
|
12166
12211
|
// Find next activity
|
|
@@ -12193,13 +12238,16 @@ class AXCWorkflowEngine {
|
|
|
12193
12238
|
...state,
|
|
12194
12239
|
status: 'completed',
|
|
12195
12240
|
currentStepId: undefined,
|
|
12196
|
-
output: state.variables
|
|
12241
|
+
output: state.variables,
|
|
12242
|
+
activityOutputs,
|
|
12243
|
+
lastActivityOutput,
|
|
12197
12244
|
};
|
|
12198
12245
|
await this.updateInstanceFromState(instanceId, state);
|
|
12199
12246
|
return {
|
|
12200
12247
|
instanceId: instanceId,
|
|
12201
12248
|
state: state,
|
|
12202
12249
|
pendingTask: null,
|
|
12250
|
+
activityOutputs,
|
|
12203
12251
|
lastActivityOutput: lastActivityOutput
|
|
12204
12252
|
};
|
|
12205
12253
|
}
|
|
@@ -12262,6 +12310,12 @@ class AXCWorkflowEngine {
|
|
|
12262
12310
|
// Apply frontend outputs into workflow state
|
|
12263
12311
|
// Merge userInput into variables (not as separate keys)
|
|
12264
12312
|
const userInput = request.userInput || {};
|
|
12313
|
+
let activityOutputs = { ...(state.activityOutputs || {}) };
|
|
12314
|
+
let lastActivityOutput = userInput;
|
|
12315
|
+
activityOutputs = {
|
|
12316
|
+
...activityOutputs,
|
|
12317
|
+
[request.stepId]: userInput,
|
|
12318
|
+
};
|
|
12265
12319
|
state = {
|
|
12266
12320
|
...state,
|
|
12267
12321
|
variables: {
|
|
@@ -12269,6 +12323,8 @@ class AXCWorkflowEngine {
|
|
|
12269
12323
|
...userInput, // Merge userInput directly into variables
|
|
12270
12324
|
[`${request.stepId}_outcome`]: request.outcome, // Keep outcome for reference
|
|
12271
12325
|
},
|
|
12326
|
+
activityOutputs,
|
|
12327
|
+
lastActivityOutput,
|
|
12272
12328
|
lastUpdated: new Date()
|
|
12273
12329
|
};
|
|
12274
12330
|
// Find next activity based on outcome from frontend
|
|
@@ -12281,7 +12337,9 @@ class AXCWorkflowEngine {
|
|
|
12281
12337
|
...state,
|
|
12282
12338
|
status: 'completed',
|
|
12283
12339
|
currentStepId: undefined,
|
|
12284
|
-
output: state.variables
|
|
12340
|
+
output: state.variables,
|
|
12341
|
+
activityOutputs,
|
|
12342
|
+
lastActivityOutput,
|
|
12285
12343
|
};
|
|
12286
12344
|
console.log('[AXCWorkflowExecutionService] 📝 Updating instance to completed state');
|
|
12287
12345
|
await this.updateInstanceFromState(request.instanceId, state);
|
|
@@ -12335,6 +12393,8 @@ class AXCWorkflowEngine {
|
|
|
12335
12393
|
// - ui-activity: running (workflow manager will execute it immediately)
|
|
12336
12394
|
state = {
|
|
12337
12395
|
...state,
|
|
12396
|
+
activityOutputs,
|
|
12397
|
+
lastActivityOutput,
|
|
12338
12398
|
status: taskType === 'human-task' ? 'suspended' : 'running',
|
|
12339
12399
|
currentStepId: currentActivity.id,
|
|
12340
12400
|
};
|
|
@@ -12350,6 +12410,11 @@ class AXCWorkflowEngine {
|
|
|
12350
12410
|
// Backend activity → execute it
|
|
12351
12411
|
console.log(`[AXCWorkflowEngine] ⚙️ Executing backend activity '${currentActivity.name || currentActivity.id}' (${activityType})`);
|
|
12352
12412
|
const executionResult = await this.executeBackendActivityLocally(currentActivity, { ...state.variables, ...state.input }, state);
|
|
12413
|
+
lastActivityOutput = executionResult.output;
|
|
12414
|
+
activityOutputs = {
|
|
12415
|
+
...activityOutputs,
|
|
12416
|
+
[currentActivity.id]: executionResult.output,
|
|
12417
|
+
};
|
|
12353
12418
|
// Update variables with output
|
|
12354
12419
|
state = {
|
|
12355
12420
|
...state,
|
|
@@ -12357,6 +12422,8 @@ class AXCWorkflowEngine {
|
|
|
12357
12422
|
...state.variables,
|
|
12358
12423
|
...executionResult.output
|
|
12359
12424
|
},
|
|
12425
|
+
activityOutputs,
|
|
12426
|
+
lastActivityOutput,
|
|
12360
12427
|
currentStepId: currentActivity.id,
|
|
12361
12428
|
lastUpdated: new Date()
|
|
12362
12429
|
};
|
|
@@ -12371,7 +12438,9 @@ class AXCWorkflowEngine {
|
|
|
12371
12438
|
...state,
|
|
12372
12439
|
status: 'completed',
|
|
12373
12440
|
currentStepId: undefined,
|
|
12374
|
-
output: state.variables
|
|
12441
|
+
output: state.variables,
|
|
12442
|
+
activityOutputs,
|
|
12443
|
+
lastActivityOutput,
|
|
12375
12444
|
};
|
|
12376
12445
|
await this.updateInstanceFromState(request.instanceId, state);
|
|
12377
12446
|
return {
|
|
@@ -12411,7 +12480,9 @@ class AXCWorkflowEngine {
|
|
|
12411
12480
|
...state,
|
|
12412
12481
|
status: 'completed',
|
|
12413
12482
|
currentStepId: undefined,
|
|
12414
|
-
output: state.variables
|
|
12483
|
+
output: state.variables,
|
|
12484
|
+
activityOutputs,
|
|
12485
|
+
lastActivityOutput,
|
|
12415
12486
|
};
|
|
12416
12487
|
await this.updateInstanceFromState(request.instanceId, state);
|
|
12417
12488
|
return {
|
|
@@ -12921,12 +12992,26 @@ class AXCWorkflowEngine {
|
|
|
12921
12992
|
*/
|
|
12922
12993
|
async createWorkItemFromBookmark(instanceId, activityId, bookmarkId, activityDef) {
|
|
12923
12994
|
try {
|
|
12995
|
+
console.log(`[AXCWorkflowEngine] 📋 createWorkItemFromBookmark called:`, {
|
|
12996
|
+
instanceId,
|
|
12997
|
+
activityId,
|
|
12998
|
+
bookmarkId,
|
|
12999
|
+
activityDefName: activityDef?.name,
|
|
13000
|
+
});
|
|
12924
13001
|
// Get workflow instance to get workflow name
|
|
12925
13002
|
const instance = await this.db.instances.get(instanceId);
|
|
12926
13003
|
if (!instance) {
|
|
12927
13004
|
console.warn(`[AXCWorkflowEngine] ⚠️ Instance ${instanceId} not found, skipping work item creation`);
|
|
12928
13005
|
return;
|
|
12929
13006
|
}
|
|
13007
|
+
console.log(`[AXCWorkflowEngine] 📦 Workflow instance found:`, {
|
|
13008
|
+
id: instance.id,
|
|
13009
|
+
definitionId: instance.definitionId,
|
|
13010
|
+
name: instance.name,
|
|
13011
|
+
correlationId: instance.correlationId,
|
|
13012
|
+
entityRefId: instance.entityRefId,
|
|
13013
|
+
entityRefType: instance.entityRefType,
|
|
13014
|
+
});
|
|
12930
13015
|
// Get bookmark to extract taskToken
|
|
12931
13016
|
const bookmark = await this.db.bookmarks.get(bookmarkId);
|
|
12932
13017
|
let taskToken = null;
|
|
@@ -12942,11 +13027,25 @@ class AXCWorkflowEngine {
|
|
|
12942
13027
|
// Get workflow definition to get workflow title
|
|
12943
13028
|
const workflowDef = await this.getDefinition(instance.definitionId || instance.name || '');
|
|
12944
13029
|
const workflowTitle = workflowDef?.title || instance.name || 'Workflow';
|
|
13030
|
+
console.log(`[AXCWorkflowEngine] 📖 Workflow definition:`, {
|
|
13031
|
+
definitionId: instance.definitionId,
|
|
13032
|
+
name: instance.name,
|
|
13033
|
+
workflowTitle,
|
|
13034
|
+
workflowDefFound: !!workflowDef,
|
|
13035
|
+
});
|
|
12945
13036
|
// Get activity definition for title
|
|
12946
13037
|
const activityTitle = activityDef?.title || activityId;
|
|
12947
13038
|
// Create a meaningful title
|
|
12948
13039
|
const workItemTitle = `${workflowTitle} - ${activityTitle}`;
|
|
12949
13040
|
const now = new Date().toISOString();
|
|
13041
|
+
// Extract entity reference from instance
|
|
13042
|
+
const entityRefId = instance.entityRefId || null;
|
|
13043
|
+
const entityRefType = instance.entityRefType || null;
|
|
13044
|
+
console.log(`[AXCWorkflowEngine] 🏷️ Entity reference:`, {
|
|
13045
|
+
entityRefId,
|
|
13046
|
+
entityRefType,
|
|
13047
|
+
hasEntityRef: !!(entityRefId && entityRefType),
|
|
13048
|
+
});
|
|
12950
13049
|
// Create work item
|
|
12951
13050
|
const workItem = {
|
|
12952
13051
|
id: AXPDataGenerator.uuid(),
|
|
@@ -12961,8 +13060,8 @@ class AXCWorkflowEngine {
|
|
|
12961
13060
|
priority: 'Normal',
|
|
12962
13061
|
assignedUserId: null, // Will be assigned later
|
|
12963
13062
|
correlationId: instance.correlationId || null,
|
|
12964
|
-
entityRefId:
|
|
12965
|
-
entityRefType:
|
|
13063
|
+
entityRefId: entityRefId,
|
|
13064
|
+
entityRefType: entityRefType,
|
|
12966
13065
|
createdAt: now,
|
|
12967
13066
|
updatedAt: now,
|
|
12968
13067
|
};
|
|
@@ -12971,13 +13070,146 @@ class AXCWorkflowEngine {
|
|
|
12971
13070
|
workItem.taskToken = taskToken;
|
|
12972
13071
|
}
|
|
12973
13072
|
await this.entityStorageService.insertOne('WorkflowManagement.WorkItem', workItem);
|
|
12974
|
-
console.log(`[AXCWorkflowEngine] ✅ Created work item
|
|
13073
|
+
console.log(`[AXCWorkflowEngine] ✅ Created work item:`, {
|
|
13074
|
+
id: workItem.id,
|
|
13075
|
+
instanceId: instanceId,
|
|
13076
|
+
bookmarkId: bookmarkId,
|
|
13077
|
+
activityNodeId: activityId,
|
|
13078
|
+
title: workItemTitle,
|
|
13079
|
+
entityRefId: workItem.entityRefId,
|
|
13080
|
+
entityRefType: workItem.entityRefType,
|
|
13081
|
+
status: workItem.status,
|
|
13082
|
+
priority: workItem.priority,
|
|
13083
|
+
assignedUserId: workItem.assignedUserId,
|
|
13084
|
+
createdAt: workItem.createdAt,
|
|
13085
|
+
});
|
|
13086
|
+
// 🎯 Try to set assignedUserId from entity data if entityRefId is available
|
|
13087
|
+
// COMMENTED FOR TESTING: Allow all tasks to appear in task board
|
|
13088
|
+
// if (entityRefId && entityRefType && !workItem.assignedUserId) {
|
|
13089
|
+
// try {
|
|
13090
|
+
// await this.updateWorkItemAssigneeFromEntity(workItem.id, entityRefType, entityRefId);
|
|
13091
|
+
// } catch (error) {
|
|
13092
|
+
// console.warn(`[AXCWorkflowEngine] ⚠️ Failed to set assignee from entity data:`, error);
|
|
13093
|
+
// // Continue without assignee - can be set later
|
|
13094
|
+
// }
|
|
13095
|
+
// }
|
|
12975
13096
|
}
|
|
12976
13097
|
catch (error) {
|
|
12977
13098
|
console.error(`[AXCWorkflowEngine] ❌ Failed to create work item for bookmark ${bookmarkId}:`, error);
|
|
12978
13099
|
// Don't fail workflow execution if work item creation fails
|
|
12979
13100
|
}
|
|
12980
13101
|
}
|
|
13102
|
+
/**
|
|
13103
|
+
* Update work items entity reference after entity is created.
|
|
13104
|
+
*/
|
|
13105
|
+
async updateWorkItemsEntityRef(instanceId, entityRefId, entityRefType) {
|
|
13106
|
+
try {
|
|
13107
|
+
console.log(`[AXCWorkflowEngine] 🔄 Updating work items entity reference:`, {
|
|
13108
|
+
instanceId,
|
|
13109
|
+
entityRefId,
|
|
13110
|
+
entityRefType,
|
|
13111
|
+
});
|
|
13112
|
+
// Query all work items for this instance
|
|
13113
|
+
const workItems = await this.entityStorageService.query('WorkflowManagement.WorkItem', {
|
|
13114
|
+
skip: 0,
|
|
13115
|
+
take: 1000,
|
|
13116
|
+
filter: {
|
|
13117
|
+
logic: 'and',
|
|
13118
|
+
filters: [
|
|
13119
|
+
{
|
|
13120
|
+
field: 'instanceId',
|
|
13121
|
+
operator: { type: 'equal' },
|
|
13122
|
+
value: instanceId,
|
|
13123
|
+
},
|
|
13124
|
+
],
|
|
13125
|
+
},
|
|
13126
|
+
});
|
|
13127
|
+
console.log(`[AXCWorkflowEngine] 📦 Found ${workItems.items?.length || 0} work items to update`);
|
|
13128
|
+
// Update each work item
|
|
13129
|
+
for (const workItem of workItems.items || []) {
|
|
13130
|
+
if (!workItem.entityRefId || !workItem.entityRefType) {
|
|
13131
|
+
const updatedWorkItem = {
|
|
13132
|
+
...workItem,
|
|
13133
|
+
entityRefId,
|
|
13134
|
+
entityRefType,
|
|
13135
|
+
updatedAt: new Date().toISOString(),
|
|
13136
|
+
};
|
|
13137
|
+
await this.entityStorageService.updateOne('WorkflowManagement.WorkItem', workItem.id, updatedWorkItem);
|
|
13138
|
+
console.log(`[AXCWorkflowEngine] ✅ Updated work item ${workItem.id} with entity reference:`, {
|
|
13139
|
+
workItemId: workItem.id,
|
|
13140
|
+
entityRefId,
|
|
13141
|
+
entityRefType,
|
|
13142
|
+
});
|
|
13143
|
+
// Also try to set assignee from entity data
|
|
13144
|
+
// COMMENTED FOR TESTING: Allow all tasks to appear in task board
|
|
13145
|
+
// if (!workItem.assignedUserId) {
|
|
13146
|
+
// try {
|
|
13147
|
+
// await this.updateWorkItemAssigneeFromEntity(workItem.id, entityRefType, entityRefId);
|
|
13148
|
+
// } catch (error) {
|
|
13149
|
+
// console.warn(`[AXCWorkflowEngine] ⚠️ Failed to set assignee for work item ${workItem.id}:`, error);
|
|
13150
|
+
// }
|
|
13151
|
+
// }
|
|
13152
|
+
}
|
|
13153
|
+
}
|
|
13154
|
+
}
|
|
13155
|
+
catch (error) {
|
|
13156
|
+
console.error(`[AXCWorkflowEngine] ❌ Failed to update work items entity reference:`, error);
|
|
13157
|
+
// Don't fail workflow execution if update fails
|
|
13158
|
+
}
|
|
13159
|
+
}
|
|
13160
|
+
/**
|
|
13161
|
+
* Update work item assignee from entity data (e.g., employee.manager.userId for leave requests).
|
|
13162
|
+
*/
|
|
13163
|
+
async updateWorkItemAssigneeFromEntity(workItemId, entityRefType, entityRefId) {
|
|
13164
|
+
try {
|
|
13165
|
+
console.log(`[AXCWorkflowEngine] 👤 Setting assignee from entity data:`, {
|
|
13166
|
+
workItemId,
|
|
13167
|
+
entityRefType,
|
|
13168
|
+
entityRefId,
|
|
13169
|
+
});
|
|
13170
|
+
// Load entity data
|
|
13171
|
+
const entityData = await this.entityStorageService.getOne(entityRefType, entityRefId);
|
|
13172
|
+
if (!entityData) {
|
|
13173
|
+
console.warn(`[AXCWorkflowEngine] ⚠️ Entity data not found: ${entityRefType}:${entityRefId}`);
|
|
13174
|
+
return;
|
|
13175
|
+
}
|
|
13176
|
+
// Extract assignee based on entity type
|
|
13177
|
+
let assignedUserId = null;
|
|
13178
|
+
// For leave requests: use employee.manager.userId
|
|
13179
|
+
if (entityRefType === 'HumanCapitalManagement.LeaveRequest') {
|
|
13180
|
+
assignedUserId = entityData.employee?.manager?.userId || entityData.employeeId || null;
|
|
13181
|
+
console.log(`[AXCWorkflowEngine] 📋 Leave request assignee:`, {
|
|
13182
|
+
employeeId: entityData.employeeId,
|
|
13183
|
+
managerUserId: entityData.employee?.manager?.userId,
|
|
13184
|
+
assignedUserId,
|
|
13185
|
+
});
|
|
13186
|
+
}
|
|
13187
|
+
// Update work item if assignee found
|
|
13188
|
+
if (assignedUserId) {
|
|
13189
|
+
const workItem = await this.entityStorageService.getOne('WorkflowManagement.WorkItem', workItemId);
|
|
13190
|
+
if (workItem) {
|
|
13191
|
+
const updatedWorkItem = {
|
|
13192
|
+
...workItem,
|
|
13193
|
+
assignedUserId,
|
|
13194
|
+
assignedAt: new Date().toISOString(),
|
|
13195
|
+
updatedAt: new Date().toISOString(),
|
|
13196
|
+
};
|
|
13197
|
+
await this.entityStorageService.updateOne('WorkflowManagement.WorkItem', workItemId, updatedWorkItem);
|
|
13198
|
+
console.log(`[AXCWorkflowEngine] ✅ Updated work item assignee:`, {
|
|
13199
|
+
workItemId,
|
|
13200
|
+
assignedUserId,
|
|
13201
|
+
});
|
|
13202
|
+
}
|
|
13203
|
+
}
|
|
13204
|
+
else {
|
|
13205
|
+
console.log(`[AXCWorkflowEngine] ℹ️ No assignee found for entity ${entityRefType}:${entityRefId}`);
|
|
13206
|
+
}
|
|
13207
|
+
}
|
|
13208
|
+
catch (error) {
|
|
13209
|
+
console.warn(`[AXCWorkflowEngine] ⚠️ Failed to set assignee from entity data:`, error);
|
|
13210
|
+
// Don't fail if assignee update fails
|
|
13211
|
+
}
|
|
13212
|
+
}
|
|
12981
13213
|
/**
|
|
12982
13214
|
* Consume (mark as consumed) a bookmark for a workflow instance.
|
|
12983
13215
|
*
|
|
@@ -13051,7 +13283,12 @@ class AXCWorkflowEngine {
|
|
|
13051
13283
|
}
|
|
13052
13284
|
// Extract state from workflowState (ERD: WORKFLOW_INSTANCE_STATE)
|
|
13053
13285
|
// Properties map to variables
|
|
13054
|
-
const
|
|
13286
|
+
const properties = (state.properties || {});
|
|
13287
|
+
const { __activityOutputs, __lastActivityOutput, ...variables } = properties;
|
|
13288
|
+
const activityOutputs = __activityOutputs && typeof __activityOutputs === 'object'
|
|
13289
|
+
? __activityOutputs
|
|
13290
|
+
: {};
|
|
13291
|
+
const lastActivityOutput = __lastActivityOutput;
|
|
13055
13292
|
const input = state.input || {};
|
|
13056
13293
|
const output = state.output || {};
|
|
13057
13294
|
// Normalize dates (instance.updatedAt is always string in AXPWorkflowInstance)
|
|
@@ -13064,6 +13301,8 @@ class AXCWorkflowEngine {
|
|
|
13064
13301
|
status,
|
|
13065
13302
|
currentStepId,
|
|
13066
13303
|
variables,
|
|
13304
|
+
activityOutputs,
|
|
13305
|
+
lastActivityOutput,
|
|
13067
13306
|
input,
|
|
13068
13307
|
output,
|
|
13069
13308
|
lastUpdated
|
|
@@ -13119,7 +13358,11 @@ class AXCWorkflowEngine {
|
|
|
13119
13358
|
instance.workflowState.subStatus = subStatus;
|
|
13120
13359
|
instance.workflowState.input = instanceState.input || {};
|
|
13121
13360
|
instance.workflowState.output = instanceState.output || {};
|
|
13122
|
-
instance.workflowState.properties =
|
|
13361
|
+
instance.workflowState.properties = {
|
|
13362
|
+
...(instanceState.variables || {}),
|
|
13363
|
+
__activityOutputs: instanceState.activityOutputs || {},
|
|
13364
|
+
__lastActivityOutput: instanceState.lastActivityOutput,
|
|
13365
|
+
};
|
|
13123
13366
|
instance.workflowState.updatedAt = now;
|
|
13124
13367
|
if (instanceState.status === 'completed' || instanceState.status === 'error') {
|
|
13125
13368
|
instance.workflowState.finishedAt = now;
|
|
@@ -13261,6 +13504,12 @@ class AXCWorkflowEngine {
|
|
|
13261
13504
|
const connections = workflow.graph.connections || [];
|
|
13262
13505
|
// Apply frontend output to workflow state
|
|
13263
13506
|
const output = request.output || {};
|
|
13507
|
+
let activityOutputs = { ...(state.activityOutputs || {}) };
|
|
13508
|
+
let lastActivityOutput = output;
|
|
13509
|
+
activityOutputs = {
|
|
13510
|
+
...activityOutputs,
|
|
13511
|
+
[request.activityNode]: output,
|
|
13512
|
+
};
|
|
13264
13513
|
state = {
|
|
13265
13514
|
...state,
|
|
13266
13515
|
variables: {
|
|
@@ -13268,8 +13517,43 @@ class AXCWorkflowEngine {
|
|
|
13268
13517
|
...output, // Merge frontend output into variables
|
|
13269
13518
|
[`${request.activityNode}_outcome`]: request.outcome, // Keep outcome for reference
|
|
13270
13519
|
},
|
|
13520
|
+
activityOutputs,
|
|
13521
|
+
lastActivityOutput,
|
|
13271
13522
|
lastUpdated: new Date(),
|
|
13272
13523
|
};
|
|
13524
|
+
// 🎯 Update entityRefId and entityRefType if entity was created
|
|
13525
|
+
// Check if this activity created an entity (workflow-activity:create-entity)
|
|
13526
|
+
const completedActivity = this.findActivityInGraph(workflow.graph, request.activityNode);
|
|
13527
|
+
if (completedActivity?.name === 'workflow-activity:create-entity' && output['id']) {
|
|
13528
|
+
// Extract entity type from activity inputs
|
|
13529
|
+
const entityModule = completedActivity.inputs?.module || '';
|
|
13530
|
+
const entityName = completedActivity.inputs?.entity || '';
|
|
13531
|
+
const entityType = entityModule && entityName ? `${entityModule}.${entityName}` : null;
|
|
13532
|
+
const entityId = output['id'];
|
|
13533
|
+
console.log(`[AXCWorkflowEngine] 🔗 Entity created in workflow:`, {
|
|
13534
|
+
activityNode: request.activityNode,
|
|
13535
|
+
entityId,
|
|
13536
|
+
entityType,
|
|
13537
|
+
entityModule,
|
|
13538
|
+
entityName,
|
|
13539
|
+
});
|
|
13540
|
+
if (entityId && entityType) {
|
|
13541
|
+
// Update workflow instance with entity reference
|
|
13542
|
+
const instance = await this.db.instances.get(request.instanceId);
|
|
13543
|
+
if (instance) {
|
|
13544
|
+
instance.entityRefId = entityId;
|
|
13545
|
+
instance.entityRefType = entityType;
|
|
13546
|
+
await this.db.instances.put(instance, instance.id);
|
|
13547
|
+
console.log(`[AXCWorkflowEngine] ✅ Updated workflow instance with entity reference:`, {
|
|
13548
|
+
instanceId: request.instanceId,
|
|
13549
|
+
entityRefId: entityId,
|
|
13550
|
+
entityRefType: entityType,
|
|
13551
|
+
});
|
|
13552
|
+
// Update all work items for this instance with entity reference
|
|
13553
|
+
await this.updateWorkItemsEntityRef(request.instanceId, entityId, entityType);
|
|
13554
|
+
}
|
|
13555
|
+
}
|
|
13556
|
+
}
|
|
13273
13557
|
// Find next activity based on outcome from frontend
|
|
13274
13558
|
const nextConnection = connections.find((conn) => conn.source.activtyName === request.activityNode &&
|
|
13275
13559
|
(conn.source.port === request.outcome || (!conn.source.port && request.outcome === 'Done')));
|
|
@@ -13304,7 +13588,7 @@ class AXCWorkflowEngine {
|
|
|
13304
13588
|
await this.updateInstanceFromState(request.instanceId, state);
|
|
13305
13589
|
throw new Error(`Next activity '${nextConnection.target.activtyName}' not found in workflow graph`);
|
|
13306
13590
|
}
|
|
13307
|
-
|
|
13591
|
+
// `activityOutputs` and `lastActivityOutput` are tracked and persisted in `state`.
|
|
13308
13592
|
while (currentActivity && executionCount < maxExecutions) {
|
|
13309
13593
|
executionCount++;
|
|
13310
13594
|
// Map activity name (registry key) to activity type
|
|
@@ -13332,6 +13616,8 @@ class AXCWorkflowEngine {
|
|
|
13332
13616
|
// Update state (suspended for human-task, running for ui-activity)
|
|
13333
13617
|
state = {
|
|
13334
13618
|
...state,
|
|
13619
|
+
activityOutputs,
|
|
13620
|
+
lastActivityOutput,
|
|
13335
13621
|
status: pendingTask.taskType === 'human-task' ? 'suspended' : 'running',
|
|
13336
13622
|
currentStepId: currentActivity.id,
|
|
13337
13623
|
};
|
|
@@ -13348,6 +13634,10 @@ class AXCWorkflowEngine {
|
|
|
13348
13634
|
console.log(`[AXCWorkflowEngine] ⚙️ Executing backend activity '${currentActivity.name || currentActivity.id}' (${activityType})`);
|
|
13349
13635
|
const executionResult = await this.executeBackendActivityLocally(currentActivity, { ...state.variables, ...state.input }, state);
|
|
13350
13636
|
lastActivityOutput = executionResult.output;
|
|
13637
|
+
activityOutputs = {
|
|
13638
|
+
...activityOutputs,
|
|
13639
|
+
[currentActivity.id]: executionResult.output,
|
|
13640
|
+
};
|
|
13351
13641
|
// Update variables with output
|
|
13352
13642
|
state = {
|
|
13353
13643
|
...state,
|
|
@@ -13355,6 +13645,8 @@ class AXCWorkflowEngine {
|
|
|
13355
13645
|
...state.variables,
|
|
13356
13646
|
...executionResult.output,
|
|
13357
13647
|
},
|
|
13648
|
+
activityOutputs,
|
|
13649
|
+
lastActivityOutput,
|
|
13358
13650
|
currentStepId: currentActivity.id,
|
|
13359
13651
|
lastUpdated: new Date(),
|
|
13360
13652
|
};
|
|
@@ -13370,6 +13662,8 @@ class AXCWorkflowEngine {
|
|
|
13370
13662
|
status: 'completed',
|
|
13371
13663
|
currentStepId: undefined,
|
|
13372
13664
|
output: state.variables,
|
|
13665
|
+
activityOutputs,
|
|
13666
|
+
lastActivityOutput,
|
|
13373
13667
|
};
|
|
13374
13668
|
await this.updateInstanceFromState(request.instanceId, state);
|
|
13375
13669
|
return {
|
|
@@ -13410,6 +13704,8 @@ class AXCWorkflowEngine {
|
|
|
13410
13704
|
status: 'completed',
|
|
13411
13705
|
currentStepId: undefined,
|
|
13412
13706
|
output: state.variables,
|
|
13707
|
+
activityOutputs,
|
|
13708
|
+
lastActivityOutput,
|
|
13413
13709
|
};
|
|
13414
13710
|
await this.updateInstanceFromState(request.instanceId, state);
|
|
13415
13711
|
return {
|