diff --git a/FeatureFlags.js b/FeatureFlags.js index d4926a374..deab1f4ac 100644 --- a/FeatureFlags.js +++ b/FeatureFlags.js @@ -47,8 +47,8 @@ module.exports = { //feature to switch to prisma from fs enableUseDB: false, + //feature to use GCP_bucket / fs depending on deployment env to store blobs enableUseFileManager: false, - // ----------------------------------------------------------------------------- // Chopping Block // diff --git a/src/engine/e2e_tests/process/data/processBPMN/basicUserTaskProcess.xml b/src/engine/e2e_tests/process/data/processBPMN/basicUserTaskProcess.xml index f2d3dfa3d..38d3de047 100644 --- a/src/engine/e2e_tests/process/data/processBPMN/basicUserTaskProcess.xml +++ b/src/engine/e2e_tests/process/data/processBPMN/basicUserTaskProcess.xml @@ -1,5 +1,5 @@ - + SequenceFlow_0hqzz44 diff --git a/src/engine/e2e_tests/process/data/processBPMN/withImage.xml b/src/engine/e2e_tests/process/data/processBPMN/withImage.xml index ec8eeafa5..56014e303 100644 --- a/src/engine/e2e_tests/process/data/processBPMN/withImage.xml +++ b/src/engine/e2e_tests/process/data/processBPMN/withImage.xml @@ -1,5 +1,5 @@ - + Flow_1g4gvbf diff --git a/src/engine/e2e_tests/process/deployment/deployment.e2e.test.js b/src/engine/e2e_tests/process/deployment/deployment.e2e.test.js index cc12fb795..b20e1b190 100644 --- a/src/engine/e2e_tests/process/deployment/deployment.e2e.test.js +++ b/src/engine/e2e_tests/process/deployment/deployment.e2e.test.js @@ -1305,7 +1305,7 @@ describe('Test deploying a process', () => { // deploy and start process on machine 4 await deployProcess('parallelScriptTaskDynamicProcess', engineNames[0]); - let instanceId = await startInstance(definitionId, 123, engineNames[0]); + let instanceId = await startInstance(definitionId, '123', engineNames[0]); // after starting the process, wait 5 seconds before requesting the state of the instance await new Promise((resolve) => setTimeout(() => resolve(), 5000)); @@ -2528,8 +2528,8 @@ describe('Test deploying a process', () => { { type: 'MIGRATION', time: expect.any(Number), - sourceVersion: 111, - targetVersion: 123, + sourceVersion: '111', + targetVersion: '123', }, ]); }); @@ -2699,8 +2699,8 @@ describe('Test deploying a process', () => { { type: 'MIGRATION', time: expect.any(Number), - sourceVersion: 111, - targetVersion: 456, + sourceVersion: '111', + targetVersion: '456', }, { type: 'TOKEN-MOVE', @@ -2872,8 +2872,8 @@ describe('Test deploying a process', () => { { type: 'MIGRATION', time: expect.any(Number), - sourceVersion: 111, - targetVersion: 456, + sourceVersion: '111', + targetVersion: '456', }, { type: 'TOKEN-MOVE', diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/adaptiveProcess/adaptiveProcess.xml b/src/engine/e2e_tests/process/deployment/testProcesses/adaptiveProcess/adaptiveProcess.xml index 9645a28a0..c8aeba68d 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/adaptiveProcess/adaptiveProcess.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/adaptiveProcess/adaptiveProcess.xml @@ -1,5 +1,5 @@ - + Flow_0b9vgiw diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/basicStaticProcess/basicStaticProcess.xml b/src/engine/e2e_tests/process/deployment/testProcesses/basicStaticProcess/basicStaticProcess.xml index bbeafab46..bd7da489d 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/basicStaticProcess/basicStaticProcess.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/basicStaticProcess/basicStaticProcess.xml @@ -1,5 +1,5 @@ - + Flow_09gzsbw diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/callActivityStaticProcess/callActivityStaticProcess.xml b/src/engine/e2e_tests/process/deployment/testProcesses/callActivityStaticProcess/callActivityStaticProcess.xml index 618246cdc..d96fe0ad5 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/callActivityStaticProcess/callActivityStaticProcess.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/callActivityStaticProcess/callActivityStaticProcess.xml @@ -1,6 +1,6 @@ - - + + Flow_0ad549t diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/deciderStopInstanceProcess/deciderStopInstanceProcess.xml b/src/engine/e2e_tests/process/deployment/testProcesses/deciderStopInstanceProcess/deciderStopInstanceProcess.xml index 95aebea53..d152ed7d3 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/deciderStopInstanceProcess/deciderStopInstanceProcess.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/deciderStopInstanceProcess/deciderStopInstanceProcess.xml @@ -1,5 +1,5 @@ - + diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/deciderStopTokenProcess/deciderStopTokenProcess.xml b/src/engine/e2e_tests/process/deployment/testProcesses/deciderStopTokenProcess/deciderStopTokenProcess.xml index 08cf9de7e..9e2fdd3d5 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/deciderStopTokenProcess/deciderStopTokenProcess.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/deciderStopTokenProcess/deciderStopTokenProcess.xml @@ -1,5 +1,5 @@ - + diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/deploymentWaitingProcess/deploymentWaitingProcess.xml b/src/engine/e2e_tests/process/deployment/testProcesses/deploymentWaitingProcess/deploymentWaitingProcess.xml index 5e37e3c24..671227538 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/deploymentWaitingProcess/deploymentWaitingProcess.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/deploymentWaitingProcess/deploymentWaitingProcess.xml @@ -1,5 +1,5 @@ - + diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/externalActivity/externalActivity.xml b/src/engine/e2e_tests/process/deployment/testProcesses/externalActivity/externalActivity.xml index fd6da9712..58d859551 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/externalActivity/externalActivity.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/externalActivity/externalActivity.xml @@ -1,5 +1,5 @@ - + Flow_0gtagl3 diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/migrationExtended/migrationExtended.xml b/src/engine/e2e_tests/process/deployment/testProcesses/migrationExtended/migrationExtended.xml index 625d66bc5..580e387f7 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/migrationExtended/migrationExtended.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/migrationExtended/migrationExtended.xml @@ -1,5 +1,5 @@ - + Flow_0b9vgiw diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/migrationInitial/migrationInitial.xml b/src/engine/e2e_tests/process/deployment/testProcesses/migrationInitial/migrationInitial.xml index a3a9ae831..458986604 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/migrationInitial/migrationInitial.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/migrationInitial/migrationInitial.xml @@ -1,5 +1,5 @@ - + Flow_0b9vgiw diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/migrationReplace/migrationReplace.xml b/src/engine/e2e_tests/process/deployment/testProcesses/migrationReplace/migrationReplace.xml index df72e0c9d..0080a7436 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/migrationReplace/migrationReplace.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/migrationReplace/migrationReplace.xml @@ -1,5 +1,5 @@ - + Flow_0b9vgiw diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/parallelScriptTaskDynamicProcess/parallelScriptTaskDynamicProcess.xml b/src/engine/e2e_tests/process/deployment/testProcesses/parallelScriptTaskDynamicProcess/parallelScriptTaskDynamicProcess.xml index a81ed11fa..cc86d5607 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/parallelScriptTaskDynamicProcess/parallelScriptTaskDynamicProcess.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/parallelScriptTaskDynamicProcess/parallelScriptTaskDynamicProcess.xml @@ -1,5 +1,5 @@ - + diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/scriptTaskStaticProcess/scriptTaskStaticProcess.xml b/src/engine/e2e_tests/process/deployment/testProcesses/scriptTaskStaticProcess/scriptTaskStaticProcess.xml index 34082da5c..42d86964b 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/scriptTaskStaticProcess/scriptTaskStaticProcess.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/scriptTaskStaticProcess/scriptTaskStaticProcess.xml @@ -1,5 +1,5 @@ - + diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/threeEngineDynamicHC/threeEngineDynamicHC.xml b/src/engine/e2e_tests/process/deployment/testProcesses/threeEngineDynamicHC/threeEngineDynamicHC.xml index 0ba33548f..0b17d37e4 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/threeEngineDynamicHC/threeEngineDynamicHC.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/threeEngineDynamicHC/threeEngineDynamicHC.xml @@ -1,5 +1,5 @@ - + Flow_1dgdtpu diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/threeEngineDynamicSC/threeEngineDynamicSC.xml b/src/engine/e2e_tests/process/deployment/testProcesses/threeEngineDynamicSC/threeEngineDynamicSC.xml index 3babbe8fc..ff1cd400a 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/threeEngineDynamicSC/threeEngineDynamicSC.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/threeEngineDynamicSC/threeEngineDynamicSC.xml @@ -1,5 +1,5 @@ - + diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/timerCatchingStaticProcess/timerCatchingStaticProcess.xml b/src/engine/e2e_tests/process/deployment/testProcesses/timerCatchingStaticProcess/timerCatchingStaticProcess.xml index 8dce75ad7..716305e01 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/timerCatchingStaticProcess/timerCatchingStaticProcess.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/timerCatchingStaticProcess/timerCatchingStaticProcess.xml @@ -1,5 +1,5 @@ - + diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineDynamicHC/twoEngineDynamicHC.xml b/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineDynamicHC/twoEngineDynamicHC.xml index 8074cb69e..46c920cf7 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineDynamicHC/twoEngineDynamicHC.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineDynamicHC/twoEngineDynamicHC.xml @@ -1,5 +1,5 @@ - + diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineStatic/twoEngineStatic.xml b/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineStatic/twoEngineStatic.xml index e3a6060a1..5bf7b466d 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineStatic/twoEngineStatic.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineStatic/twoEngineStatic.xml @@ -1,5 +1,5 @@ - + Flow_0rsi5hp diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineTerminationStatic/twoEngineTerminationStatic.xml b/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineTerminationStatic/twoEngineTerminationStatic.xml index 2fc1f35e7..adfa5922c 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineTerminationStatic/twoEngineTerminationStatic.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineTerminationStatic/twoEngineTerminationStatic.xml @@ -1,5 +1,5 @@ - + diff --git a/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineVariablesStatic/twoEngineVariablesStatic.xml b/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineVariablesStatic/twoEngineVariablesStatic.xml index c0027827e..5e84f82e4 100644 --- a/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineVariablesStatic/twoEngineVariablesStatic.xml +++ b/src/engine/e2e_tests/process/deployment/testProcesses/twoEngineVariablesStatic/twoEngineVariablesStatic.xml @@ -1,5 +1,5 @@ - + diff --git a/src/engine/e2e_tests/process/processEndpoint.e2e.test.js b/src/engine/e2e_tests/process/processEndpoint.e2e.test.js index f8ef49843..684a0ade4 100644 --- a/src/engine/e2e_tests/process/processEndpoint.e2e.test.js +++ b/src/engine/e2e_tests/process/processEndpoint.e2e.test.js @@ -36,7 +36,7 @@ describe('Test process endpoints', () => { deploymentMethod: 'dynamic', deploymentDate: expect.any(Number), needs: { html: ['userTaskFileName'], imports: [], images: [] }, - version: 123, + versionId: '123', }, ], instances: [], @@ -61,7 +61,7 @@ describe('Test process endpoints', () => { imports: [], images: ['Activity_08fwikp_image123e6803-63a8-4cf1-9596-2999fdd016a7.png'], }, - version: 1671026484009, + versionId: '1671026484009', versionName: 'Version 1', versionDescription: 'Initial Version', basedOnVersion: '1671024712832', @@ -83,7 +83,7 @@ describe('Test process endpoints', () => { deploymentMethod: 'dynamic', deploymentDate: expect.any(Number), needs: { html: ['userTaskFileName'], imports: [], images: [] }, - version: 123, + versionId: '123', }, ], instances: [], @@ -94,7 +94,7 @@ describe('Test process endpoints', () => { it('returns an array containing all the known versions of a process on a GET request', async () => { const getResponse = await request.get('/process/definitionId/versions'); expect(getResponse.status).toBe(200); - expect(getResponse.body).toStrictEqual([123]); + expect(getResponse.body).toStrictEqual(['123']); }); describe('/process/{definitionId}/versions/{version}', () => { @@ -107,7 +107,7 @@ describe('Test process endpoints', () => { deploymentMethod: 'dynamic', deploymentDate: expect.any(Number), needs: { html: ['userTaskFileName'], imports: [], images: [] }, - version: 123, + versionId: '123', }); }); }); @@ -162,7 +162,7 @@ describe('Test process endpoints', () => { 'User_Task_1qjpbcl_image72fe83de-2c44-4d1f-ae71-6b323bee7f1c.png', ], }, - version: 1671026484009, + versionId: '1671026484009', versionName: 'Version 1', versionDescription: 'Initial Version', basedOnVersion: '1671024712832', diff --git a/src/engine/native/node/native-config/src/config_default.json b/src/engine/native/node/native-config/src/config_default.json index 23e33fc40..7bad87cd3 100644 --- a/src/engine/native/node/native-config/src/config_default.json +++ b/src/engine/native/node/native-config/src/config_default.json @@ -9,7 +9,8 @@ "maxProcessLogEntries": 500, "maxProcessLogTables": 5, "rotationInterval": 600, - "maxStandardLogEntries": 1000 + "maxStandardLogEntries": 1000, + "mqttLevel": "info" }, "processes": { "acceptUserTasks": false, diff --git a/src/engine/universal/core/src/__tests__/bpmn/importer.bpmn b/src/engine/universal/core/src/__tests__/bpmn/importer.bpmn index 5e57fc41b..713703bfd 100644 --- a/src/engine/universal/core/src/__tests__/bpmn/importer.bpmn +++ b/src/engine/universal/core/src/__tests__/bpmn/importer.bpmn @@ -1,6 +1,6 @@ - + Flow_0xrwj67 diff --git a/src/engine/universal/core/src/__tests__/bpmn/manualCallActivityInterruption.bpmn b/src/engine/universal/core/src/__tests__/bpmn/manualCallActivityInterruption.bpmn index 5f4bca559..2e2157fd5 100644 --- a/src/engine/universal/core/src/__tests__/bpmn/manualCallActivityInterruption.bpmn +++ b/src/engine/universal/core/src/__tests__/bpmn/manualCallActivityInterruption.bpmn @@ -1,6 +1,6 @@ - + Flow_0xrwj67 diff --git a/src/engine/universal/core/src/engine/__tests__/shouldActivateFlowNode.test.js b/src/engine/universal/core/src/engine/__tests__/shouldActivateFlowNode.test.js index 4ac9f597b..a861bfe56 100644 --- a/src/engine/universal/core/src/engine/__tests__/shouldActivateFlowNode.test.js +++ b/src/engine/universal/core/src/engine/__tests__/shouldActivateFlowNode.test.js @@ -106,7 +106,7 @@ describe('Tests for the function that is supposed to decide if a flow node shoul // mock the return values of the function analyzing the bpmn or returning the import bpmn getTargetDefinitionsAndProcessIdForCallActivityByObject.mockReturnValue({ definitionId: 'callActivityDefinitionId', - version: 456, + versionId: '456', }); mockRoot = { @@ -143,7 +143,7 @@ describe('Tests for the function that is supposed to decide if a flow node shoul // check if the creation of the instance of the imported process was triggered expect(mockEngine._management.createInstance).toHaveBeenCalledWith( 'callActivityDefinitionId', - 456, + '456', { mockVariable: 'mockValue' }, undefined, expect.any(Function), diff --git a/src/engine/universal/core/src/engine/engine.js b/src/engine/universal/core/src/engine/engine.js index 8c4f75c14..05ecfeb69 100644 --- a/src/engine/universal/core/src/engine/engine.js +++ b/src/engine/universal/core/src/engine/engine.js @@ -102,18 +102,18 @@ class Engine { * Deploys the process version to the NeoBPMN Engine making it ready to start instances * * @param {string} definitionId The name of the file of the (main) process (as stored in the `data`) - * @param {number} the version of the process to deploy + * @param {string} the version of the process to deploy */ - async deployProcessVersion(definitionId, version) { - if (!this._versionProcessMapping[version]) { + async deployProcessVersion(definitionId, versionId) { + if (!this._versionProcessMapping[versionId]) { // Fetch the stored BPMN - const bpmn = await distribution.db.getProcessVersion(definitionId, version); + const bpmn = await distribution.db.getProcessVersion(definitionId, versionId); const [processId] = await getProcessIds(bpmn); // validate imports and user tasks on first deploy || assumes validity for imported processes since we expect to have a fully valid main process - if (!(await distribution.db.isProcessVersionValid(definitionId, version))) { + if (!(await distribution.db.isProcessVersionValid(definitionId, versionId))) { throw new Error( - `Process version ${version} for process ${processId} with definitionId ${definitionId} is invalid. It can't be deployed.`, + `Process version ${versionId} for process ${processId} with definitionId ${definitionId} is invalid. It can't be deployed.`, ); } @@ -136,7 +136,7 @@ class Engine { this.machineInformation = { id, name: name || hostname, ip, port }; - const process = await NeoEngine.BpmnProcess.fromXml(`${definitionId}-${version}`, bpmn, { + const process = await NeoEngine.BpmnProcess.fromXml(`${definitionId}-${versionId}`, bpmn, { shouldPassTokenHook: getShouldPassToken(this), shouldActivateFlowNodeHook: getShouldActivateFlowNode(this), }); @@ -150,9 +150,9 @@ class Engine { // (possibly multiple versions and instances of that process though) this.definitionId = definitionId; - this._versionProcessMapping[version] = process; - this._versionBpmnMapping[version] = bpmn; - this.versions.push(version); + this._versionProcessMapping[versionId] = process; + this._versionBpmnMapping[versionId] = bpmn; + this.versions.push(versionId); } } @@ -162,7 +162,7 @@ class Engine { * When encountering User Tasks in the ongoing execution, they are added to * the `userTasks` array property. * - * @param {number} the version of the process to start + * @param {string} the version of the process to start * @param {object} processVariables The process variables in the init state * @param {object|string} instance contains the instance object that came from another engine to be contiued here (might contain only an id of an activity to start) * @param {function} onStarted function that is executed when the new instance starts @@ -439,6 +439,7 @@ class Engine { const state = instance.getState(); + // FIXME: Doesn't work when version ID is not a number string (e.g. uuid) const processId = state.processId.substring(0, state.processId.lastIndexOf('-')); const processVersion = state.processId.substring(processId.length + 1); @@ -448,8 +449,8 @@ class Engine { return { type: entry.type, time: entry.time, - sourceVersion: parseInt(entry.from.substring(processId.length + 1)), - targetVersion: parseInt(entry.to.substring(processId.length + 1)), + sourceVersion: entry.from.substring(processId.length + 1), + targetVersion: entry.to.substring(processId.length + 1), }; } else { return entry; diff --git a/src/engine/universal/core/src/engine/shouldActivateFlowNode.js b/src/engine/universal/core/src/engine/shouldActivateFlowNode.js index b1e78941e..c84174f34 100644 --- a/src/engine/universal/core/src/engine/shouldActivateFlowNode.js +++ b/src/engine/universal/core/src/engine/shouldActivateFlowNode.js @@ -100,7 +100,7 @@ function onUserTask(engine, instance, tokenId, userTask) { function onCallActivity(engine, instance, tokenId, callActivity) { return new Promise(async (resolve) => { // get necessary process information about the process referenced by the callActivity - const { definitionId, version } = getTargetDefinitionsAndProcessIdForCallActivityByObject( + const { definitionId, versionId } = getTargetDefinitionsAndProcessIdForCallActivityByObject( getRootFromElement(callActivity), callActivity.id, ); @@ -114,7 +114,7 @@ function onCallActivity(engine, instance, tokenId, callActivity) { // make sure that the imported process is started with the correct version and the current instance variables await engine._management.createInstance( definitionId, - version, + versionId, instance.getVariables(), undefined, // onStarted callBack: log that we started an instance of a callActivity process and put a reference to the instance into the token diff --git a/src/engine/universal/core/src/management.js b/src/engine/universal/core/src/management.js index d30bbf1b9..349e8902b 100644 --- a/src/engine/universal/core/src/management.js +++ b/src/engine/universal/core/src/management.js @@ -65,7 +65,7 @@ const Management = { /** * Creates a new engine instance for execution of the given process version. * @param {string} definitionId The name of the file the process to start is stored in - * @param {number} version the version of the process to start + * @param {string} version the version of the process to start * @param {object} variables The process variables for the execution * @param {string} [activityID] The optional id of the activity to start execution at (if not at the beginning) * @param {function} [onStarted] an optional callback that should be called when the instance starts diff --git a/src/engine/universal/core/src/messaging-setup.js b/src/engine/universal/core/src/messaging-setup.js index b8f201d49..5ee88420e 100644 --- a/src/engine/universal/core/src/messaging-setup.js +++ b/src/engine/universal/core/src/messaging-setup.js @@ -1,4 +1,5 @@ const { version: proceedVersion } = require('../../../native/node/package.json'); +const { logging } = require('@proceed/machine'); /** * This file contains functionality that handles setup and interactions of the messaging interface with other modules of the engine @@ -58,4 +59,67 @@ module.exports = { } } }, + async setupMonitoringAndLogging(messaging, configModule, machineModule, logger) { + let { serverAddress, baseTopic } = await configModule.readConfig('messaging'); + if (!serverAddress) return; + + if (baseTopic && !baseTopic.endsWith('/')) baseTopic += '/'; + baseTopic += 'proceed-pms'; + + // Monitoring data + const [{ id: machineId }, loadInterval] = await Promise.all([ + machineModule.getMachineInformation(['id']), + configModule.readConfig('engine.loadInterval'), + ]); + + setInterval(async () => { + try { + const machineData = await machineModule.getMachineInformation(); + await messaging.publish(`${baseTopic}/engine/${machineId}/machine/monitoring`, machineData); + } catch (e) { + logger.error('Failed to publish monitoring data'); + } + }, loadInterval * 1000); + + // Logging data + const mqttLevel = await configModule.readConfig('logs.mqttLevel'); + const orderedLevels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal']; + const mqttLevelIdx = orderedLevels.indexOf(mqttLevel); + const logGuard = (level) => orderedLevels.indexOf(level) >= mqttLevelIdx; + + logging.registerCallback(async (obj, log) => { + try { + if (!logGuard(log && log.level)) return; + + const sentMessages = []; + const print = `[${log.level.toUpperCase()}] ${log.moduleName}${obj.definitionId || ''} ${log.msg}`; + + sentMessages.push(messaging.publish(`${baseTopic}/engine/${machineId}/logging`, print)); + + if (obj.definitionId) { + sentMessages.push( + messaging.publish(`${baseTopic}/engine/${machineId}/logging/process`, print), + ); + + if (log.instanceId) { + sentMessages.push( + messaging.publish( + `${baseTopic}/engine/process/${obj.definitionId}/instance/${log.instanceId}/logging`, + print, + ), + ); + } + } else { + sentMessages.push( + messaging.publish(`${baseTopic}/engine/${machineId}/logging/standard`, print), + ); + } + + await Promise.all(sentMessages); + } catch (e) { + // NOTE: using logger.error could cause an infinite loop if publish keeps failing + console.error(e); + } + }); + }, }; diff --git a/src/engine/universal/core/src/module.js b/src/engine/universal/core/src/module.js index 3e44b6f8d..4f7f27482 100644 --- a/src/engine/universal/core/src/module.js +++ b/src/engine/universal/core/src/module.js @@ -10,7 +10,7 @@ const monitoring = require('@proceed/monitoring'); const management = require('./management.js'); const { setup5thIndustryEndpoints } = require('./engine/5thIndustry.js'); const { enableInterruptedInstanceRecovery } = require('../../../../../FeatureFlags.js'); -const { setupMessaging } = require('./messaging-setup.js'); +const { setupMessaging, setupMonitoringAndLogging } = require('./messaging-setup.js'); const { enableMessaging, enable5thIndustryIntegration } = require('../../../../../FeatureFlags.js'); const configObject = { @@ -53,6 +53,7 @@ module.exports = { if (enableMessaging) { await setupMessaging(system.messaging, config, machineInformation, logger); + await setupMonitoringAndLogging(system.messaging, config, machineInformation, logger); } if (!options.silentMode) { diff --git a/src/engine/universal/distribution/src/database/__tests__/data/OneImage.xml b/src/engine/universal/distribution/src/database/__tests__/data/OneImage.xml index a67b9ad42..81dbe13df 100644 --- a/src/engine/universal/distribution/src/database/__tests__/data/OneImage.xml +++ b/src/engine/universal/distribution/src/database/__tests__/data/OneImage.xml @@ -1,5 +1,5 @@ - + Flow_1g4gvbf diff --git a/src/engine/universal/distribution/src/database/__tests__/data/OneImport.xml b/src/engine/universal/distribution/src/database/__tests__/data/OneImport.xml index ae9031a46..dc2446a12 100644 --- a/src/engine/universal/distribution/src/database/__tests__/data/OneImport.xml +++ b/src/engine/universal/distribution/src/database/__tests__/data/OneImport.xml @@ -1,6 +1,6 @@ - - + + diff --git a/src/engine/universal/distribution/src/database/__tests__/data/OneProcess.xml b/src/engine/universal/distribution/src/database/__tests__/data/OneProcess.xml index 65f6561c6..001cd19dc 100644 --- a/src/engine/universal/distribution/src/database/__tests__/data/OneProcess.xml +++ b/src/engine/universal/distribution/src/database/__tests__/data/OneProcess.xml @@ -1,5 +1,5 @@ - + Flow_0qukoq2 diff --git a/src/engine/universal/distribution/src/database/__tests__/data/OneUserTask.xml b/src/engine/universal/distribution/src/database/__tests__/data/OneUserTask.xml index 9695da4f2..82fdd8bbe 100644 --- a/src/engine/universal/distribution/src/database/__tests__/data/OneUserTask.xml +++ b/src/engine/universal/distribution/src/database/__tests__/data/OneUserTask.xml @@ -1,5 +1,5 @@ - + Flow_0qukoq2 diff --git a/src/engine/universal/distribution/src/database/__tests__/db.test.js b/src/engine/universal/distribution/src/database/__tests__/db.test.js index b55c0254a..c9ba714ae 100644 --- a/src/engine/universal/distribution/src/database/__tests__/db.test.js +++ b/src/engine/universal/distribution/src/database/__tests__/db.test.js @@ -97,7 +97,7 @@ describe('Tests for the functions in the database module', () => { }); describe('isProcessVersionExisting', () => { it('returns false if the process does not exist', async () => { - const result = await db.isProcessVersionExisting('testFile', 123); + const result = await db.isProcessVersionExisting('testFile', 'abc'); expect(result).toBe(false); expect(data.read).toHaveBeenCalledWith('processes.json/testFile'); @@ -105,11 +105,11 @@ describe('Tests for the functions in the database module', () => { it('returns false if the specific version of the process does not exist', async () => { data.read.mockResolvedValueOnce( JSON.stringify({ - 123: {}, + abc: {}, }), ); - const result = await db.isProcessVersionExisting('testFile', 456); + const result = await db.isProcessVersionExisting('testFile', 'def'); expect(result).toBe(false); expect(data.read).toHaveBeenCalledWith('processes.json/testFile'); @@ -117,11 +117,11 @@ describe('Tests for the functions in the database module', () => { it('returns true if the process version exists', async () => { data.read.mockResolvedValueOnce( JSON.stringify({ - 123: {}, + abc: {}, }), ); - const result = await db.isProcessVersionExisting('testFile', 123); + const result = await db.isProcessVersionExisting('testFile', 'abc'); expect(result).toBe(true); expect(data.read).toHaveBeenCalledWith('processes.json/testFile'); @@ -136,7 +136,7 @@ describe('Tests for the functions in the database module', () => { 'processes.json/_a04f4854-6e50-408f-8ec5-18f4541c32e9', ); expect(JSON.parse(data.write.mock.calls[0][1])).toEqual({ - 123: { + abc: { deploymentDate: expect.any(Number), processId: '_958fd9c3-b99d-4e8e-95a1-a0a618eaa9d3', needs: { html: [], imports: [], images: [] }, @@ -144,14 +144,14 @@ describe('Tests for the functions in the database module', () => { }, }); expect(data.write.mock.calls[1][0]).toEqual( - '_a04f4854-6e50-408f-8ec5-18f4541c32e9/_a04f4854-6e50-408f-8ec5-18f4541c32e9-123.bpmn', + '_a04f4854-6e50-408f-8ec5-18f4541c32e9/_a04f4854-6e50-408f-8ec5-18f4541c32e9-abc.bpmn', ); expect(data.write.mock.calls[1][1]).toEqual(OneProcessDefinition); }); it('will save the information of the new version alongside the ones for existing versions', async () => { data.read.mockResolvedValueOnce( JSON.stringify({ - 456: 'otherVersionInformation', + def: 'otherVersionInformation', }), ); @@ -162,16 +162,16 @@ describe('Tests for the functions in the database module', () => { 'processes.json/_a04f4854-6e50-408f-8ec5-18f4541c32e9', ); expect(JSON.parse(data.write.mock.calls[0][1])).toEqual({ - 123: { + abc: { deploymentDate: expect.any(Number), processId: '_958fd9c3-b99d-4e8e-95a1-a0a618eaa9d3', needs: { html: [], imports: [], images: [] }, validated: false, }, - 456: 'otherVersionInformation', + def: 'otherVersionInformation', }); expect(data.write.mock.calls[1][0]).toEqual( - '_a04f4854-6e50-408f-8ec5-18f4541c32e9/_a04f4854-6e50-408f-8ec5-18f4541c32e9-123.bpmn', + '_a04f4854-6e50-408f-8ec5-18f4541c32e9/_a04f4854-6e50-408f-8ec5-18f4541c32e9-abc.bpmn', ); expect(data.write.mock.calls[1][1]).toEqual(OneProcessDefinition); }); @@ -183,7 +183,7 @@ describe('Tests for the functions in the database module', () => { 'processes.json/_a04f4854-6e50-408f-8ec5-18f4541c32e9', ); expect(JSON.parse(data.write.mock.calls[0][1])).toEqual({ - 123: { + abc: { deploymentDate: expect.any(Number), processId: '_958fd9c3-b99d-4e8e-95a1-a0a618eaa9d3', needs: { html: ['User_Task_1'], imports: [], images: [] }, @@ -191,7 +191,7 @@ describe('Tests for the functions in the database module', () => { }, }); expect(data.write.mock.calls[1][0]).toEqual( - '_a04f4854-6e50-408f-8ec5-18f4541c32e9/_a04f4854-6e50-408f-8ec5-18f4541c32e9-123.bpmn', + '_a04f4854-6e50-408f-8ec5-18f4541c32e9/_a04f4854-6e50-408f-8ec5-18f4541c32e9-abc.bpmn', ); expect(data.write.mock.calls[1][1]).toEqual(OneUserTaskDefinition); }); @@ -203,7 +203,7 @@ describe('Tests for the functions in the database module', () => { 'processes.json/_a04f4854-6e50-408f-8ec5-18f4541c32e9', ); expect(JSON.parse(data.write.mock.calls[0][1])).toEqual({ - 789: { + ghi: { deploymentDate: expect.any(Number), processId: '_958fd9c3-b99d-4e8e-95a1-a0a618eaa9d3', needs: { @@ -212,7 +212,7 @@ describe('Tests for the functions in the database module', () => { { definitionId: '_a04f4854-6e50-408f-8ec5-18f4541c32e9', processId: '_958fd9c3-b99d-4e8e-95a1-a0a618eaa9d3', - version: 123, + versionId: 'abc', }, ], images: [], @@ -221,7 +221,7 @@ describe('Tests for the functions in the database module', () => { }, }); expect(data.write.mock.calls[1][0]).toEqual( - '_a04f4854-6e50-408f-8ec5-18f4541c32e9/_a04f4854-6e50-408f-8ec5-18f4541c32e9-789.bpmn', + '_a04f4854-6e50-408f-8ec5-18f4541c32e9/_a04f4854-6e50-408f-8ec5-18f4541c32e9-ghi.bpmn', ); expect(data.write.mock.calls[1][1]).toEqual(OneImportDefinition); }); @@ -259,7 +259,7 @@ describe('Tests for the functions in the database module', () => { it('saves the html of an user task into the file the process containing it is stored in', async () => { data.read.mockResolvedValueOnce( JSON.stringify({ - 123: { + abc: { deploymentDate: expect.any(Number), processId: '_958fd9c3-b99d-4e8e-95a1-a0a618eaa9d3', needs: { html: [], imports: [], images: [] }, @@ -281,13 +281,13 @@ describe('Tests for the functions in the database module', () => { it('parses image dependencies from the html and adds them to process versions that use the user task', async () => { data.read.mockResolvedValueOnce( JSON.stringify({ - 123: { + abc: { deploymentDate: expect.any(Number), processId: '_958fd9c3-b99d-4e8e-95a1-a0a618eaa9d3', needs: { html: [], imports: [], images: [] }, validated: false, }, - 456: { + def: { deploymentDate: expect.any(Number), processId: '_958fd9c3-b99d-4e8e-95a1-a0a618eaa9d3', needs: { html: ['taskFileName'], imports: [], images: [] }, @@ -315,13 +315,13 @@ describe('Tests for the functions in the database module', () => { expect(data.write).toHaveBeenCalledWith( 'processes.json/processDefinitionId', JSON.stringify({ - 123: { + abc: { deploymentDate: expect.any(Number), processId: '_958fd9c3-b99d-4e8e-95a1-a0a618eaa9d3', needs: { html: [], imports: [], images: [] }, validated: false, }, - 456: { + def: { deploymentDate: expect.any(Number), processId: '_958fd9c3-b99d-4e8e-95a1-a0a618eaa9d3', needs: { @@ -358,7 +358,7 @@ describe('Tests for the functions in the database module', () => { return OneProcessDefinition; } else { return JSON.stringify({ - 123: { + abc: { deploymentDate: 1337, processId: '_958fd9c3-b99d-4e8e-95a1-a0a618eaa9d3', needs: { html: [], imports: [], images: [] }, @@ -380,7 +380,7 @@ describe('Tests for the functions in the database module', () => { definitionName: 'OneProcess', deploymentMethod: 'dynamic', needs: { html: [], imports: [], images: [] }, - version: 123, + versionId: 'abc', versionName: 'Version 1', versionDescription: 'This is the first version', basedOnVersion: undefined, @@ -439,7 +439,7 @@ describe('Tests for the functions in the database module', () => { { definitionId: '_a04f4854-6e50-408f-8ec5-18f4541c32e9', processId: '_958fd9c3-b99d-4e8e-95a1-a0a618eaa9d3', - version: 123, + versionId: 'abc', }, ], images: [], @@ -493,7 +493,7 @@ describe('Tests for the functions in the database module', () => { describe('isProcessVersionValid', () => { it('returns true for a process without any user tasks and imports and sets validated flag in file', async () => { data.read.mockImplementation(async (path) => { - if (path === 'processDefinitionId/processDefinitionId-123.bpmn') { + if (path === 'processDefinitionId/processDefinitionId-abc.bpmn') { return 'Something'; } else if (path === 'processDefinitionId/user-tasks/') { return []; @@ -501,7 +501,7 @@ describe('Tests for the functions in the database module', () => { return []; } else { return JSON.stringify({ - 123: { + abc: { deploymentDate: 1337, validated: false, needs: { html: [], imports: [], images: [] }, @@ -511,13 +511,13 @@ describe('Tests for the functions in the database module', () => { } }); - const result = await db.isProcessVersionValid('processDefinitionId', 123); + const result = await db.isProcessVersionValid('processDefinitionId', 'abc'); expect(result).toBe(true); expect(data.write).toHaveBeenCalledWith( 'processes.json/processDefinitionId', JSON.stringify({ - 123: { + abc: { deploymentDate: 1337, validated: true, needs: { html: [], imports: [], images: [] }, @@ -528,11 +528,11 @@ describe('Tests for the functions in the database module', () => { }); it('returns true immediately when validated flag is set in the process file', async () => { data.read.mockImplementation(async (path) => { - if (path === 'processDefinitionId/processDefinitionId-123.bpmn') { + if (path === 'processDefinitionId/processDefinitionId-abc.bpmn') { return 'Something'; } else { return JSON.stringify({ - 123: { + abc: { deploymentDate: 1337, validated: true, needs: { html: [], imports: [], images: [] }, @@ -542,14 +542,14 @@ describe('Tests for the functions in the database module', () => { } }); - const result = await db.isProcessVersionValid('processDefinitionId', 123); + const result = await db.isProcessVersionValid('processDefinitionId', 'abc'); expect(result).toBe(true); expect(data.write).toBeCalledTimes(0); }); it('returns false for missing user task html', async () => { data.read.mockImplementation(async (path) => { - if (path === 'processDefinitionId/processDefinitionId-123.bpmn') { + if (path === 'processDefinitionId/processDefinitionId-abc.bpmn') { return 'someBpmn'; } else if (path === 'processDefinitionId/user-tasks/') { return []; @@ -557,7 +557,7 @@ describe('Tests for the functions in the database module', () => { return []; } else { return JSON.stringify({ - 123: { + abc: { deploymentDate: 1337, validated: false, needs: { html: ['html1'], imports: [], images: [] }, @@ -567,13 +567,13 @@ describe('Tests for the functions in the database module', () => { } }); - const result = await db.isProcessVersionValid('processDefinitionId', 123); + const result = await db.isProcessVersionValid('processDefinitionId', 'abc'); expect(result).toBe(false); }); it('returns true for process with user task and existing html', async () => { data.read.mockImplementation(async (path) => { - if (path === 'processDefinitionId/processDefinitionId-123.bpmn') { + if (path === 'processDefinitionId/processDefinitionId-abc.bpmn') { return 'someBpmn'; } else if (path === 'processDefinitionId/user-tasks/') { return ['html1']; @@ -583,7 +583,7 @@ describe('Tests for the functions in the database module', () => { return []; } else { return JSON.stringify({ - 123: { + abc: { deploymentDate: 1337, validated: false, needs: { html: ['html1'], imports: [], images: [] }, @@ -593,22 +593,22 @@ describe('Tests for the functions in the database module', () => { } }); - const result = await db.isProcessVersionValid('processDefinitionId', 123); + const result = await db.isProcessVersionValid('processDefinitionId', 'abc'); expect(result).toBe(true); }); it('returns false for missing definition of imported process', async () => { data.read.mockImplementation(async (path) => { - if (path === 'processDefinitionId/processDefinitionId-123.bpmn') { + if (path === 'processDefinitionId/processDefinitionId-abc.bpmn') { return 'someBpmn'; } else if (path === 'processes.json/processDefinitionId') { return JSON.stringify({ - 123: { + abc: { deploymentDate: 1337, validated: false, needs: { html: [], - imports: [{ definitionId: 'otherProcessDefinitionId', version: 456 }], + imports: [{ definitionId: 'otherProcessDefinitionId', versionId: 'def' }], images: [], }, processId: 'someId', @@ -619,25 +619,25 @@ describe('Tests for the functions in the database module', () => { } }); - const result = await db.isProcessVersionValid('processDefinitionId', 123); + const result = await db.isProcessVersionValid('processDefinitionId', 'abc'); expect(result).toBe(false); }); it('returns true for existing imported process with existing user task html', async () => { data.read.mockImplementation(async (path) => { - if (path === 'processDefinitionId/processDefinitionId-123.bpmn') { + if (path === 'processDefinitionId/processDefinitionId-abc.bpmn') { return 'someBpmn'; } else if (path === 'processDefinitionId/user-tasks/') { return []; } else if (path === 'processDefinitionId/images/') { return []; - } else if (path === 'otherProcessDefinitionId/otherProcessDefinitionId-456.bpmn') { + } else if (path === 'otherProcessDefinitionId/otherProcessDefinitionId-def.bpmn') { return 'someBpmn'; } else if (path === 'otherProcessDefinitionId/user-tasks/') { return ['html2']; } else if (path === 'processes.json/processDefinitionId') { return JSON.stringify({ - 123: { + abc: { deploymentDate: 1337, validated: false, needs: { @@ -645,7 +645,7 @@ describe('Tests for the functions in the database module', () => { imports: [ { definitionId: 'otherProcessDefinitionId', - version: 456, + versionId: 'def', processId: 'someOtherId', }, ], @@ -656,7 +656,7 @@ describe('Tests for the functions in the database module', () => { }); } else { return JSON.stringify({ - 456: { + def: { deploymentDate: 1337, validated: false, needs: { html: ['html2'], imports: [], images: [] }, @@ -666,31 +666,35 @@ describe('Tests for the functions in the database module', () => { } }); - const result = await db.isProcessVersionValid('processDefinitionId', 123); + const result = await db.isProcessVersionValid('processDefinitionId', 'abc'); expect(result).toBe(true); }); it("returns false if the process id referenced in the importing definitions doesn't match the process id in the referenced definitions", async () => { data.read.mockImplementation(async (path) => { - if (path === 'processDefinitionId/processDefinitionId-123.bpmn') { + if (path === 'processDefinitionId/processDefinitionId-abc.bpmn') { return 'someBpmn'; } else if (path === 'processDefinitionId/user-tasks/') { return []; } else if (path === 'processDefinitionId/images/') { return []; - } else if (path === 'otherProcessDefinitionId/otherProcessDefinitionId-456.bpmn') { + } else if (path === 'otherProcessDefinitionId/otherProcessDefinitionId-def.bpmn') { return 'someBpmn'; } else if (path === 'otherProcessDefinitionId/user-tasks/') { return ['html2.html']; } else if (path === 'processes.json/processDefinitionId') { return JSON.stringify({ - 123: { + abc: { deploymentDate: 1337, validated: false, needs: { html: [], imports: [ - { definitionId: 'otherProcessDefinitionId', version: 456, processId: 'someId' }, + { + definitionId: 'otherProcessDefinitionId', + versionId: 'def', + processId: 'someId', + }, ], images: [], }, @@ -699,7 +703,7 @@ describe('Tests for the functions in the database module', () => { }); } else { return JSON.stringify({ - 456: { + def: { deploymentDate: 1337, validated: false, needs: { html: ['html2'], imports: [], images: [] }, @@ -709,14 +713,14 @@ describe('Tests for the functions in the database module', () => { } }); - const result = await db.isProcessVersionValid('processDefinitionId', 123); + const result = await db.isProcessVersionValid('processDefinitionId', 'abc'); expect(result).toBe(false); }); it('returns false for missing image', async () => { data.read.mockImplementation(async (path) => { - if (path === 'processDefinitionId/processDefinitionId-123.bpmn') { + if (path === 'processDefinitionId/processDefinitionId-abc.bpmn') { return 'someBpmn'; } else if (path === 'processDefinitionId/user-tasks/') { return []; @@ -724,7 +728,7 @@ describe('Tests for the functions in the database module', () => { return []; } else { return JSON.stringify({ - 123: { + abc: { deploymentDate: 1337, validated: false, needs: { html: [], imports: [], images: ['someImage'] }, @@ -734,13 +738,13 @@ describe('Tests for the functions in the database module', () => { } }); - const result = await db.isProcessVersionValid('processDefinitionId', 123); + const result = await db.isProcessVersionValid('processDefinitionId', 'abc'); expect(result).toBe(false); }); it('returns true for process with existing image', async () => { data.read.mockImplementation(async (path) => { - if (path === 'processDefinitionId/processDefinitionId-123.bpmn') { + if (path === 'processDefinitionId/processDefinitionId-abc.bpmn') { return 'someBpmn'; } else if (path === 'processDefinitionId/user-tasks/') { return []; @@ -748,7 +752,7 @@ describe('Tests for the functions in the database module', () => { return ['someImage']; } else { return JSON.stringify({ - 123: { + abc: { deploymentDate: 1337, validated: false, needs: { html: [], imports: [], images: ['someImage'] }, @@ -758,7 +762,7 @@ describe('Tests for the functions in the database module', () => { } }); - const result = await db.isProcessVersionValid('processDefinitionId', 123); + const result = await db.isProcessVersionValid('processDefinitionId', 'abc'); expect(result).toBe(true); }); diff --git a/src/engine/universal/distribution/src/database/db.js b/src/engine/universal/distribution/src/database/db.js index 1c2a6a5c6..c54173da0 100644 --- a/src/engine/universal/distribution/src/database/db.js +++ b/src/engine/universal/distribution/src/database/db.js @@ -25,16 +25,16 @@ module.exports = { }, /** - * Checks if a specific version of a process exists + * Checks if a specific versionId of a process exists * * * @param {String} definitionId name of the file the definition of the process is stored in - * @param {Number} version the specific version of the process to check - * @returns {Boolean} - indicates if the version exists or not + * @param {Number} versionId the specific versionId of the process to check + * @returns {Boolean} - indicates if the versionId exists or not */ - async isProcessVersionExisting(definitionId, version) { + async isProcessVersionExisting(definitionId, versionId) { const processInfo = JSON.parse(await data.read(`processes.json/${definitionId}`)); - return !!(processInfo && processInfo[version]); + return !!(processInfo && processInfo[versionId]); }, /** @@ -42,29 +42,29 @@ module.exports = { * e.g. there are definitions for all imported processes and html for all user tasks * * @param {String} definitionId the id of the process definitions to check - * @param {Number} version the version to validate + * @param {Number} versionId the versionId to validate * @param {String} [expectedProcessId] the processId that is expected for this specific process (checked when used as an import) * @returns {Boolean} - indicates if the process is valid and can be executed */ - async isProcessVersionValid(definitionId, version, expectedProcessId) { + async isProcessVersionValid(definitionId, versionId, expectedProcessId) { const processInfo = JSON.parse(await data.read(`processes.json/${definitionId}`)); - if (!processInfo || !processInfo[version]) { + if (!processInfo || !processInfo[versionId]) { return false; } - const versionInfo = processInfo[version]; + const versionInfo = processInfo[versionId]; if (expectedProcessId && expectedProcessId !== versionInfo.processId) { return false; } - //check if the version was already validated, yes? => just return true + //check if the versionId was already validated, yes? => just return true if (versionInfo.validated) { return true; } - // get the requirements for the version + // get the requirements for the versionId const requirements = versionInfo.needs; // get all known user task files for the process @@ -88,7 +88,7 @@ module.exports = { // recursively check if all imported process versions exist and are valid themselves for (const { definitionId: importDefinitionId, - version: importVersion, + versionId: importVersion, processId: importProcessId, } of requirements.imports) { if (!(await this.isProcessVersionValid(importDefinitionId, importVersion, importProcessId))) @@ -97,17 +97,17 @@ module.exports = { // set flag in the process file that the validity check was done and succesful versionInfo.validated = true; - processInfo[version] = versionInfo; + processInfo[versionId] = versionInfo; await data.write(`processes.json/${definitionId}`, JSON.stringify(processInfo)); return true; }, /** - * Saves the definition of a process version under the definitionid and version id in the given bpmn + * Saves the definition of a process versionId under the definitionid and versionId id in the given bpmn * * @param {String} bpmn the process definition - * @throws Will throw if the bpmn contains either no definitionId or no version information + * @throws Will throw if the bpmn contains either no definitionId or no versionId information */ async saveProcessVersionDefinition(bpmn) { const bpmnObj = await toBpmnObject(bpmn); @@ -125,20 +125,20 @@ module.exports = { const versionInfo = await getDefinitionsVersionInformation(bpmnObj); - if (!versionInfo || !versionInfo.version) { - throw new Error('The bpmn does not contain valid version information!'); + if (!versionInfo || !versionInfo.versionId) { + throw new Error('The bpmn does not contain valid versionId information!'); } - const { version } = versionInfo; + const { versionId } = versionInfo; - // save version info into the processes list + // save versionId info into the processes list let processInfo = JSON.parse(await data.read(`processes.json/${bpmnDefinitionId}`)); // make sure to keep information about other existing versions if (!processInfo) { processInfo = {}; } - // save version specific information (needs gives information about the required process fragments) - processInfo[version] = { + // save versionId specific information (needs gives information about the required process fragments) + processInfo[versionId] = { deploymentDate: Date.now(), needs: await getRequiredProcessFragments(bpmnObj), validated: false, @@ -148,13 +148,13 @@ module.exports = { await data.write(`processes.json/${bpmnDefinitionId}`, JSON.stringify(processInfo)); // save the bpmn - await data.writeProcessVersionBpmn(bpmnDefinitionId, version, bpmn); + await data.writeProcessVersionBpmn(bpmnDefinitionId, versionId, bpmn); - await publishDeployedVersionInfo(bpmnDefinitionId, version, bpmn); + await publishDeployedVersionInfo(bpmnDefinitionId, versionId, bpmn); return { definitionId: bpmnDefinitionId, - version, + versionId, bpmn, }; }, @@ -171,27 +171,27 @@ module.exports = { }, /** - * Returns the bpmn of a specific process version + * Returns the bpmn of a specific process versionId * * @param {string} definitionId - * @param {number} version the version we want to get the bpmn of - * @returns {string} the bpmn of the specific process version + * @param {number} versionId the versionId we want to get the bpmn of + * @returns {string} the bpmn of the specific process versionId */ - async getProcessVersion(definitionId, version) { - if (!(await this.isProcessVersionExisting(definitionId, version))) { + async getProcessVersion(definitionId, versionId) { + if (!(await this.isProcessVersionExisting(definitionId, versionId))) { throw new Error( - `Process version (${version}) for the process with the given definitionId (${definitionId}) does not exist!`, + `Process versionId (${versionId}) for the process with the given definitionId (${definitionId}) does not exist!`, ); } - return await data.readProcessVersionBpmn(definitionId, version); + return await data.readProcessVersionBpmn(definitionId, versionId); }, /** - * Gets the BPMNs for all version of a process + * Gets the BPMNs for all versionId of a process * * @param {String} definitionId - * @returns {Array<{ version: string, bpmn: string }>} - the process definitions of every version of the process + * @returns {Array<{ versionId: string, bpmn: string }>} - the process definitions of every versionId of the process */ async getProcess(definitionId) { const processInfo = await data.read(`processes.json/${definitionId}`); @@ -204,54 +204,54 @@ module.exports = { const versionBpmn = []; - for (const version of versions) { + for (const versionId of versions) { versionBpmn.push({ - version, - bpmn: await data.readProcessVersionBpmn(definitionId, version), + versionId, + bpmn: await data.readProcessVersionBpmn(definitionId, versionId), }); } }, /** * Information about an imported process - * @typedef {{ definitionId: string, processId: string, version: number }} ImportInformation + * @typedef {{ definitionId: string, processId: string, versionId: number }} ImportInformation */ /** - * The dependencies of a process version + * The dependencies of a process versionId * @typedef {{ html: string[], images: string[], imports: ImportInformation[]}} VersionDependencies */ /** - * Information about a specific version of a process - * @typedef {{ bpmn: string, deploymentDate: number, definitionName: string, deploymentMethod: string, needs: VersionDependencies, version: number, versionName: string, versionDescription: string }} VersionInfo + * Information about a specific versionId of a process + * @typedef {{ bpmn: string, deploymentDate: number, definitionName: string, deploymentMethod: string, needs: VersionDependencies, versionId: number, versionName: string, versionDescription: string }} VersionInfo */ /** - * Gets the definition and additional information for a specific version of a process + * Gets the definition and additional information for a specific versionId of a process * * @param {String} processDefinitionId - * @param {Number} version - * @returns {VersionInfo} the information about the version + * @param {Number} versionId + * @returns {VersionInfo} the information about the versionId */ - async getProcessVersionInfo(processDefinitionId, version) { + async getProcessVersionInfo(processDefinitionId, versionId) { const processInfo = JSON.parse(await data.read(`processes.json/${processDefinitionId}`)); - if (!processInfo || !processInfo[version]) { + if (!processInfo || !processInfo[versionId]) { throw new Error( - `Process version ${version} does not exist for the process (id: ${processDefinitionId}).`, + `Process versionId ${versionId} does not exist for the process (id: ${processDefinitionId}).`, ); } - const versionInfo = processInfo[version]; + const versionInfo = processInfo[versionId]; const deploymentDate = versionInfo.deploymentDate; - const bpmn = await data.readProcessVersionBpmn(processDefinitionId, version); + const bpmn = await data.readProcessVersionBpmn(processDefinitionId, versionId); if (!bpmn) { throw new Error( - `There exists no BPMN for the process (id: ${processDefinitionId}) with version ${version}.`, + `There exists no BPMN for the process (id: ${processDefinitionId}) with versionId ${versionId}.`, ); } @@ -265,7 +265,7 @@ module.exports = { definitionName, deploymentMethod, needs: versionInfo.needs, - version: bpmnVersionInfo.version, + versionId: bpmnVersionInfo.versionId, versionName: bpmnVersionInfo.name, versionDescription: bpmnVersionInfo.description, basedOnVersion: bpmnVersionInfo.versionBasedOn, @@ -291,7 +291,7 @@ module.exports = { } const infoPromises = Object.keys(processInfo).map( - async (version) => await this.getProcessVersionInfo(processDefinitionId, version), + async (versionId) => await this.getProcessVersionInfo(processDefinitionId, versionId), ); const versions = await Promise.all(infoPromises); @@ -376,14 +376,14 @@ module.exports = { const imageDependencies = getHTMLImagesToKnow(html); if (imageDependencies.length) { - // add the dependency to every process version that depends on the user task - Object.values(processInfo).forEach((version) => { - if (version.needs.html.includes(fileName)) { - // if the version has a dependency on the user task - // add all the image dependencies that are not already referenced in the needs array of the version + // add the dependency to every process versionId that depends on the user task + Object.values(processInfo).forEach((versionId) => { + if (versionId.needs.html.includes(fileName)) { + // if the versionId has a dependency on the user task + // add all the image dependencies that are not already referenced in the needs array of the versionId imageDependencies.forEach((imageFileName) => { - if (!version.needs.images.includes(imageFileName)) { - version.needs.images.push(imageFileName); + if (!versionId.needs.images.includes(imageFileName)) { + versionId.needs.images.push(imageFileName); } }); } diff --git a/src/engine/universal/distribution/src/routes/ProcessStorageRoutes.js b/src/engine/universal/distribution/src/routes/ProcessStorageRoutes.js index 7864e1131..3801f642f 100644 --- a/src/engine/universal/distribution/src/routes/ProcessStorageRoutes.js +++ b/src/engine/universal/distribution/src/routes/ProcessStorageRoutes.js @@ -31,8 +31,8 @@ module.exports = (path, management) => { network.post(`${path}/`, { cors: true }, async (req) => { const { body } = req; const { bpmn } = body; - const { definitionId, version } = await db.saveProcessVersionDefinition(bpmn); - log.info(`Process version deployed (id: ${definitionId}, version: ${version})`); + const { definitionId, versionId } = await db.saveProcessVersionDefinition(bpmn); + log.info(`Process version deployed (id: ${definitionId}, version: ${versionId})`); return JSON.stringify(bpmn); }); @@ -52,7 +52,7 @@ module.exports = (path, management) => { try { const process = await db.getProcessInfo(definitionId); - return JSON.stringify(process.versions.map(({ version }) => version)); + return JSON.stringify(process.versions.map(({ versionId }) => versionId)); } catch ({ message }) { throw new APIError(404, message); } diff --git a/src/engine/universal/machine/logging/logging.js b/src/engine/universal/machine/logging/logging.js index d5ae98eb9..a38e4f0ff 100644 --- a/src/engine/universal/machine/logging/logging.js +++ b/src/engine/universal/machine/logging/logging.js @@ -6,6 +6,8 @@ const rotationUtils = require('./src/utils/logRotationUtils'); const startRotation = require('./src/rotation/rotation'); const routes = require('./src/routes/logRoutes'); +/** @typedef {{moduleName:string; definitionId: string; consoleOnly: boolean;}} LoggerConfObject */ + let singletonInstance; /** @@ -22,6 +24,7 @@ class Logging { this.doneInitializing = undefined; // See @proceed/system.console console.constructor._setLoggingModule(this); + this.logCallbacks = new Set(); } /** @@ -65,13 +68,29 @@ class Logging { routes(this); } + /** @param {(obj: LoggerConfObject, log:any)=>void} callback */ + registerCallback(callback) { + return this.logCallbacks.add(callback); + } + + /** @param {(obj: LoggerConfObject, log:string)=>void} callback */ + unregisterCallback(callback) { + return this.logCallbacks.delete(callback); + } + /** * Factory method creating a logger - * @param {object} confObject An object containing all configuration parameters for the logger + * @param {LoggerConfObject } confObject An object containing all configuration parameters for the logger * @returns a logger */ getLogger(confObject) { - const logger = loggerLoader(confObject, this.init.bind(this)); + const logger = loggerLoader(confObject, this.init.bind(this), [ + (msg) => { + for (const callback of this.logCallbacks) { + callback(confObject, msg); + } + }, + ]); return logger; } diff --git a/src/engine/universal/machine/logging/src/loggerHelpers/logger.js b/src/engine/universal/machine/logging/src/loggerHelpers/logger.js index cc2a5bb89..414416401 100644 --- a/src/engine/universal/machine/logging/src/loggerHelpers/logger.js +++ b/src/engine/universal/machine/logging/src/loggerHelpers/logger.js @@ -15,16 +15,17 @@ const writerLoader = require('./writers.js'); * * Class for logger instances * Instantiates a new logger - * @param {object} confObject The configuration for the logger + * @param {{moduleName:string; definitionId: string; consoleOnly: boolean;}} confObject The configuration for the logger * @param {promise} loggingInitializedPromise a promise indicating that the logger has + * @param {((...args: any[])=>void)[]} [customWriters] Custom writer functions to be used by the logger * finished being asynchronously initialized */ class Logger { - constructor(confObject, loggingInitializer) { + constructor(confObject, loggingInitializer, customWriters) { this.instanceInitialized = false; this.confObject = confObject; this.loggingInitializer = loggingInitializer; - this.functionsForWriter = []; + this.functionsForWriter = customWriters ? [...customWriters] : []; this.moduleName = confObject.moduleName; } @@ -184,7 +185,9 @@ Logger.initialization = new Promise((resolve) => { /** * @param {object} confObject The configuration for the logger * @param {promise} loggingInitializedPromise a promise indicating that the logger has + * @param {((...args: any[])=>void)[]} [customWriters] Custom writer functions to be used by the logger * finished being asynchronously initialized * @returns a configured instance of the Logger class */ -module.exports = (confObject, loggingInitializer) => new Logger(confObject, loggingInitializer); +module.exports = (confObject, loggingInitializer, customWriters) => + new Logger(confObject, loggingInitializer, customWriters); diff --git a/src/helper-modules/bpmn-helper/customSchema.json b/src/helper-modules/bpmn-helper/customSchema.json index d5b8da52b..7f47f7509 100644 --- a/src/helper-modules/bpmn-helper/customSchema.json +++ b/src/helper-modules/bpmn-helper/customSchema.json @@ -250,13 +250,13 @@ ] }, { - "name": "version", + "name": "versionId", "extends": ["bpmn:Definitions", "bpmn:Import"], "properties": [ { - "name": "version", + "name": "versionId", "isAttr": true, - "type": "Number" + "type": "String" } ] }, @@ -293,6 +293,17 @@ } ] }, + { + "name": "versionCreatedOn", + "extends": ["bpmn:Definitions"], + "properties": [ + { + "name": "versionCreatedOn", + "isAttr": true, + "type": "Date" + } + ] + }, { "name": "creatorEnvironmentId", "extends": ["bpmn:Definitions"], diff --git a/src/helper-modules/bpmn-helper/src/getters.d.ts b/src/helper-modules/bpmn-helper/src/getters.d.ts index bc86277a8..6ec210855 100644 --- a/src/helper-modules/bpmn-helper/src/getters.d.ts +++ b/src/helper-modules/bpmn-helper/src/getters.d.ts @@ -255,14 +255,15 @@ export function getImports(bpmn: string | object): Promise; * Returns the version information of the given bpmn process definition * * @param {string|object} bpmn - the process definition as XML string or BPMN-moddle Object - * @returns {(Promise.<{version?: number, name?: string, description?: string, versionBasedOn?: number}>)} - The version information if it exists + * @returns {(Promise.<{version?: string, name?: string, description?: string, versionBasedOn?: string, versionCreatedOn?: string}>)} - The version information if it exists * @throws {Error} will throw if the definition contains a version that is not a number */ export function getDefinitionsVersionInformation(bpmn: string | object): Promise<{ - version?: number; + versionId?: string; name?: string; description?: string; - versionBasedOn?: number; + versionBasedOn?: string; + versionCreatedOn: string; }>; /** * Get all process ids from a BPMN definitions/object. @@ -373,7 +374,7 @@ export function getSubprocessContent(bpmn: string, subprocessId: string): Promis * * @param {object} bpmnObj - The BPMN XML as converted bpmn-moddle object with toBpmnObject * @param {string} callActivityId - The id of the callActivity - * @returns { { definitionId: string, processId: string, version: number } } An Object with the definition, process id and version + * @returns { { definitionId: string, processId: string, versionId: string } } An Object with the definition, process id and version * @throws An Error if the callActivity id does not exist * @throws If the callActivity has no 'calledElement' attribute * @throws If the targetNamespace for a callActivity could not be found @@ -385,14 +386,14 @@ export function getTargetDefinitionsAndProcessIdForCallActivityByObject( ): { definitionId: string; processId: string; - version: number; + versionId: string; }; /** * Get all definitionIds for all imported Processes used in callActivities * * @param {(string|object)} bpmn - the process definition as XML string or BPMN-Moddle Object * @param {boolean} [dontThrow] - whether to throw errors or not in retrieving process ids in call activities - * @returns { Promise.<{ [callActivityId: string]: { definitionId: string, processId: string, version: number }}> } an object (a map) with all callActivityIds as keys + * @returns { Promise.<{ [callActivityId: string]: { definitionId: string, processId: string, versionId: string }}> } an object (a map) with all callActivityIds as keys * @throws see function: {@link getTargetDefinitionsAndProcessIdForCallActivityByObject} */ export function getDefinitionsAndProcessIdForEveryCallActivity( @@ -402,7 +403,7 @@ export function getDefinitionsAndProcessIdForEveryCallActivity( [callActivityId: string]: { definitionId: string; processId: string; - version: number; + versionId: string; }; }>; /** diff --git a/src/helper-modules/bpmn-helper/src/getters.js b/src/helper-modules/bpmn-helper/src/getters.js index 9d24d4214..e190244b1 100644 --- a/src/helper-modules/bpmn-helper/src/getters.js +++ b/src/helper-modules/bpmn-helper/src/getters.js @@ -64,27 +64,28 @@ async function getDefinitionsName(bpmn) { * Returns the version information of the given bpmn process definition * * @param {string|object} bpmn - the process definition as XML string or BPMN-moddle Object - * @returns {(Promise.<{version?: number, name?: string, description?: string, versionBasedOn?: number}>)} - The version information if it exists + * @returns {(Promise.<{versionId?: string, name?: string, description?: string, versionBasedOn?: string, versionCreatedOn?: string }>)} - The version information if it exists * @throws {Error} will throw if the definition contains a version that is not a number */ async function getDefinitionsVersionInformation(bpmn) { const bpmnObj = typeof bpmn === 'string' ? await toBpmnObject(bpmn) : bpmn; - if (bpmnObj.version && isNaN(bpmnObj.version)) { - throw new Error('The process version has to be a number (time in ms since 1970)'); - } + // if (bpmnObj.versionId && isNaN(bpmnObj.versionId)) { + // throw new Error('The process version has to be a number (time in ms since 1970)'); + // } - if (!bpmnObj.version) { + if (!bpmnObj.versionId) { return { versionBasedOn: bpmnObj.versionBasedOn, }; } return { - version: parseInt(bpmnObj.version), + versionId: bpmnObj.versionId, name: bpmnObj.versionName, description: bpmnObj.versionDescription, versionBasedOn: bpmnObj.versionBasedOn, + versionCreatedOn: bpmnObj.versionCreatedOn, }; } @@ -443,7 +444,7 @@ function getTargetDefinitionsAndProcessIdForCallActivityByObject(bpmnObj, callAc ); } - const version = importElement.version || importElement.$attrs['proceed:version']; + const version = importElement.versionId || importElement.$attrs['proceed:versionId']; if (!version) { throw new Error( @@ -454,7 +455,7 @@ function getTargetDefinitionsAndProcessIdForCallActivityByObject(bpmnObj, callAc return { definitionId: importElement.location, processId, - version: version && parseInt(version), + versionId: version, }; } @@ -463,7 +464,7 @@ function getTargetDefinitionsAndProcessIdForCallActivityByObject(bpmnObj, callAc * * @param {(string|object)} bpmn - the process definition as XML string or BPMN-Moddle Object * @param {boolean} [dontThrow] - whether to throw errors or not in retrieving process ids in call activities - * @returns { Promise.<{ [callActivityId: string]: { definitionId: string, processId: string, version: number }}> } an object (a map) with all callActivityIds as keys + * @returns { Promise.<{ [callActivityId: string]: { definitionId: string, processId: string, versionId: string }}> } an object (a map) with all callActivityIds as keys * @throws see function: {@link getTargetDefinitionsAndProcessIdForCallActivityByObject} */ async function getDefinitionsAndProcessIdForEveryCallActivity(bpmn, dontThrow = false) { diff --git a/src/helper-modules/bpmn-helper/src/setters.d.ts b/src/helper-modules/bpmn-helper/src/setters.d.ts index 4921b2429..7e97f436c 100644 --- a/src/helper-modules/bpmn-helper/src/setters.d.ts +++ b/src/helper-modules/bpmn-helper/src/setters.d.ts @@ -22,24 +22,27 @@ export function setDefinitionsName(bpmn: string | object, name: string): Promise * * @param {(string|object)} bpmn - the process definition as XML string or BPMN-Moddle Object * @param {object} versionInformation - the version information to set in the definitions object - * @param {(string|number)} [versionInformation.version] - the version number (a time since epoch string or number) + * @param {(string)} [versionInformation.versionId] - the versionId (a uuid assigned to a version) * @param {string} [versionInformation.versionName] - a human readable name for the version * @param {string} [versionInformation.versionDescription] - a longer description of the version - * @param {(string|number)} [versionInformation.versionBasedOn] - a reference to the version this one is based on + * @param {(string)} [versionInformation.versionBasedOn] - a reference to the version this one is based on + * @param {(string)} [versionInformation.versionCreatedOn] - a timestamp (UTC) when the version was created * @returns {Promise} the modified BPMN process as bpmn-moddle object or XML string based on input */ export function setDefinitionsVersionInformation( bpmn: string | object, { - version, + versionId, versionName, versionDescription, versionBasedOn, + versionCreatedOn, }: { - version?: string | number; + versionId?: string; versionName?: string; versionDescription?: string; - versionBasedOn?: string | number; + versionBasedOn?: string; + versionCreatedOn?: string; }, ): Promise; /** diff --git a/src/helper-modules/bpmn-helper/src/setters.js b/src/helper-modules/bpmn-helper/src/setters.js index 15eaa8986..bbba0f1b8 100644 --- a/src/helper-modules/bpmn-helper/src/setters.js +++ b/src/helper-modules/bpmn-helper/src/setters.js @@ -59,28 +59,27 @@ async function setDefinitionsName(bpmn, name) { * * @param {(string|object)} bpmn - the process definition as XML string or BPMN-Moddle Object * @param {object} versionInformation - the version information to set in the definitions object - * @param {(string|number)} [versionInformation.version] - the version number (a time since epoch string or number) + * @param {(string)} [versionInformation.versionId] - the versionId (a uuid assigned to a version) * @param {string} [versionInformation.versionName] - a human readable name for the version * @param {string} [versionInformation.versionDescription] - a longer description of the version - * @param {(string|number)} [versionInformation.versionBasedOn] - a reference to the version this one is based on + * @param {(string)} [versionInformation.versionBasedOn] - a reference to the version this one is based on + * @param {(string)} [versionInformation.versionCreatedOn] - a timestamp (UTC) when the version was created * @returns {Promise} the modified BPMN process as bpmn-moddle object or XML string based on input */ async function setDefinitionsVersionInformation( bpmn, - { version, versionName, versionDescription, versionBasedOn }, + { versionId, versionName, versionDescription, versionBasedOn, versionCreatedOn }, ) { - if (version && isNaN(version)) { - throw new Error('The process version has to be a number (time in ms since 1970)'); - } return await manipulateElementsByTagName(bpmn, 'bpmn:Definitions', (definitions) => { - definitions.version = version; + definitions.versionId = versionId; definitions.versionName = versionName; definitions.versionDescription = versionDescription; definitions.versionBasedOn = versionBasedOn; + definitions.versionCreatedOn = versionCreatedOn; // make sure that the targetnamespace is unique for the new version definitions.targetNamespace = generateTargetNamespace( - `${definitions.id}${version ? `#${version}` : ''}`, + `${definitions.id}${versionCreatedOn ? `#${versionCreatedOn}` : ''}`, ); }); } diff --git a/src/helper-modules/process-performance-calculator/__tests__/data/allowed_elements.bpmn b/src/helper-modules/process-performance-calculator/__tests__/data/allowed_elements.bpmn index 847cb5660..eacde0f28 100644 --- a/src/helper-modules/process-performance-calculator/__tests__/data/allowed_elements.bpmn +++ b/src/helper-modules/process-performance-calculator/__tests__/data/allowed_elements.bpmn @@ -1,6 +1,6 @@ - + diff --git a/src/helper-modules/process-performance-calculator/__tests__/data/wrong_call.bpmn b/src/helper-modules/process-performance-calculator/__tests__/data/wrong_call.bpmn index 108b6d3d7..38c72b9ac 100644 --- a/src/helper-modules/process-performance-calculator/__tests__/data/wrong_call.bpmn +++ b/src/helper-modules/process-performance-calculator/__tests__/data/wrong_call.bpmn @@ -1,6 +1,6 @@ - + diff --git a/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/element-status.tsx b/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/element-status.tsx index 65ad7febb..ff4bb940a 100644 --- a/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/element-status.tsx +++ b/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/element-status.tsx @@ -1,13 +1,12 @@ import { ReactNode } from 'react'; import { Alert, Checkbox, Image, Progress, ProgressProps, Space, Typography } from 'antd'; import { ClockCircleFilled } from '@ant-design/icons'; -import React from 'react'; -import { statusToType } from './instance-helpers'; -import { convertISODurationToMiliseconds, getMetaDataFromElement } from '@proceed/bpmn-helper'; -import { generateRequestUrl } from '@/lib/engines/endpoints'; +import { getPlanDelays, getTimeInfo, statusToType } from './instance-helpers'; +import { getMetaDataFromElement } from '@proceed/bpmn-helper'; import { DisplayTable, RelevantInstanceInfo } from './instance-info-panel'; +import { endpointBuilder } from '@/lib/engines/endpoint'; -function transformMilisecondsToTimeFormat(milliseconds: number | undefined) { +function transformMillisecondsToTimeFormat(milliseconds: number | undefined) { if (!milliseconds || milliseconds < 0 || milliseconds < 1000) return; const days = Math.floor(milliseconds / (3600000 * 24)); @@ -21,7 +20,6 @@ function transformMilisecondsToTimeFormat(milliseconds: number | undefined) { const seconds = Math.floor(milliseconds / 1000); milliseconds -= seconds * 1000; - // Will display time in 10:30:23 format return `${days} Days, ${hours}h, ${minutes}min, ${seconds}s`; } @@ -46,11 +44,13 @@ export function ElementStatus({ info }: { info: RelevantInstanceInfo }) { marginTop: '1rem', }} > + {/** TODO: correct image url */} , ]); @@ -158,64 +158,14 @@ export function ElementStatus({ info }: { info: RelevantInstanceInfo }) { statusEntries.push(['Documentation:', info.element.businessObject?.documentation?.[0]?.text]); // Activity time calculation - let start: Date | undefined = undefined; - if (info.instance) { - if (isRootElement) start = new Date(info.instance.globalStartTime); - else if (logInfo) start = new Date(logInfo.startTime); - else if (token) start = new Date(token.currentFlowElementStartTime); - } - - let end; - if (info.instance) { - if (isRootElement) { - const ended = info.instance.instanceState.every( - (state) => - state !== 'RUNNING' && - state !== 'READY' && - state !== 'DEPLOYMENT-WAITING' && - state !== 'PAUSING' && - state !== 'PAUSED', - ); - - if (ended) { - const lastLog = info.instance.log[info.instance.log.length - 1]; - if (lastLog) end = new Date(lastLog.endTime); - } - } else if (logInfo) { - end = new Date(logInfo.endTime); - } - } - - let duration; - if (start && end) duration = end.getTime() - start.getTime(); - - const plan = { - end: metaData.timePlannedEnd ? new Date(metaData.timePlannedEnd) : undefined, - start: metaData.timePlannedOccurrence ? new Date(metaData.timePlannedOccurrence) : undefined, - duration: metaData.timePlannedDuration - ? convertISODurationToMiliseconds(metaData.timePlannedDuration) - : undefined, - }; - - // The order in which missing times are derived from the others is irrelevant - // If there is only one -> not possible to derive the others - // If there are two -> derive the missing one (order doesn't matter) - // If there are three -> nothing to do - - if (!plan.end && plan.start && plan.duration) - plan.end = new Date(plan.start.getTime() + plan.duration); - - if (!plan.start && plan.end && plan.duration) - plan.start = new Date(plan.end.getTime() - plan.duration); - - if (!plan.duration && plan.start && plan.end) - plan.duration = plan.end.getTime() - plan.start.getTime(); + const { start, end, duration } = getTimeInfo({ + element: info.element, + instance: info.instance, + logInfo, + token, + }); - const delays = { - start: plan.start && start && start.getTime() - plan.start.getTime(), - end: plan.end && end && end.getTime() - plan.end.getTime(), - duration: plan.duration && duration && duration - plan.duration, - }; + const { delays, plan } = getPlanDelays({ elementMetaData: metaData, start, end, duration }); // Activity time statusEntries.push([ @@ -233,7 +183,7 @@ export function ElementStatus({ info }: { info: RelevantInstanceInfo }) { Delay: = 1000 ? 'danger' : undefined}> - {transformMilisecondsToTimeFormat(delays.start)} + {transformMillisecondsToTimeFormat(delays.start)} , ]); @@ -242,18 +192,18 @@ export function ElementStatus({ info }: { info: RelevantInstanceInfo }) { Duration: - {transformMilisecondsToTimeFormat(duration)} + {transformMillisecondsToTimeFormat(duration)} , Planned Duration: - {transformMilisecondsToTimeFormat(plan.duration)} + {transformMillisecondsToTimeFormat(plan.duration)} , Delay: = 1000 ? 'danger' : undefined}> - {delays.start ? transformMilisecondsToTimeFormat(delays.duration) : ''} + {transformMillisecondsToTimeFormat(delays.duration)} , ]); @@ -273,7 +223,7 @@ export function ElementStatus({ info }: { info: RelevantInstanceInfo }) { Delay: = 1000 ? 'danger' : undefined}> - {transformMilisecondsToTimeFormat(delays.end)} + {transformMillisecondsToTimeFormat(delays.end)} , ]); diff --git a/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/instance-coloring.ts b/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/instance-coloring.ts index c6d4c4b37..c3bfbe588 100644 --- a/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/instance-coloring.ts +++ b/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/instance-coloring.ts @@ -1,7 +1,7 @@ import { BPMNCanvasRef } from '@/components/bpmn-canvas'; import { InstanceInfo } from '@/lib/engines/deployment'; import { getMetaDataFromElement } from '@proceed/bpmn-helper/src/getters'; -import { getPlannedEnd } from './instance-helpers'; +import { getPlanDelays, getTimeInfo } from './instance-helpers'; export const colorOptions = [ { @@ -64,37 +64,29 @@ function getExecutionColor(executionState: string, wasInterrupted: boolean) { } export function progressToColor( - elementMetaData: any, - timeInfo: { startTime: number | null; endTime: number | null }, + timeInfo: ReturnType, + planInfo: ReturnType, ) { - let plannedStart = timeInfo.startTime; - if (elementMetaData.timePlannedOccurrence) { - plannedStart = new Date(elementMetaData.timePlannedOccurrence).getTime(); + if (planInfo.plan.duration && timeInfo.start) { + const criticalTime = Math.floor(0.7 * planInfo.plan.duration); + const currentDate = Date.now(); + + if (currentDate < timeInfo.start.getTime() + criticalTime) { + return 'green'; + } else if (currentDate < timeInfo.start.getTime() + planInfo.plan.duration) { + return 'orange'; + } else { + return 'red'; + } } - const plannedDuration = elementMetaData.timePlannedDuration; - - if (!plannedStart || !plannedDuration) return 'white'; - - const plannedEnd = getPlannedEnd(plannedStart, plannedDuration); - if (!plannedEnd) return 'white'; - - if (timeInfo.endTime) { - if (plannedEnd.getTime() > timeInfo.endTime) return 'green'; + if (timeInfo.end) { + if (!planInfo.plan.end) return 'white'; + if (planInfo.plan.end.getTime() >= timeInfo.end.getTime()) return 'green'; else return 'red'; } - const durationInMs = plannedEnd.getTime() - plannedStart; - const criticalTime = Math.floor(0.7 * durationInMs); - const currentDate = new Date().getTime(); - - if (currentDate < plannedStart + criticalTime) { - return 'green'; - } else if (currentDate < plannedEnd.getTime()) { - return 'orange'; - } else { - return 'red'; - } + return 'white'; } function flowElementsStyling( @@ -114,29 +106,19 @@ function flowElementsStyling( ) { return undefined; } - let timeInfo: { startTime: number | null; endTime: number | null } = { - startTime: null, - endTime: null, - }; let logIdx = instance.log.length - 1; while (logIdx >= 0 && instance.log[logIdx].flowElementId !== element.id) logIdx--; const logEntry = logIdx >= 0 ? instance.log[logIdx] : undefined; - const token = instance.tokens.find((token) => token.currentFlowElementId === element.id); - if (token) { - timeInfo.startTime = token.currentFlowElementStartTime; - } else if (logEntry) { - // if there is no more up to date token based time info use log info if some exists - timeInfo = logEntry; - } - let color; switch (colors) { case 'timeColors': - const metaData = getMetaDataFromElement(element); - color = progressToColor(metaData, timeInfo); + const metaData = getMetaDataFromElement(element.businessObject); + const timeInfo = getTimeInfo({ element, logInfo: logEntry, token, instance }); + const planInfo = getPlanDelays({ elementMetaData: metaData, ...timeInfo }); + color = progressToColor(timeInfo, planInfo); break; case 'noColors': color = 'white'; diff --git a/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/instance-helpers.ts b/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/instance-helpers.ts index 3da00215b..93202c9e7 100644 --- a/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/instance-helpers.ts +++ b/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/instance-helpers.ts @@ -1,3 +1,7 @@ +import { InstanceInfo } from '@/lib/engines/deployment'; +import { convertISODurationToMiliseconds } from '@proceed/bpmn-helper/src/getters'; +import type { ElementLike } from 'diagram-js/lib/core/Types'; + export type ElementStatus = | 'PAUSED' | 'DEPLOYMENT_WAITING' @@ -25,8 +29,6 @@ export function statusToType(status: string) { case 'ENDED': return 'success'; case 'ABORTED': - case 'ERROR-SEMANTIC': - case 'ERROR-TECHNICAL': case 'ERROR-INTERRUPTED': case 'ERROR-CONSTRAINT-UNFULFILLED': case 'STOPPED': @@ -36,20 +38,96 @@ export function statusToType(status: string) { } } -export function getPlannedEnd(plannedStart: number, plannedDuration: string) { - const anchor = new Date(plannedStart); +export function getTimeInfo({ + element, + logInfo, + token, + instance, +}: { + element: ElementLike; + /** Log entry for element in instance information */ + logInfo?: InstanceInfo['log'][number]; + /** Token where currentFlowElementId is the element */ + token?: InstanceInfo['tokens'][number]; + instance?: InstanceInfo; +}) { + if (!instance) return { start: undefined, end: undefined, duration: undefined }; + + const isRootElement = element && element.type === 'bpmn:Process'; + + let start: Date | undefined = undefined; + if (isRootElement) start = new Date(instance.globalStartTime); + else if (logInfo) start = new Date(logInfo.startTime); + else if (token) start = new Date(token.currentFlowElementStartTime); + + let end; + if (isRootElement) { + const ended = instance.instanceState.every( + (state) => + state !== 'RUNNING' && + state !== 'READY' && + state !== 'DEPLOYMENT-WAITING' && + state !== 'PAUSING' && + state !== 'PAUSED', + ); + + if (ended) { + const lastLog = instance.log[instance.log.length - 1]; + if (lastLog) end = new Date(lastLog.endTime); + } + } else if (logInfo) { + end = new Date(logInfo.endTime); + } + + let duration: number | undefined; + if (start && end) duration = end.getTime() - start.getTime(); + + return { start, end, duration }; +} + +export function getPlanDelays({ + elementMetaData, + start, + end, + duration, +}: { + elementMetaData: { + [key: string]: any; + }; + + start?: Date; + end?: Date; + duration?: number; +}) { + const plan = { + end: elementMetaData.timePlannedEnd ? new Date(elementMetaData.timePlannedEnd) : undefined, + start: elementMetaData.timePlannedOccurrence + ? new Date(elementMetaData.timePlannedOccurrence) + : undefined, + duration: elementMetaData.timePlannedDuration + ? convertISODurationToMiliseconds(elementMetaData.timePlannedDuration) + : undefined, + }; + + // The order in which missing times are derived from the others is irrelevant + // If there is only one -> not possible to derive the others + // If there are two -> derive the missing one (order doesn't matter) + // If there are three -> nothing to do + + if (!plan.end && plan.start && plan.duration) + plan.end = new Date(plan.start.getTime() + plan.duration); + + if (!plan.start && plan.end && plan.duration) + plan.start = new Date(plan.end.getTime() - plan.duration); - const re = - /^P((?\d+)Y)?((?\d+)M)?((?\d+)D)?(T((?\d+)H)?((?\d+)M)?((?\d+(.\d+)?)S)?)?$/; - const match = re.exec(plannedDuration); - if (!match || !match.groups) return null; + if (!plan.duration && plan.start && plan.end) + plan.duration = plan.end.getTime() - plan.start.getTime(); - anchor.setFullYear(anchor.getFullYear() + (+match.groups['y'] || 0)); - anchor.setMonth(anchor.getMonth() + (+match.groups['m'] || 0)); - anchor.setDate(anchor.getDate() + (+match.groups['d'] || 0)); - anchor.setHours(anchor.getHours() + (+match.groups['th'] || 0)); - anchor.setMinutes(anchor.getMinutes() + (+match.groups['tm'] || 0)); - anchor.setSeconds(anchor.getSeconds() + (+match.groups['ts'] || 0)); + const delays = { + start: plan.start && start && start.getTime() - plan.start.getTime(), + end: plan.end && end && end.getTime() - plan.end.getTime(), + duration: plan.duration && duration && duration - plan.duration, + }; - return anchor; + return { plan, delays }; } diff --git a/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/page.tsx b/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/page.tsx index 5a0211a2e..25e510bac 100644 --- a/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/page.tsx +++ b/src/management-system-v2/app/(dashboard)/[environmentId]/executions/[processId]/page.tsx @@ -1,7 +1,7 @@ // TODO: remove the use client if this page is used in server 'use client'; -import { Button, Result, Select, Spin, Tooltip, Space, Dropdown, Typography } from 'antd'; +import { Button, Result, Select, Spin, Tooltip, Space, Dropdown } from 'antd'; import useDeployments from '../deployments-hook'; import Content from '@/components/content'; import BPMNCanvas, { BPMNCanvasRef } from '@/components/bpmn-canvas'; @@ -13,7 +13,7 @@ import contentStyles from './content.module.scss'; import styles from '@/app/(dashboard)/[environmentId]/processes/[processId]/modeler-toolbar.module.scss'; import InstanceInfoPanel from './instance-info-panel'; import { useSearchParamState } from '@/lib/use-search-param-state'; -import { MdColorLens } from 'react-icons/md'; +import { MdColorLens, MdOutlineColorLens } from 'react-icons/md'; import { ColorOptions, applyColors, colorOptions, flushPreviousStyling } from './instance-coloring'; import { RemoveReadOnly } from '@/lib/typescript-utils'; import type { ElementLike } from 'diagram-js/lib/core/Types'; @@ -186,14 +186,17 @@ function ProcessDeploymentView({ items: [ { key: '-1', - label: selectedVersion ? ( - none - ) : ( - 'Select a version' - ), - disabled: !selectedVersion, + label: 'Select a version', + disabled: true, }, - + ...(selectedVersion + ? [ + { + label: '', + key: '-2', + }, + ] + : []), ...selectedProcess.versions.map((version) => ({ label: version.versionName || version.definitionName, key: `${version.version}`, @@ -225,7 +228,7 @@ function ProcessDeploymentView({ selectedKeys: [selectedColoring], }} > -