@5minds/node-red-contrib-processcube 2.0.0-feature-629c78-m2dq1ygt → 7.6.0-develop-51b534-mjy3s4sm

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.
Files changed (68) hide show
  1. package/README.md +3 -58
  2. package/check-authorization.html +138 -0
  3. package/check-authorization.js +27 -0
  4. package/dataobject-instance-query.html +141 -0
  5. package/dataobject-instance-query.js +45 -0
  6. package/endevent-finished-listener.js +14 -25
  7. package/examples/Check-Authorization-Sample.json +109 -0
  8. package/examples/Dataobject-Instance-Query-Sample.json +109 -0
  9. package/externaltask-error.html +8 -3
  10. package/externaltask-error.js +43 -29
  11. package/externaltask-event-listener.js +11 -28
  12. package/externaltask-input.html +48 -3
  13. package/externaltask-input.js +581 -114
  14. package/externaltask-output.js +20 -16
  15. package/icons/data-object-query.svg +5 -0
  16. package/message-event-trigger.html +1 -1
  17. package/message-event-trigger.js +8 -7
  18. package/package.json +74 -67
  19. package/process-event-listener.js +166 -225
  20. package/process-start.html +6 -0
  21. package/process-start.js +29 -6
  22. package/process-terminate.html +1 -1
  23. package/process-terminate.js +7 -5
  24. package/processcube-engine-config.html +25 -7
  25. package/processcube-engine-config.js +25 -135
  26. package/processcube-google-docs-mail-template.html +150 -0
  27. package/processcube-google-docs-mail-template.js +158 -0
  28. package/processdefinition-deploy.html +44 -0
  29. package/processdefinition-deploy.js +28 -0
  30. package/processdefinition-query.html +18 -13
  31. package/processdefinition-query.js +33 -31
  32. package/processinstance-delete-advanced.html +82 -0
  33. package/processinstance-delete-advanced.js +33 -0
  34. package/processinstance-delete.html +60 -8
  35. package/processinstance-delete.js +84 -30
  36. package/processinstance-query.html +116 -109
  37. package/processinstance-query.js +28 -5
  38. package/signal-event-trigger.js +8 -6
  39. package/usertask-event-listener.html +123 -1
  40. package/usertask-event-listener.js +30 -45
  41. package/usertask-input.html +119 -0
  42. package/usertask-input.js +7 -9
  43. package/usertask-output.js +15 -8
  44. package/wait-for-usertask.html +122 -6
  45. package/wait-for-usertask.js +44 -47
  46. package/.github/workflows/build-and-publish.yml +0 -72
  47. package/.processcube/authority/config/config.json +0 -36
  48. package/.processcube/authority/config/upeSeedingData.json +0 -12
  49. package/Dockerfile +0 -9
  50. package/doc_generator/_process_instances_query.md +0 -115
  51. package/doc_generator/generator.js +0 -41
  52. package/doc_generator/generator_with_swagger.js +0 -72
  53. package/doc_generator/package-lock.json +0 -176
  54. package/doc_generator/package.json +0 -15
  55. package/doc_generator/query_template.mustache +0 -20
  56. package/doc_generator/swagger.json +0 -4110
  57. package/docker-compose.yml +0 -44
  58. package/nodered/flows.json +0 -2156
  59. package/nodered/flows_cred.json +0 -3
  60. package/nodered/settings.js +0 -562
  61. package/nodered/static/ProcessCube_Logo.svg +0 -53
  62. package/processes/Call-Activity-Sample.bpmn +0 -88
  63. package/processes/External-Task-Auth-Sample.bpmn +0 -82
  64. package/processes/External-Task-Sample.bpmn +0 -94
  65. package/processes/SampleEvent.bpmn +0 -73
  66. package/processes/User-Task-Auth-Sample.bpmn +0 -63
  67. package/processes/User-Task-Sample.bpmn +0 -76
  68. package/processes/Wait-For-Usertask.bpmn +0 -74
@@ -44,19 +44,10 @@
44
44
  <label for="node-input-query"><i class="fa fa-tag"></i> Query</label>
45
45
  <input type="text" id="node-input-query" />
46
46
  </div>
47
- <div class="form-row" style="display:flex; margin-bottom: 3px;">
48
- <label for="node-input-models_only" style="vertical-align:top"
49
- ><i class="fa fa-list-alt"></i> Models Only</label
50
- >
51
- <div>
52
- <input
53
- type="checkbox"
54
- checked
55
- id="node-input-models_only"
56
- style="display: inline-block; width: auto; margin: 0px 0px 0px 4px;"
57
- />
58
- <label style="width:auto" for="node-input-models_only">Only send models as result.</label>
59
- </div>
47
+
48
+ <div class="form-row" style="margin-bottom: 3px;">
49
+ <input type="checkbox" checked id="node-input-models_only" style="display: inline-block; width: auto; vertical-align: top; margin-left: 30px; margin-right: 5px;">
50
+ <label style="width:auto" for="node-input-models_only">Only send models as result</label>
60
51
  </div>
