@5minds/node-red-contrib-processcube 0.11.0-feature-34fec2-lyelwzbp → 0.12.0-develop-2b2936-lyelsu47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.processcube/authority/config/config.json +36 -0
- package/.processcube/authority/config/upeSeedingData.json +12 -0
- package/Dockerfile +1 -4
- package/docker-compose.yml +12 -0
- package/externaltask-input.js +7 -2
- package/message-event-trigger.js +2 -1
- package/nodered/node-red-contrib-processcube-flows.json +177 -2436
- package/nodered/node-red-contrib-processcube-flows_cred.json +3 -0
- package/nodered/package.json +1 -4
- package/nodered/settings.js +2 -2
- package/package.json +5 -4
- package/process-start.js +1 -1
- package/processcube-engine-config.html +12 -0
- package/processcube-engine-config.js +115 -1
- package/processdefinition-query.js +6 -2
- package/processes/NodeRedExternalTask.bpmn +12 -26
- package/processinstance-query.js +2 -2
- package/signal-event-trigger.js +2 -1
- package/usertask-finished-listener.js +25 -8
- package/usertask-input.js +6 -2
- package/usertask-new-listener.js +26 -8
- package/usertask-output.js +1 -1
- package/wait-for-usertask.html +0 -76
- package/wait-for-usertask.js +0 -82
package/nodered/package.json
CHANGED
@@ -2,11 +2,8 @@
|
|
2
2
|
"name": "node-red-contrib-processcube-sample",
|
3
3
|
"version": "1.0.0",
|
4
4
|
"description": "A sample for the processcube node-red contrib package",
|
5
|
-
"scripts": {
|
6
|
-
"start": "./node_modules/.bin/node-red --settings=./settings.js node-red-contrib-processcube-flows.json"
|
7
|
-
},
|
8
5
|
"dependencies": {
|
9
|
-
"@5minds/node-red-contrib-processcube": "file
|
6
|
+
"@5minds/node-red-contrib-processcube": "file:/src/node-red-contrib-processcube/",
|
10
7
|
"@5minds/node-red-dashboard-2-processcube-dynamic-form": "^1.0.4",
|
11
8
|
"@5minds/node-red-dashboard-2-processcube-usertask-table": "^1.0.7",
|
12
9
|
"@flowfuse/node-red-dashboard": "^1.11.1",
|
package/nodered/settings.js
CHANGED
@@ -41,7 +41,7 @@ module.exports = {
|
|
41
41
|
* node-red from being able to decrypt your existing credentials and they will be
|
42
42
|
* lost.
|
43
43
|
*/
|
44
|
-
|
44
|
+
credentialSecret: "a-secret-key",
|
45
45
|
|
46
46
|
/** By default, the flow JSON will be formatted over multiple lines making
|
47
47
|
* it easier to compare changes when using version control.
|
@@ -53,7 +53,7 @@ module.exports = {
|
|
53
53
|
* the user's home directory. To use a different location, the following
|
54
54
|
* property can be used
|
55
55
|
*/
|
56
|
-
|
56
|
+
userDir: '/nodered/',
|
57
57
|
|
58
58
|
/** Node-RED scans the `nodes` directory in the userDir to find local node files.
|
59
59
|
* The following property can be used to specify an additional directory to scan.
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@5minds/node-red-contrib-processcube",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.12.0-develop-2b2936-lyelsu47",
|
4
4
|
"license": "MIT",
|
5
5
|
"description": "Node-RED nodes for ProcessCube",
|
6
6
|
"authors": [
|
@@ -44,12 +44,13 @@
|
|
44
44
|
"UserTaskNewListener": "usertask-new-listener.js",
|
45
45
|
"UserTaskFinishedListener": "usertask-finished-listener.js",
|
46
46
|
"UserTaskInput": "usertask-input.js",
|
47
|
-
"UserTaskOutput": "usertask-output.js"
|
48
|
-
"WaitForUsertask": "wait-for-usertask.js"
|
47
|
+
"UserTaskOutput": "usertask-output.js"
|
49
48
|
}
|
50
49
|
},
|
51
50
|
"dependencies": {
|
52
|
-
"@5minds/processcube_engine_client": "^5.0.0"
|
51
|
+
"@5minds/processcube_engine_client": "^5.0.0",
|
52
|
+
"jwt-decode": "^4.0.0",
|
53
|
+
"openid-client": "^5.5.0"
|
53
54
|
},
|
54
55
|
"keywords": [
|
55
56
|
"node-red",
|
package/process-start.js
CHANGED
@@ -27,7 +27,7 @@ module.exports = function(RED) {
|
|
27
27
|
initialToken: msg.payload
|
28
28
|
};
|
29
29
|
|
30
|
-
client.processDefinitions.startProcessInstance(startParameters).then((result) => {
|
30
|
+
client.processDefinitions.startProcessInstance(startParameters, node.engine.identity).then((result) => {
|
31
31
|
|
32
32
|
msg.payload = result;
|
33
33
|
|
@@ -6,6 +6,10 @@
|
|
6
6
|
},
|
7
7
|
label: function() {
|
8
8
|
return this.url;
|
9
|
+
},
|
10
|
+
credentials: {
|
11
|
+
clientId: { type: "text" },
|
12
|
+
clientSecret: { type: "password" }
|
9
13
|
}
|
10
14
|
});
|
11
15
|
</script>
|
@@ -15,4 +19,12 @@
|
|
15
19
|
<label for="node-config-input-url"><i class="fa fa-bookmark"></i> Url</label>
|
16
20
|
<input type="text" id="node-config-input-url">
|
17
21
|
</div>
|
22
|
+
<div class="form-row">
|
23
|
+
<label for="node-config-input-clientId"><i class="fa fa-bookmark"></i> Client id</label>
|
24
|
+
<input type="text" id="node-config-input-clientId">
|
25
|
+
</div>
|
26
|
+
<div class="form-row">
|
27
|
+
<label for="node-config-input-clientSecret"><i class="fa fa-bookmark"></i> Client secret</label>
|
28
|
+
<input type="password" id="node-config-input-clientSecret">
|
29
|
+
</div>
|
18
30
|
</script>
|
@@ -1,7 +1,121 @@
|
|
1
|
+
const engine_client = require('@5minds/processcube_engine_client');
|
2
|
+
const jwt = require('jwt-decode');
|
3
|
+
const oidc = require('openid-client');
|
4
|
+
|
5
|
+
const DELAY_FACTOR = 0.85;
|
6
|
+
|
1
7
|
module.exports = function(RED) {
|
2
8
|
function ProcessCubeEngineNode(n) {
|
3
9
|
RED.nodes.createNode(this, n);
|
10
|
+
const identityChangedCallbacks = [];
|
4
11
|
this.url = n.url;
|
12
|
+
this.identity = null;
|
13
|
+
this.registerOnIdentityChanged = function (callback) {
|
14
|
+
identityChangedCallbacks.push(callback);
|
15
|
+
}
|
16
|
+
this.setIdentity = (identity) => {
|
17
|
+
this.identity = identity;
|
18
|
+
|
19
|
+
for (const callback of identityChangedCallbacks) {
|
20
|
+
callback(identity);
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
if (this.credentials.clientId && this.credentials.clientSecret) {
|
25
|
+
const engineClient = new engine_client.EngineClient(this.url);
|
26
|
+
|
27
|
+
engineClient.applicationInfo.getAuthorityAddress().then(authorityUrl => {
|
28
|
+
startRefreshingIdentityCycle(this.credentials.clientId, this.credentials.clientSecret, authorityUrl, this);
|
29
|
+
});
|
30
|
+
}
|
5
31
|
}
|
6
|
-
RED.nodes.registerType("processcube-engine-config", ProcessCubeEngineNode
|
32
|
+
RED.nodes.registerType("processcube-engine-config", ProcessCubeEngineNode, {
|
33
|
+
credentials: {
|
34
|
+
clientId: { type: "text" },
|
35
|
+
clientSecret: { type: "password" }
|
36
|
+
}
|
37
|
+
});
|
38
|
+
}
|
39
|
+
|
40
|
+
async function getFreshTokenSet(clientId, clientSecret, authorityUrl) {
|
41
|
+
const issuer = await oidc.Issuer.discover(authorityUrl);
|
42
|
+
|
43
|
+
const client = new issuer.Client({
|
44
|
+
client_id: clientId,
|
45
|
+
client_secret: clientSecret,
|
46
|
+
});
|
47
|
+
|
48
|
+
const tokenSet = await client.grant({
|
49
|
+
grant_type: 'client_credentials',
|
50
|
+
scope: 'engine_etw engine_read engine_write',
|
51
|
+
});
|
52
|
+
|
53
|
+
return tokenSet;
|
54
|
+
}
|
55
|
+
|
56
|
+
function getIdentityForExternalTaskWorkers(tokenSet) {
|
57
|
+
|
58
|
+
const accessToken = tokenSet.access_token;
|
59
|
+
const decodedToken = jwt.jwtDecode(accessToken);
|
60
|
+
|
61
|
+
return {
|
62
|
+
token: tokenSet.access_token,
|
63
|
+
userId: decodedToken.sub,
|
64
|
+
};
|
65
|
+
}
|
66
|
+
|
67
|
+
async function getExpiresInForExternalTaskWorkers(tokenSet) {
|
68
|
+
let expiresIn = tokenSet.expires_in;
|
69
|
+
|
70
|
+
if (!expiresIn && tokenSet.expires_at) {
|
71
|
+
expiresIn = Math.floor(tokenSet.expires_at - Date.now() / 1000);
|
72
|
+
}
|
73
|
+
|
74
|
+
if (expiresIn === undefined) {
|
75
|
+
throw new Error('Could not determine the time until the access token for external task workers expires');
|
76
|
+
}
|
77
|
+
|
78
|
+
return expiresIn;
|
79
|
+
}
|
80
|
+
|
81
|
+
/**
|
82
|
+
* Start refreshing the identity in regular intervals.
|
83
|
+
* @param {TokenSet | null} tokenSet The token set to refresh the identity for
|
84
|
+
* @returns {Promise<void>} A promise that resolves when the timer for refreshing the identity is initialized
|
85
|
+
* */
|
86
|
+
async function startRefreshingIdentityCycle(clientId, clientSecret, authorityUrl, configNode) {
|
87
|
+
let retries = 5;
|
88
|
+
|
89
|
+
const refresh = async () => {
|
90
|
+
try {
|
91
|
+
const newTokenSet = await getFreshTokenSet(clientId, clientSecret, authorityUrl);
|
92
|
+
const expiresIn = await getExpiresInForExternalTaskWorkers(newTokenSet);
|
93
|
+
const delay = expiresIn * DELAY_FACTOR * 1000;
|
94
|
+
|
95
|
+
freshIdentity = getIdentityForExternalTaskWorkers(newTokenSet);
|
96
|
+
|
97
|
+
configNode.setIdentity(freshIdentity);
|
98
|
+
|
99
|
+
retries = 5;
|
100
|
+
setTimeout(refresh, delay);
|
101
|
+
} catch (error) {
|
102
|
+
if (retries === 0) {
|
103
|
+
console.error(
|
104
|
+
'Could not refresh identity for external task worker processes. Stopping all external task workers.',
|
105
|
+
{ error },
|
106
|
+
);
|
107
|
+
return;
|
108
|
+
}
|
109
|
+
console.error('Could not refresh identity for external task worker processes.', {
|
110
|
+
error,
|
111
|
+
retryCount: retries,
|
112
|
+
});
|
113
|
+
retries--;
|
114
|
+
|
115
|
+
const delay = 2 * 1000;
|
116
|
+
setTimeout(refresh, delay);
|
117
|
+
}
|
118
|
+
};
|
119
|
+
|
120
|
+
await refresh();
|
7
121
|
}
|
@@ -34,8 +34,12 @@ module.exports = function(RED) {
|
|
34
34
|
});
|
35
35
|
|
36
36
|
node.on('input', function(msg) {
|
37
|
-
|
38
|
-
|
37
|
+
let query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg)
|
38
|
+
query = {
|
39
|
+
...query,
|
40
|
+
identity: node.server.identity
|
41
|
+
};
|
42
|
+
|
39
43
|
client.processDefinitions.getAll(query).then((matchingProcessDefinitions) => {
|
40
44
|
|
41
45
|
|
@@ -8,9 +8,8 @@
|
|
8
8
|
<bpmn:lane id="Lane_1xzf0d3">
|
9
9
|
<bpmn:flowNodeRef>StartEvent_1</bpmn:flowNodeRef>
|
10
10
|
<bpmn:flowNodeRef>Activity_1h843f0</bpmn:flowNodeRef>
|
11
|
-
<bpmn:flowNodeRef>Event_0z1wtnd</bpmn:flowNodeRef>
|
12
|
-
<bpmn:flowNodeRef>Activity_1y52hvq</bpmn:flowNodeRef>
|
13
11
|
<bpmn:flowNodeRef>Activity_1duxvq1</bpmn:flowNodeRef>
|
12
|
+
<bpmn:flowNodeRef>Event_0z1wtnd</bpmn:flowNodeRef>
|
14
13
|
</bpmn:lane>
|
15
14
|
</bpmn:laneSet>
|
16
15
|
<bpmn:startEvent id="StartEvent_1" name="Start">
|
@@ -27,27 +26,22 @@
|
|
27
26
|
<bpmn:outgoing>Flow_110cohh</bpmn:outgoing>
|
28
27
|
</bpmn:serviceTask>
|
29
28
|
<bpmn:sequenceFlow id="Flow_110cohh" sourceRef="Activity_1h843f0" targetRef="Activity_1duxvq1" />
|
30
|
-
<bpmn:
|
31
|
-
<bpmn:endEvent id="Event_0z1wtnd">
|
32
|
-
<bpmn:incoming>Flow_1oiihw7</bpmn:incoming>
|
33
|
-
</bpmn:endEvent>
|
34
|
-
<bpmn:task id="Activity_1y52hvq" name="do wait">
|
35
|
-
<bpmn:incoming>Flow_1u1afua</bpmn:incoming>
|
36
|
-
<bpmn:outgoing>Flow_1oiihw7</bpmn:outgoing>
|
37
|
-
</bpmn:task>
|
38
|
-
<bpmn:sequenceFlow id="Flow_1oiihw7" sourceRef="Activity_1y52hvq" targetRef="Event_0z1wtnd" />
|
39
|
-
<bpmn:serviceTask id="Activity_1duxvq1" name="get process models" camunda:type="external" camunda:topic="processmodels">
|
29
|
+
<bpmn:serviceTask id="Activity_1duxvq1" name="SampleError" camunda:type="external" camunda:topic="SampleError">
|
40
30
|
<bpmn:incoming>Flow_110cohh</bpmn:incoming>
|
41
31
|
<bpmn:outgoing>Flow_1u1afua</bpmn:outgoing>
|
42
32
|
</bpmn:serviceTask>
|
33
|
+
<bpmn:sequenceFlow id="Flow_1u1afua" sourceRef="Activity_1duxvq1" targetRef="Event_0z1wtnd" />
|
34
|
+
<bpmn:endEvent id="Event_0z1wtnd">
|
35
|
+
<bpmn:incoming>Flow_1u1afua</bpmn:incoming>
|
36
|
+
</bpmn:endEvent>
|
43
37
|
</bpmn:process>
|
44
38
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
45
39
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1cidyxu">
|
46
40
|
<bpmndi:BPMNShape id="Participant_0px403d_di" bpmnElement="Participant_0px403d" isHorizontal="true">
|
47
|
-
<dc:Bounds x="5" y="4" width="
|
41
|
+
<dc:Bounds x="5" y="4" width="695" height="346" />
|
48
42
|
</bpmndi:BPMNShape>
|
49
43
|
<bpmndi:BPMNShape id="Lane_1xzf0d3_di" bpmnElement="Lane_1xzf0d3" isHorizontal="true">
|
50
|
-
<dc:Bounds x="35" y="4" width="
|
44
|
+
<dc:Bounds x="35" y="4" width="665" height="346" />
|
51
45
|
</bpmndi:BPMNShape>
|
52
46
|
<bpmndi:BPMNShape id="StartEvent_1_di" bpmnElement="StartEvent_1">
|
53
47
|
<dc:Bounds x="92" y="152" width="36" height="36" />
|
@@ -59,17 +53,13 @@
|
|
59
53
|
<dc:Bounds x="180" y="130" width="100" height="80" />
|
60
54
|
<bpmndi:BPMNLabel />
|
61
55
|
</bpmndi:BPMNShape>
|
62
|
-
<bpmndi:BPMNShape id="Event_0z1wtnd_di" bpmnElement="Event_0z1wtnd">
|
63
|
-
<dc:Bounds x="692" y="152" width="36" height="36" />
|
64
|
-
</bpmndi:BPMNShape>
|
65
|
-
<bpmndi:BPMNShape id="Activity_1y52hvq_di" bpmnElement="Activity_1y52hvq">
|
66
|
-
<dc:Bounds x="540" y="130" width="100" height="80" />
|
67
|
-
<bpmndi:BPMNLabel />
|
68
|
-
</bpmndi:BPMNShape>
|
69
56
|
<bpmndi:BPMNShape id="Activity_1ohliek_di" bpmnElement="Activity_1duxvq1">
|
70
57
|
<dc:Bounds x="370" y="130" width="100" height="80" />
|
71
58
|
<bpmndi:BPMNLabel />
|
72
59
|
</bpmndi:BPMNShape>
|
60
|
+
<bpmndi:BPMNShape id="Event_0z1wtnd_di" bpmnElement="Event_0z1wtnd">
|
61
|
+
<dc:Bounds x="562" y="152" width="36" height="36" />
|
62
|
+
</bpmndi:BPMNShape>
|
73
63
|
<bpmndi:BPMNEdge id="Flow_1xfzejj_di" bpmnElement="Flow_1xfzejj">
|
74
64
|
<di:waypoint x="128" y="170" />
|
75
65
|
<di:waypoint x="180" y="170" />
|
@@ -80,11 +70,7 @@
|
|
80
70
|
</bpmndi:BPMNEdge>
|
81
71
|
<bpmndi:BPMNEdge id="Flow_1u1afua_di" bpmnElement="Flow_1u1afua">
|
82
72
|
<di:waypoint x="470" y="170" />
|
83
|
-
<di:waypoint x="
|
84
|
-
</bpmndi:BPMNEdge>
|
85
|
-
<bpmndi:BPMNEdge id="Flow_1oiihw7_di" bpmnElement="Flow_1oiihw7">
|
86
|
-
<di:waypoint x="640" y="170" />
|
87
|
-
<di:waypoint x="692" y="170" />
|
73
|
+
<di:waypoint x="562" y="170" />
|
88
74
|
</bpmndi:BPMNEdge>
|
89
75
|
</bpmndi:BPMNPlane>
|
90
76
|
</bpmndi:BPMNDiagram>
|
package/processinstance-query.js
CHANGED
@@ -34,9 +34,9 @@ module.exports = function(RED) {
|
|
34
34
|
});
|
35
35
|
|
36
36
|
node.on('input', function(msg) {
|
37
|
-
|
37
|
+
let query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg)
|
38
38
|
|
39
|
-
client.processInstances.query(query).then((matchingInstances) => {
|
39
|
+
client.processInstances.query(query, { identity: node.server.identity }).then((matchingInstances) => {
|
40
40
|
|
41
41
|
msg.payload = matchingInstances;
|
42
42
|
|
package/signal-event-trigger.js
CHANGED
@@ -28,14 +28,31 @@ module.exports = function(RED) {
|
|
28
28
|
eventEmitter = flowContext.get('emitter');
|
29
29
|
}
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
node.
|
38
|
-
|
31
|
+
const register = async () => {
|
32
|
+
let currentIdentity = node.server.identity;
|
33
|
+
let subscription = await client.userTasks.onUserTaskFinished((userTaskFinishedNotification) => {
|
34
|
+
node.send({ payload: { flowNodeInstanceId: userTaskFinishedNotification.flowNodeInstanceId, action: "finished", type: "usertask" } });
|
35
|
+
}, { identity: currentIdentity });
|
36
|
+
|
37
|
+
node.server.registerOnIdentityChanged(async (identity) => {
|
38
|
+
client.userTasks.removeSubscription(subscription, currentIdentity);
|
39
|
+
currentIdentity = identity;
|
40
|
+
|
41
|
+
subscription = await client.userTasks.onUserTaskFinished((userTaskFinishedNotification) => {
|
42
|
+
node.send({ payload: { flowNodeInstanceId: userTaskFinishedNotification.flowNodeInstanceId, action: "finished", type: "usertask" } });
|
43
|
+
}, { identity: currentIdentity });
|
44
|
+
});
|
45
|
+
|
46
|
+
node.on("close", async () => {
|
47
|
+
client.userTasks.removeSubscription(subscription, currentIdentity);
|
48
|
+
client.dispose();
|
49
|
+
client = null;
|
50
|
+
});
|
51
|
+
}
|
52
|
+
|
53
|
+
if (node.server) {
|
54
|
+
register();
|
55
|
+
}
|
39
56
|
}
|
40
57
|
RED.nodes.registerType("usertask-finished-listener", UserTaskFinishedListener);
|
41
58
|
}
|
package/usertask-input.js
CHANGED
@@ -15,6 +15,7 @@ module.exports = function(RED) {
|
|
15
15
|
function UserTaskInput(config) {
|
16
16
|
RED.nodes.createNode(this,config);
|
17
17
|
var node = this;
|
18
|
+
var msgCounter = 0;
|
18
19
|
var flowContext = node.context().flow;
|
19
20
|
var nodeContext = node.context();
|
20
21
|
|
@@ -42,8 +43,11 @@ module.exports = function(RED) {
|
|
42
43
|
});
|
43
44
|
|
44
45
|
node.on('input', function(msg) {
|
45
|
-
|
46
|
-
|
46
|
+
let query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg)
|
47
|
+
query = {
|
48
|
+
...query,
|
49
|
+
identity: node.server.identity
|
50
|
+
}
|
47
51
|
client.userTasks.query(query).then((matchingFlowNodes) => {
|
48
52
|
|
49
53
|
if (!config.force_send_array && matchingFlowNodes && matchingFlowNodes.userTasks && matchingFlowNodes.userTasks.length == 1) {
|
package/usertask-new-listener.js
CHANGED
@@ -27,15 +27,33 @@ module.exports = function(RED) {
|
|
27
27
|
flowContext.set('emitter', new EventEmitter());
|
28
28
|
eventEmitter = flowContext.get('emitter');
|
29
29
|
}
|
30
|
+
|
31
|
+
const register = async () => {
|
32
|
+
let currentIdentity = node.server.identity;
|
33
|
+
let subscription = await client.userTasks.onUserTaskWaiting((userTaskWaitingNotification) => {
|
34
|
+
node.send({ payload: { flowNodeInstanceId: userTaskWaitingNotification.flowNodeInstanceId, action: "new", type: "usertask" } });
|
35
|
+
}, { identity: currentIdentity });
|
36
|
+
|
37
|
+
node.server.registerOnIdentityChanged(async (identity) => {
|
38
|
+
client.userTasks.removeSubscription(subscription, currentIdentity);
|
39
|
+
currentIdentity = identity;
|
40
|
+
|
41
|
+
subscription = await client.userTasks.onUserTaskWaiting((userTaskWaitingNotification) => {
|
42
|
+
node.send({ payload: { flowNodeInstanceId: userTaskWaitingNotification.flowNodeInstanceId, action: "new", type: "usertask" } });
|
43
|
+
}, { identity: currentIdentity });
|
44
|
+
});
|
45
|
+
|
46
|
+
node.on("close", async () => {
|
47
|
+
client.userTasks.removeSubscription(subscription, currentIdentity);
|
48
|
+
client.dispose();
|
49
|
+
client = null;
|
50
|
+
});
|
51
|
+
}
|
52
|
+
|
53
|
+
if (node.server) {
|
54
|
+
register();
|
55
|
+
}
|
30
56
|
|
31
|
-
node.on("close", async () => {
|
32
|
-
client.dispose();
|
33
|
-
client = null;
|
34
|
-
});
|
35
|
-
|
36
|
-
client.userTasks.onUserTaskWaiting((userTaskWaitingNotification) => {
|
37
|
-
node.send({ payload: { flowNodeInstanceId: userTaskWaitingNotification.flowNodeInstanceIdaction, action: "new", type: "usertask" } });
|
38
|
-
});
|
39
57
|
}
|
40
58
|
RED.nodes.registerType("usertask-new-listener", UserTaskNewListener);
|
41
59
|
}
|
package/usertask-output.js
CHANGED
@@ -37,7 +37,7 @@ module.exports = function(RED) {
|
|
37
37
|
|
38
38
|
const userTaskResult = RED.util.evaluateNodeProperty(config.result, config.result_type, node, msg);
|
39
39
|
|
40
|
-
client.userTasks.finishUserTask(flowNodeInstanceId, userTaskResult).then(() => {
|
40
|
+
client.userTasks.finishUserTask(flowNodeInstanceId, userTaskResult, node.server.identity).then(() => {
|
41
41
|
|
42
42
|
node.send(msg);
|
43
43
|
}).catch(error => {
|
package/wait-for-usertask.html
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
<script type="text/javascript">
|
2
|
-
RED.nodes.registerType('wait-for-usertask',{
|
3
|
-
category: 'ProcessCube',
|
4
|
-
color: '#02AFD6',
|
5
|
-
defaults: {
|
6
|
-
name: {value: ""},
|
7
|
-
engine: {value: "", type: "processcube-engine-config"},
|
8
|
-
query: {value: "payload"},
|
9
|
-
query_type: {value: "msg"},
|
10
|
-
only_for_new: {value: false}
|
11
|
-
},
|
12
|
-
inputs: 1,
|
13
|
-
outputs: 1,
|
14
|
-
icon: "font-awesome/fa-envelope-open",
|
15
|
-
label: function() {
|
16
|
-
return this.name || "wait-for-usertask";
|
17
|
-
},
|
18
|
-
oneditprepare: function() {
|
19
|
-
$("#node-input-query").typedInput({
|
20
|
-
default: 'msg',
|
21
|
-
types: ['msg', 'json']
|
22
|
-
});
|
23
|
-
|
24
|
-
$("#node-input-query").typedInput('value', this.query);
|
25
|
-
$("#node-input-query").typedInput('type', this.query_type);
|
26
|
-
},
|
27
|
-
oneditsave: function() {
|
28
|
-
this.query = $("#node-input-query").typedInput('value'),
|
29
|
-
this.query_type = $("#node-input-query").typedInput('type')
|
30
|
-
|
31
|
-
}
|
32
|
-
});
|
33
|
-
</script>
|
34
|
-
|
35
|
-
<script type="text/html" data-template-name="wait-for-usertask">
|
36
|
-
<div class="form-row">
|
37
|
-
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
38
|
-
<input type="text" id="node-input-name" placeholder="Name">
|
39
|
-
</div>
|
40
|
-
<div class="form-row">
|
41
|
-
<label for="node-input-engine"><i class="fa fa-tag"></i> Engine-URL</label>
|
42
|
-
<input type="text" id="node-input-engine" placeholder="http://engine:8000">
|
43
|
-
</div>
|
44
|
-
<div class="form-row">
|
45
|
-
<label for="node-input-query"><i class="fa fa-tag"></i> Query</label>
|
46
|
-
<input type="text" id="node-input-query">
|
47
|
-
</div>
|
48
|
-
<div class="form-row" style="display:flex; margin-bottom: 3px;">
|
49
|
-
<label for="node-input-only_for_new" style="vertical-align:top"><i class="fa fa-list-alt"></i> Only for new</label>
|
50
|
-
<div>
|
51
|
-
<input type="checkbox" checked id="node-input-only_for_new" style="display: inline-block; width: auto; margin: 0px 0px 0px 4px;">
|
52
|
-
<label style="width:auto" for="node-input-multisend">Trigger only for new user task or *checked* also for old ones?</label>
|
53
|
-
</div>
|
54
|
-
</div>
|
55
|
-
</script>
|
56
|
-
|
57
|
-
<script type="text/markdown" data-help-name="wait-for-usertask">
|
58
|
-
Waiting for Usertasks of the connected ProcessCube Engine.
|
59
|
-
|
60
|
-
### Inputs
|
61
|
-
|
62
|
-
: payload (json) : the query to filter the usertasks.
|
63
|
-
|
64
|
-
## Outputs
|
65
|
-
|
66
|
-
: payload.userTask (string) : The filtered UserTask
|
67
|
-
|
68
|
-
### Details
|
69
|
-
|
70
|
-
- `msg.payload` or a constant json to filter the UserTasks for Waiting for
|
71
|
-
- `Only for new` will trigger only for new UserTasks if checked and also for old ones if not checked.
|
72
|
-
|
73
|
-
### References
|
74
|
-
|
75
|
-
- [The ProcessCube Developer Network](https://processcube.io) - All documentation for the ProcessCube© Plattform
|
76
|
-
</script>
|
package/wait-for-usertask.js
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
const process = require('process');
|
2
|
-
|
3
|
-
const engine_client = require('@5minds/processcube_engine_client');
|
4
|
-
const { userInfo } = require('os');
|
5
|
-
|
6
|
-
module.exports = function (RED) {
|
7
|
-
function WaitForUsertask(config) {
|
8
|
-
RED.nodes.createNode(this, config);
|
9
|
-
var node = this;
|
10
|
-
var nodeContext = node.context();
|
11
|
-
|
12
|
-
this.engine = this.server = RED.nodes.getNode(config.engine);
|
13
|
-
|
14
|
-
const engineUrl = this.engine?.url || process.env.ENGINE_URL || 'http://engine:8000';
|
15
|
-
|
16
|
-
var client = nodeContext.get('client');
|
17
|
-
|
18
|
-
if (!client) {
|
19
|
-
nodeContext.set('client', new engine_client.EngineClient(engineUrl));
|
20
|
-
client = nodeContext.get('client');
|
21
|
-
}
|
22
|
-
|
23
|
-
node.on("close", async () => {
|
24
|
-
if (client != null) {
|
25
|
-
client.dispose();
|
26
|
-
client = null;
|
27
|
-
}
|
28
|
-
});
|
29
|
-
|
30
|
-
node.on('input', async function (msg) {
|
31
|
-
|
32
|
-
const query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg)
|
33
|
-
|
34
|
-
const sub = await client.userTasks.onUserTaskWaiting(async (userTaskWaitingNotification) => {
|
35
|
-
|
36
|
-
const newQuery = {
|
37
|
-
'flowNodeInstanceId': userTaskWaitingNotification.flowNodeInstanceId,
|
38
|
-
...query
|
39
|
-
};
|
40
|
-
|
41
|
-
const matchingFlowNodes = await client.userTasks.query(newQuery);
|
42
|
-
|
43
|
-
if (matchingFlowNodes.userTasks && matchingFlowNodes.userTasks.length == 1) {
|
44
|
-
const userTask = matchingFlowNodes.userTasks[0];
|
45
|
-
|
46
|
-
msg.payload = { userTask: userTask };
|
47
|
-
node.send(msg);
|
48
|
-
} else {
|
49
|
-
}
|
50
|
-
|
51
|
-
// remove subscription
|
52
|
-
client.userTasks.removeSubscription(sub);
|
53
|
-
});
|
54
|
-
|
55
|
-
console.debug('Handling old userTasks config.only_for_new', config.only_for_new);
|
56
|
-
|
57
|
-
if (config.only_for_new === false) {
|
58
|
-
// only check suspended user tasks
|
59
|
-
const suspendedQuery = {
|
60
|
-
'state': 'suspended',
|
61
|
-
...query
|
62
|
-
};
|
63
|
-
|
64
|
-
const matchingFlowNodes = await client.userTasks.query(suspendedQuery);
|
65
|
-
|
66
|
-
if (matchingFlowNodes.userTasks && matchingFlowNodes.userTasks.length >= 1) {
|
67
|
-
const userTask = matchingFlowNodes.userTasks[0];
|
68
|
-
|
69
|
-
msg.payload = { userTask: userTask };
|
70
|
-
node.send(msg);
|
71
|
-
|
72
|
-
// remove subscription
|
73
|
-
client.userTasks.removeSubscription(sub);
|
74
|
-
} else {
|
75
|
-
// let the *sub* be active
|
76
|
-
|
77
|
-
}
|
78
|
-
}
|
79
|
-
});
|
80
|
-
}
|
81
|
-
RED.nodes.registerType("wait-for-usertask", WaitForUsertask);
|
82
|
-
}
|