61
52
  </script>
62
53
 
@@ -76,6 +67,20 @@ Only models can be queried by setting the `models_only` flag.
76
67
  : processDefinitions / models (Array) : The processDefinitions / models that matched the query.
77
68
  : totalCount (number) : The number of matches.
78
69
 
70
+
71
+ ### Query fields
72
+
73
+ **Summary**:
74
+
75
+ **Description**: Filter result for &#39;ProcessDefinitions Query&#39;
76
+
77
+ #### Parameters:
78
+ - Name: `offset` Required: `false`
79
+ - Type: number
80
+ - Description: The index of the first ProcessDefinition to include.
81
+ - Name: `limit` Required: `false`
82
+ - Type: number
83
+ - Description: The maximum number of ProcessDefinitions to include.
79
84
  ### References
80
85
 
81
86
  - [The ProcessCube&copy; Developer Network](https://processcube.io) - All documentation for the ProcessCube&copy; platform
@@ -4,43 +4,45 @@ module.exports = function (RED) {
4
4
  var node = this;
5
5
 
6
6
  node.on('input', function (msg) {
7
-
8
- const engine = RED.nodes.getNode(config.engine);
9
- const client = engine.engineClient;
7
+ node.engine = RED.nodes.getNode(config.engine);
8
+ const client = node.engine.engineClient;
10
9
 
11
10
  if (!client) {
12
- node.error('No engine configured.');
11
+ node.error('No engine configured.', msg);
13
12
  return;
14
13
  }
15
14
 
16
15
  let query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg);
17
-
18
- query = {
19
- ...query,
20
- identity: engine.identity,
21
- };
22
-
23
- client.processDefinitions.getAll(query).then((matchingProcessDefinitions) => {
24
-
25
- if (config.models_only && matchingProcessDefinitions.totalCount > 0) {
26
- let models = [];
27
-
28
- matchingProcessDefinitions.processDefinitions.forEach((processDefinition) => {
29
- processDefinition.processModels.forEach((model) => {
30
- models.push(model);
31
- });
32
- });
33
-
34
- msg.payload = {
35
- models: models,
36
- totalCount: models.length,
37
- };
38
- } else {
39
- msg.payload = matchingProcessDefinitions;
40
- }
41
-
42
- node.send(msg);
43
- });
16
+
17
+ if (typeof query !== 'object' || Array.isArray(query) || query === null) {
18
+ query = {};
19
+ }
20
+
21
+ node.log(`Querying process definitions with query: ${JSON.stringify(query)}`);
22
+
23
+ const isUser = !!msg._client?.user && !!msg._client.user.accessToken;
24
+ const identity = isUser ? { userId: msg._client.user.id, token: msg._client.user.accessToken } : null;
25
+ query.identity = identity;
26
+
27
+ client.processDefinitions
28
+ .getAll(query)
29
+ .then((matchingProcessDefinitions) => {
30
+ if (config.models_only) {
31
+ const models = matchingProcessDefinitions.processDefinitions.flatMap(processDefinition => processDefinition.processModels);
32
+
33
+ msg.payload = {
34
+ models: models,
35
+ totalCount: models.length,
36
+ };
37
+ } else {
38
+ msg.payload = matchingProcessDefinitions;
39
+ }
40
+
41
+ node.send(msg);
42
+ })
43
+ .catch((error) => {
44
+ node.error(error, msg);
45
+ });
44
46
  });
45
47
  }
46
48
  RED.nodes.registerType('processdefinition-query', ProcessdefinitionQuery);
@@ -0,0 +1,82 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType('processinstance-delete-advanced', {
3
+ category: 'ProcessCube DevOps',
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
+ delete_releated: { value: false },
11
+ },
12
+ inputs: 1,
13
+ outputs: 1,
14
+ icon: 'font-awesome/fa-sign-in',
15
+ label: function () {
16
+ return this.name || 'processinstance-delete-advanced';
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
+ </script>
33
+
34
+ <script type="text/html" data-template-name="processinstance-delete-advanced">
35
+ <div class="form-row">
36
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
37
+ <input type="text" id="node-input-name" placeholder="Name" />
38
+ </div>
39
+ <div class="form-row">
40
+ <label for="node-input-engine"><i class="fa fa-link"></i> Engine-URL</label>
41
+ <input type="text" id="node-input-engine" placeholder="Engine-URL" />
42
+ </div>
43
+ <div class="form-row">
44
+ <label for="node-input-query"><i class="fa fa-search"></i> Query</label>
45
+ <input type="text" id="node-input-query" />
46
+ </div>
47
+ <div class="form-row" style="margin-bottom: 3px;">
48
+ <label style="width:auto" for="node-input-delete_releated"><i class="fa fa-trash"></i> Related Data</label>
49
+ <input
50
+ type="checkbox"
51
+ checked
52
+ id="node-input-delete_releated"
53
+ style="display: inline-block; width: auto; vertical-align: top; margin-left: 5px; margin-right: 3px;"
54
+ />
55
+ <label style="width:auto"> Delete</label>
56
+ </div>
57
+ </script>
58
+
59
+ <script type="text/markdown" data-help-name="processinstance-delete-advanced">
60
+ Delete outdated instances of a process model in ProcessCube.
61
+
62
+ *Supported only on engines version 19 or higher.*
63
+
64
+ ## Inputs
65
+
66
+ The node can take an input query from either a specific field on the msg object or as a json object directly in the nodes configuration.
67
+ In both cases the node supports the following fields in the query:
68
+
69
+
70
+ : processInstanceId (String): The IDs of the ProcessInstances to delete.
71
+ : processModelId (String): The ID of the ProcessModel to delete the instances from.
72
+ : finishedBefore (Datetime): The date before which the instances should be deleted.
73
+ : finshedAfter (Datetime): The date after which the instances should be deleted.
74
+
75
+
76
+ ## Outputs
77
+
78
+ ### References
79
+
80
+ - [The ProcessCube Developer Network](https://processcube.io) - All documentation for the ProcessCube&copy; platform
81
+ - [Node-RED Integration in ProcessCube&copy;](https://processcube.io/docs/node-red) - Node-RED integration in ProcessCube&copy;
82
+ </script>
@@ -0,0 +1,33 @@
1
+ module.exports = function (RED) {
2
+ function ProcessInstanceDeleteAdvanced(config) {
3
+ RED.nodes.createNode(this, config);
4
+ const node = this;
5
+
6
+ node.on('input', async function (msg) {
7
+ node.engine = RED.nodes.getNode(config.engine);
8
+ const client = node.engine ? node.engine.engineClient : null;
9
+
10
+ let query = RED.util.evaluateNodeProperty(config.query, config.query_type, node, msg);
11
+
12
+ const isUser = !!msg._client?.user && !!msg._client.user.accessToken;
13
+ const userIdentity = isUser ? { userId: msg._client.user.id, token: msg._client.user.accessToken } : null;
14
+
15
+ if (!client || !client.processInstances) {
16
+ node.error('No engine or processInstances API configured.', msg);
17
+ return;
18
+ }
19
+
20
+ try {
21
+ const result = await client.processInstances.delete(query, config.delete_releated, userIdentity)
22
+
23
+ msg.payload = result
24
+
25
+ node.send(msg);
26
+ } catch (queryError) {
27
+ node.error(`Failed to delete process instances Error: ${queryError.message}`, msg);
28
+ }
29
+ });
30
+ }
31
+
32
+ RED.nodes.registerType('processinstance-delete-advanced', ProcessInstanceDeleteAdvanced);
33
+ };
@@ -5,8 +5,10 @@
5
5
  defaults: {
6
6
  name: { value: '' },
7
7
  engine: { value: '', type: 'processcube-engine-config' },
8
- time: { value: '', type: 'number' },
9
- time_type: { value: 'hours' },
8
+ modelid: { value: '' },
9
+ duration: { value: '', type: 'number' },
10
+ time_type: { value: '' },
11
+ batch_size: { value: '100', type: 'number' },
10
12
  },
11
13
  inputs: 1,
12
14
  outputs: 1,
@@ -27,29 +29,79 @@
27
29
  <input type="text" id="node-input-engine" placeholder="Engine-URL" />
28
30
  </div>
29
31
  <div class="form-row">
30
- <label for="node-input-time"><i class="fa fa-tag"></i> Time</label>
31
- <input type="text" id="node-input-time" />
32
+ <label for="node-input-modelid"><i class="fa fa-tag"></i> Model-ID</label>
33
+ <input type="text" id="node-input-modelid" />
32
34
  </div>
33
35
  <div class="form-row">
34
- <label for="node-input-time_type"><i class="fa fa-sliders"></i> Period</label>
36
+ <label for="node-input-duration"><i class="fa fa-tag"></i> Duration</label>
37
+ <input type="text" id="node-input-duration" />
38
+ </div>
39
+ <div class="form-row">
40
+ <label for="node-input-time_type"><i class="fa fa-sliders"></i> Time Unit</label>
35
41
  <select id="node-input-time_type" style="width: 70%;">
36
42
  <option value="hours">Hours</option>
37
43
  <option value="days">Days</option>
38
44
  </select>
39
45
  </div>
46
+ <div class="form-row">
47
+ <label for="node-input-batch-size"><i class="fa fa-tag"></i> Batch Size</label>
48
+ <input type="text" id="node-input-batch_size" />
49
+ </div>
40
50
  </script>
41
51
 
42
52
  <script type="text/markdown" data-help-name="processinstance-delete">
43
- Delete old instances of a process model in the ProcessCube.
53
+ Delete old instances of a process model in the ProcessCube.
44
54
 
45
55
  ## Inputs
46
56
 
47
- : payload.time (number): The number of given time periods.
57
+ : payload.duration (number): The number of given time periods.
48
58
  : payload.time_type ('hours' | 'days'): The type of time period to use.
59
+ : payload.batch_size (number): The number of instances to be deleted simultaneously. (default 100)
49
60
 
50
61
  ## Outputs
51
62
 
52
- : payload (string[]): The ids of the processinstances that were deleted.
63
+ : Explanation of the payload:
64
+
65
+ Object
66
+ {
67
+ successfulDeletions: [Array of strings],
68
+ failedDeletions: [Array of objects]
69
+ }
70
+
71
+ - successfulDeletions:
72
+ - Type: Array<String>
73
+ - Content: A list of successfully deleted process instance IDs.
74
+
75
+ - excample:
76
+ successfulDeletions: [
77
+ "instanceId1",
78
+ "instanceId2",
79
+ "instanceId3"
80
+ ]
81
+
82
+ - failedDeletions:
83
+ - Type: Array<Object>
84
+ - Content: A list of objects containing details of the failed deletions.
85
+ - Each object has the following fields:
86
+ - id: The ID of the process instance that could not be deleted.
87
+ - error: The error message or the reason for the error.
88
+
89
+ - Example of a complete output:
90
+ {
91
+ successfulDeletions: [
92
+ "instanceId1",
93
+ "instanceId2",
94
+ "instanceId3"
95
+ ],
96
+ failedDeletions: [
97
+ { id: "instanceId4", error: "Permission denied" },
98
+ { id: "instanceId5", error: "Instance not found" }
99
+ ]
100
+ }
101
+
102
+ The node processes the IDs in configurable batches (default value: 100) and inserts successfully deleted or failed instances into the arrays accordingly.
103
+ As processing is currently forced to batch, a detailed error output is not possible.
104
+ If an error occurs during the processing of a batch, all Id's of this batch are marked as faulty.
53
105
 
54
106
  ### References
55
107
 
@@ -1,52 +1,106 @@
1
1
  module.exports = function (RED) {
2
2
  function ProcessInstanceDelete(config) {
3
3
  RED.nodes.createNode(this, config);
4
- var node = this;
4
+ const node = this;
5
5
 
6
6
  node.on('input', async function (msg) {
7
- const engine = RED.nodes.getNode(config.engine);
8
- const client = engine.engineClient;
7
+ node.engine = RED.nodes.getNode(config.engine);
8
+ const client = node.engine ? node.engine.engineClient : null;
9
9
 
10
- if (!client) {
11
- node.error('No engine configured.');
10
+ const isUser = !!msg._client?.user && !!msg._client.user.accessToken;
11
+ const userIdentity = isUser ? { userId: msg._client.user.id, token: msg._client.user.accessToken } : null;
12
+
13
+ if (!client || !client.processInstances) {
14
+ node.error('No engine or processInstances API configured.', msg);
15
+ return;
16
+ }
17
+
18
+ const timeToUse = msg.payload.duration || config.duration;
19
+ if (!timeToUse || isNaN(timeToUse) || timeToUse <= 0) {
20
+ node.error('Invalid duration: must be a positive number.', msg);
21
+ return;
22
+ }
23
+
24
+ // Gültige Werte für time_type
25
+ const validTimeTypes = ['days', 'hours'];
26
+ const timeType = msg.payload.time_type
27
+ ? msg.payload.time_type.toLowerCase()
28
+ : config.time_type?.toLowerCase();
29
+
30
+ // time_type validieren
31
+ if (!timeType || !validTimeTypes.includes(timeType)) {
32
+ node.error(`Invalid time_type provided: ${timeType}. Allowed values are 'days' or 'hours'.`, msg);
12
33
  return;
13
34
  }
14
- let timeMultiplier;
15
- if (msg.payload.time_type) {
16
- timeMultiplier = msg.payload.time_type == 'hours' ? 1 : 24;
17
- } else {
18
- timeMultiplier = config.time_type == 'hours' ? 1 : 24;
35
+
36
+ // Zeitmultiplikator berechnen
37
+ const multiplier = timeType === 'hours' ? 1 : 24;
38
+ node.log(`Time type: ${timeType}`);
39
+
40
+ const deletionDate = new Date(Date.now() - timeToUse * multiplier * 60 * 60 * 1000);
41
+
42
+ const modelId = msg.payload.processModelId?.trim() || config.modelid?.trim();
43
+ if (!modelId) {
44
+ node.error('processModelId is not defined or empty.', msg);
45
+ return;
19
46
  }
20
47
 
21
- const timeToUse = msg.payload.time ? msg.payload.time : config.time;
48
+ // Prüfung und Festlegung von batch_size
49
+ let batchSize = msg.payload.batch_size || config.batch_size || 1000;
50
+ if (isNaN(batchSize) || batchSize <= 0 || batchSize > 1000) {
51
+ node.error(`Invalid batch_size: ${batchSize}. Must be a positive number and not exceed 1000.`, msg);
52
+ return;
53
+ }
54
+ batchSize = Math.min(batchSize, 1000); // Sicherstellen, dass der Wert 1000 nicht überschreitet
22
55
 
23
56
  try {
24
- const fetchInstancesByState = async (state) => {
25
- const result = await client.processInstances.query({ state });
26
- return result.processInstances;
27
- };
57
+ msg.payload = { successfulDeletions: [], failedDeletions: [] };
28
58
 
29
- const finishedInstances = await fetchInstancesByState('finished');
30
- const terminatedInstances = await fetchInstancesByState('terminated');
31
- const errorInstances = await fetchInstancesByState('error');
59
+ let hasMoreResults = true;
60
+ let sumSuccessful = 0;
61
+ let sumFailed = 0;
62
+ while (hasMoreResults) {
63
+ const result = await client.processInstances.query(
64
+ {
65
+ processModelId: modelId,
66
+ finishedBefore: deletionDate.toISOString(),
67
+ state: ['finished', 'error', 'terminated'],
68
+ limit: batchSize,
69
+ },
70
+ {
71
+ includeXml: false,
72
+ identity: userIdentity
73
+ }
74
+ );
32
75
 
33
- let allInstances = [...finishedInstances, ...terminatedInstances, ...errorInstances];
76
+ const processInstances = result.processInstances || [];
77
+ if (processInstances.length === 0) {
78
+ node.log(`No more process instances to delete for Model-ID: ${modelId} with Date: ${deletionDate.toISOString()}`, msg);
79
+ hasMoreResults = false;
80
+ continue;
81
+ }
34
82
 
35
- const today = new Date();
83
+ const ids = processInstances.map((obj) => obj.processInstanceId);
36
84
 
37
- const oldTasks = allInstances.filter((instance) => {
38
- const finishedDate = new Date(instance.finishedAt);
39
- const diffInHours = (today - finishedDate) / (1000 * 60 * 60);
40
- return diffInHours > Number(timeToUse) * timeMultiplier;
41
- });
85
+ try {
86
+ await client.processInstances.deleteProcessInstances(ids, true, userIdentity);
87
+ msg.payload.successfulDeletions.push(...ids);
88
+ sumSuccessful += ids.length;
89
+ } catch (deleteError) {
90
+ var message = JSON.stringify(deleteError);
91
+ sumFailed += ids.length;
92
+ ids.forEach((id) => {
93
+ msg.payload.failedDeletions.push({ id, error: message });
94
+ });
95
+ node.warn(`Failed to delete some process instances for Model-ID: ${modelId}. Error: ${message}`);
96
+ }
97
+ }
98
+ node.log(`Successfully deleted ${sumSuccessful} process instances and ${sumFailed} failed to delete process instances for Model-ID: ${modelId}.`);
42
99
 
43
- const ids = oldTasks.map((obj) => obj.processInstanceId);
44
- msg.payload = ids;
45
100
 
46
- await client.processInstances.deleteProcessInstances(ids, true, engine.identity);
47
101
  node.send(msg);
48
- } catch (error) {
49
- node.error(error);
102
+ } catch (queryError) {
103
+ node.error(`Failed to query process instances for Model-ID: ${modelId}. Error: ${queryError.message}`, msg);
50
104
  }
51
105
  });
52
106
  }