@veridid/workflow-parser 0.3.1 → 0.4.0
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/package.json +17 -32
- package/src/implementations/action.default.js +114 -0
- package/src/implementations/action.default.ts +74 -0
- package/src/implementations/display.default.js +132 -0
- package/src/implementations/display.default.ts +98 -0
- package/src/implementations/workflow.default.js +146 -0
- package/src/implementations/workflow.default.ts +64 -0
- package/src/index.js +6 -0
- package/src/index.ts +6 -0
- package/src/interfaces/actionextension.js +2 -0
- package/src/interfaces/actionextension.ts +7 -0
- package/src/interfaces/actioninterface.js +2 -0
- package/src/interfaces/actioninterface.ts +11 -0
- package/src/interfaces/displayextension.js +2 -0
- package/src/interfaces/displayextension.ts +7 -0
- package/src/interfaces/displayinterface.js +2 -0
- package/src/interfaces/displayinterface.ts +13 -0
- package/src/interfaces/workflowinterface.js +2 -0
- package/src/interfaces/workflowinterface.ts +24 -0
- package/{dist/schema.sql → src/support/Schema.sql} +2 -2
- package/src/workflowparser.js +100 -0
- package/src/workflowparser.ts +70 -0
- package/test/action.extension.js +65 -0
- package/test/action.extension.ts +22 -0
- package/test/display.extension.js +60 -0
- package/test/display.extension.ts +16 -0
- package/test/docker-compose.yml +33 -0
- package/test/pg_hba.conf +14 -0
- package/test/postgresql.conf +42 -0
- package/test/tables.sql +17 -0
- package/test/test.js +233 -0
- package/test/test.ts +159 -0
- package/test/testworkflows.json +223 -0
- package/tsconfig.json +15 -0
package/package.json
CHANGED
|
@@ -1,42 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veridid/workflow-parser",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
5
|
-
"main": "
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "FOr parsing JOSN data that represents data-driven state machines and delivering the display data for clients to render.",
|
|
5
|
+
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
-
"start": "node dist/index.js",
|
|
9
|
-
"prepublishOnly": "npm run build",
|
|
10
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
|
+
"test": " tsc --resolveJsonModule test/test.ts && node test/test.js"
|
|
11
8
|
},
|
|
9
|
+
"keywords": ["workflow", "Parser", "Data-Driven State Machine"],
|
|
10
|
+
"author": "VeriDID Corp. Nas TIl and Dave McKay",
|
|
11
|
+
"license": "MIT",
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
14
|
-
"url": "git+https://github.com/
|
|
15
|
-
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
"workflow",
|
|
18
|
-
"parser",
|
|
19
|
-
"action-menu"
|
|
20
|
-
],
|
|
21
|
-
"author": "Nas Til - VeriDID",
|
|
22
|
-
"license": "Apache-2.0",
|
|
23
|
-
"bugs": {
|
|
24
|
-
"url": "https://github.com/VeriDID/workflow-parser/issues"
|
|
25
|
-
},
|
|
26
|
-
"homepage": "https://github.com/VeriDID/workflow-parser#readme",
|
|
27
|
-
"dependencies": {
|
|
28
|
-
"dotenv": "^16.4.5",
|
|
29
|
-
"pg": "^8.12.0",
|
|
30
|
-
"uuid": "^10.0.0"
|
|
14
|
+
"url": "git+https://github.com/DigiCred-Holdings/workflow-parser.git"
|
|
31
15
|
},
|
|
16
|
+
"homepage": "https://github.com/DigiCred-Holdings/workflow-parser#readme",
|
|
32
17
|
"devDependencies": {
|
|
33
|
-
"
|
|
34
|
-
"@types/node": "^20.14.2",
|
|
35
|
-
"@types/pg": "^8.11.6",
|
|
36
|
-
"@types/uuid": "^9.0.8",
|
|
37
|
-
"typescript": "^5.4.5"
|
|
18
|
+
"typescript": "^5.8.2"
|
|
38
19
|
},
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@types/pg": "^8.11.11",
|
|
22
|
+
"pg": "^8.14.1",
|
|
23
|
+
"reflect-metadata": "^0.2.2",
|
|
24
|
+
"typedi": "^0.10.0",
|
|
25
|
+
"uuid": "^11.1.0"
|
|
26
|
+
}
|
|
42
27
|
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.DefaultAction = void 0;
|
|
40
|
+
var DefaultAction = /** @class */ (function () {
|
|
41
|
+
function DefaultAction(actionExtension) {
|
|
42
|
+
this.actionExtension = actionExtension;
|
|
43
|
+
}
|
|
44
|
+
DefaultAction.prototype.processAction = function (currentWorkflow, instance, actionInput) {
|
|
45
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
46
|
+
var transition, state, action, findtransition;
|
|
47
|
+
return __generator(this, function (_a) {
|
|
48
|
+
switch (_a.label) {
|
|
49
|
+
case 0:
|
|
50
|
+
console.log("*** processAction action=", actionInput);
|
|
51
|
+
transition = {
|
|
52
|
+
type: "none",
|
|
53
|
+
workflow_id: instance.workflow_id,
|
|
54
|
+
state_id: instance.current_state
|
|
55
|
+
};
|
|
56
|
+
if (!(actionInput.actionID != "")) return [3 /*break*/, 4];
|
|
57
|
+
state = currentWorkflow.states.find(function (item) { return item.state_id == instance.current_state; });
|
|
58
|
+
if (!(state.actions.length > 0)) return [3 /*break*/, 3];
|
|
59
|
+
action = state.actions.find(function (item) { return item.action_id == actionInput.actionID; });
|
|
60
|
+
if (!this.actionExtension) return [3 /*break*/, 2];
|
|
61
|
+
return [4 /*yield*/, this.actionExtension.actions(actionInput, instance, action, transition)];
|
|
62
|
+
case 1:
|
|
63
|
+
transition = _a.sent();
|
|
64
|
+
_a.label = 2;
|
|
65
|
+
case 2:
|
|
66
|
+
// handle the types of actions
|
|
67
|
+
switch (action === null || action === void 0 ? void 0 : action.type) {
|
|
68
|
+
case "saveData":
|
|
69
|
+
// check condition
|
|
70
|
+
if (eval(action.condition)) {
|
|
71
|
+
// save the data from the workflow action to the instance data
|
|
72
|
+
instance.state_data = Object.assign(instance.state_data, action.value);
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
case "stateData":
|
|
76
|
+
// check condition
|
|
77
|
+
if (eval(action.condition)) {
|
|
78
|
+
// save the data from the actionInput to the instance data
|
|
79
|
+
instance.state_data = Object.assign(instance.state_data, actionInput.data);
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
case "stateTransition":
|
|
83
|
+
// check condition
|
|
84
|
+
if (eval(action.condition)) {
|
|
85
|
+
// set the transition condition for a new state
|
|
86
|
+
transition.type = "stateTransition";
|
|
87
|
+
transition.state_id = action.state_id;
|
|
88
|
+
}
|
|
89
|
+
break;
|
|
90
|
+
case "workflowTransition":
|
|
91
|
+
// check condition
|
|
92
|
+
if (eval(action.condition)) {
|
|
93
|
+
// set the transition condition for a new workflow
|
|
94
|
+
transition.type = "workflowTransition";
|
|
95
|
+
transition.workflow_id = action.workflow_id;
|
|
96
|
+
}
|
|
97
|
+
break;
|
|
98
|
+
default:
|
|
99
|
+
}
|
|
100
|
+
_a.label = 3;
|
|
101
|
+
case 3:
|
|
102
|
+
findtransition = state.transitions.find(function (item) { return eval(item.condition); });
|
|
103
|
+
if (findtransition) {
|
|
104
|
+
transition = findtransition;
|
|
105
|
+
}
|
|
106
|
+
_a.label = 4;
|
|
107
|
+
case 4: return [2 /*return*/, transition];
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
return DefaultAction;
|
|
113
|
+
}());
|
|
114
|
+
exports.DefaultAction = DefaultAction;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { IActionExtension } from "../interfaces/actionextension";
|
|
2
|
+
import { IAction, Transition } from "../interfaces/actioninterface";
|
|
3
|
+
import { Instance, Workflow } from "../interfaces/workflowinterface";
|
|
4
|
+
|
|
5
|
+
export class DefaultAction implements IAction{
|
|
6
|
+
actionExtension: IActionExtension;
|
|
7
|
+
|
|
8
|
+
constructor(actionExtension: IActionExtension) {
|
|
9
|
+
this.actionExtension = actionExtension;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async processAction(currentWorkflow: Workflow, instance: Instance, actionInput: any): Promise<Transition>{
|
|
13
|
+
console.log("*** processAction action=", actionInput);
|
|
14
|
+
// start with a blank transition
|
|
15
|
+
let transition:Transition = {
|
|
16
|
+
type: "none",
|
|
17
|
+
workflow_id: instance.workflow_id,
|
|
18
|
+
state_id: instance.current_state
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
if(actionInput.actionID!="") {
|
|
22
|
+
// find the state
|
|
23
|
+
const state = currentWorkflow.states.find(item => { return item.state_id == instance.current_state });
|
|
24
|
+
// Only process actions if there are any
|
|
25
|
+
if(state.actions.length>0) {
|
|
26
|
+
const action = state.actions.find(item => { return item.action_id == actionInput.actionID })
|
|
27
|
+
// handle the types of actions from the extension first
|
|
28
|
+
if(this.actionExtension) {
|
|
29
|
+
transition = await this.actionExtension.actions(actionInput, instance, action, transition)
|
|
30
|
+
}
|
|
31
|
+
// handle the types of actions
|
|
32
|
+
switch(action?.type) {
|
|
33
|
+
case "saveData":
|
|
34
|
+
// check condition
|
|
35
|
+
if(eval(action.condition)) {
|
|
36
|
+
// save the data from the workflow action to the instance data
|
|
37
|
+
instance.state_data = Object.assign(instance.state_data, action.value);
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
case "stateData":
|
|
41
|
+
// check condition
|
|
42
|
+
if(eval(action.condition)) {
|
|
43
|
+
// save the data from the actionInput to the instance data
|
|
44
|
+
instance.state_data = Object.assign(instance.state_data, actionInput.data);
|
|
45
|
+
}
|
|
46
|
+
break;
|
|
47
|
+
case "stateTransition":
|
|
48
|
+
// check condition
|
|
49
|
+
if(eval(action.condition)) {
|
|
50
|
+
// set the transition condition for a new state
|
|
51
|
+
transition.type = "stateTransition";
|
|
52
|
+
transition.state_id = action.state_id;
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
case "workflowTransition":
|
|
56
|
+
// check condition
|
|
57
|
+
if(eval(action.condition)) {
|
|
58
|
+
// set the transition condition for a new workflow
|
|
59
|
+
transition.type = "workflowTransition";
|
|
60
|
+
transition.workflow_id = action.workflow_id;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
default:
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// check the transitions until the first true condition
|
|
67
|
+
let findtransition = state.transitions.find(item => { return eval(item.condition) })
|
|
68
|
+
if(findtransition) {
|
|
69
|
+
transition = findtransition;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return transition;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.DefaultDisplay = void 0;
|
|
40
|
+
var DefaultDisplay = /** @class */ (function () {
|
|
41
|
+
function DefaultDisplay(displayExtension) {
|
|
42
|
+
this.displayExtension = displayExtension;
|
|
43
|
+
}
|
|
44
|
+
DefaultDisplay.prototype.processDisplay = function (clientID, curentWorkflow, instance, currentState) {
|
|
45
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
46
|
+
var displayData, display, displayTemplate, i, newValue;
|
|
47
|
+
var _a;
|
|
48
|
+
return __generator(this, function (_b) {
|
|
49
|
+
switch (_b.label) {
|
|
50
|
+
case 0:
|
|
51
|
+
console.log("*** processDisplay");
|
|
52
|
+
displayData = { displayData: [] };
|
|
53
|
+
display = curentWorkflow.states.find(function (item) { return item.state_id == currentState; });
|
|
54
|
+
displayTemplate = display.display_data;
|
|
55
|
+
i = 0;
|
|
56
|
+
_b.label = 1;
|
|
57
|
+
case 1:
|
|
58
|
+
if (!(i < displayTemplate.length)) return [3 /*break*/, 5];
|
|
59
|
+
// condition can use instance.stateData
|
|
60
|
+
if ((_a = displayTemplate[i]) === null || _a === void 0 ? void 0 : _a.condition) {
|
|
61
|
+
if (!eval(displayTemplate[i].condition)) {
|
|
62
|
+
return [3 /*break*/, 4]; // don't process if condition not met
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!this.displayExtension) return [3 /*break*/, 3];
|
|
66
|
+
return [4 /*yield*/, this.displayExtension.displays(instance, displayTemplate[i])];
|
|
67
|
+
case 2:
|
|
68
|
+
newValue = _b.sent();
|
|
69
|
+
if (newValue) {
|
|
70
|
+
displayTemplate[i] = newValue;
|
|
71
|
+
}
|
|
72
|
+
_b.label = 3;
|
|
73
|
+
case 3:
|
|
74
|
+
switch (displayTemplate[i].type) {
|
|
75
|
+
case "text":
|
|
76
|
+
displayTemplate[i].text = this.parseString(displayTemplate[i].text, instance.state_data);
|
|
77
|
+
break;
|
|
78
|
+
case "control":
|
|
79
|
+
displayTemplate[i].text = this.parseString(displayTemplate[i].text, instance.state_data);
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
displayData.displayData[i] = displayTemplate[i];
|
|
83
|
+
_b.label = 4;
|
|
84
|
+
case 4:
|
|
85
|
+
i++;
|
|
86
|
+
return [3 /*break*/, 1];
|
|
87
|
+
case 5: return [2 /*return*/, displayData];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
DefaultDisplay.prototype.parseString = function (text, data) {
|
|
93
|
+
// Split out the string
|
|
94
|
+
var parts = text.split(/[{,}]/);
|
|
95
|
+
// check every other string segment looking for a key in data
|
|
96
|
+
// Text for parsing should not start with a variable "{variable} hello!"
|
|
97
|
+
// *** repalce this code with a more comprehensive parser
|
|
98
|
+
for (var i = 1; i < parts.length; i += 2) {
|
|
99
|
+
// find this value in the data
|
|
100
|
+
var value = this.findNode(parts[i], data);
|
|
101
|
+
if (value) {
|
|
102
|
+
// if there is a value, replace the entry
|
|
103
|
+
parts[i] = value;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// put the string back together again
|
|
107
|
+
return parts.join("");
|
|
108
|
+
};
|
|
109
|
+
DefaultDisplay.prototype.findNode = function (id, currentNode) {
|
|
110
|
+
var currentChild, result;
|
|
111
|
+
if (id in currentNode) {
|
|
112
|
+
return currentNode[id];
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// use a for loop instead of forEach to avoid nested functions
|
|
116
|
+
// otherwise "return" will not work properly
|
|
117
|
+
for (var i = 0; currentNode.children !== undefined; i += 1) {
|
|
118
|
+
currentChild = currentNode.children[i];
|
|
119
|
+
// Search in the current child
|
|
120
|
+
result = this.findNode(id, currentChild);
|
|
121
|
+
// Return the result if the node has been found
|
|
122
|
+
if (result !== false) {
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// the node has not been found and we have no more options
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
return DefaultDisplay;
|
|
131
|
+
}());
|
|
132
|
+
exports.DefaultDisplay = DefaultDisplay;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { IDisplayExtension } from "../interfaces/displayextension";
|
|
2
|
+
import { DisplayData, IDisplay } from "../interfaces/displayinterface";
|
|
3
|
+
import { Instance, Workflow } from "../interfaces/workflowinterface";
|
|
4
|
+
|
|
5
|
+
export class DefaultDisplay implements IDisplay {
|
|
6
|
+
displayExtension: IDisplayExtension;
|
|
7
|
+
|
|
8
|
+
constructor(displayExtension: IDisplayExtension) {
|
|
9
|
+
this.displayExtension = displayExtension;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async processDisplay(
|
|
13
|
+
clientID: string,
|
|
14
|
+
curentWorkflow: Workflow,
|
|
15
|
+
instance: Instance,
|
|
16
|
+
currentState: string): Promise<DisplayData> {
|
|
17
|
+
|
|
18
|
+
console.log("*** processDisplay");
|
|
19
|
+
// build the display data to return
|
|
20
|
+
let displayData: DisplayData = {displayData: []};
|
|
21
|
+
// for each display entry check condition and process if required
|
|
22
|
+
const display = curentWorkflow.states.find(item => { return item.state_id == currentState});
|
|
23
|
+
const displayTemplate = display.display_data;
|
|
24
|
+
for(var i=0; i<displayTemplate.length; i++) {
|
|
25
|
+
// condition can use instance.stateData
|
|
26
|
+
if(displayTemplate[i]?.condition) {
|
|
27
|
+
if(!eval(displayTemplate[i].condition)) {
|
|
28
|
+
continue; // don't process if condition not met
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// handle the types of displays from the extension first
|
|
33
|
+
if(this.displayExtension) {
|
|
34
|
+
let newValue = await this.displayExtension.displays(instance, displayTemplate[i]);
|
|
35
|
+
if(newValue) {
|
|
36
|
+
displayTemplate[i]=newValue;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
switch(displayTemplate[i].type) {
|
|
41
|
+
case "text":
|
|
42
|
+
displayTemplate[i].text= this.parseString(displayTemplate[i].text, instance.state_data);
|
|
43
|
+
break;
|
|
44
|
+
case "control":
|
|
45
|
+
displayTemplate[i].text= this.parseString(displayTemplate[i].text, instance.state_data);
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
displayData.displayData[i]=displayTemplate[i];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return displayData;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
parseString(text: string, data: any) {
|
|
55
|
+
// Split out the string
|
|
56
|
+
const parts = text.split(/[{,}]/);
|
|
57
|
+
// check every other string segment looking for a key in data
|
|
58
|
+
// Text for parsing should not start with a variable "{variable} hello!"
|
|
59
|
+
// *** repalce this code with a more comprehensive parser
|
|
60
|
+
|
|
61
|
+
for(var i=1;i<parts.length; i+=2) {
|
|
62
|
+
// find this value in the data
|
|
63
|
+
let value = this.findNode(parts[i], data);
|
|
64
|
+
if(value) {
|
|
65
|
+
// if there is a value, replace the entry
|
|
66
|
+
parts[i]=value;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// put the string back together again
|
|
70
|
+
return parts.join("");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
findNode(id: string, currentNode: any): any {
|
|
75
|
+
var currentChild: any, result: any;
|
|
76
|
+
|
|
77
|
+
if (id in currentNode) {
|
|
78
|
+
return currentNode[id];
|
|
79
|
+
} else {
|
|
80
|
+
// use a for loop instead of forEach to avoid nested functions
|
|
81
|
+
// otherwise "return" will not work properly
|
|
82
|
+
for (var i = 0; currentNode.children !== undefined ; i += 1) {
|
|
83
|
+
currentChild = currentNode.children[i];
|
|
84
|
+
|
|
85
|
+
// Search in the current child
|
|
86
|
+
result = this.findNode(id, currentChild);
|
|
87
|
+
|
|
88
|
+
// Return the result if the node has been found
|
|
89
|
+
if (result !== false) {
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// the node has not been found and we have no more options
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.DefaultWorkflow = void 0;
|
|
40
|
+
var uuid_1 = require("uuid");
|
|
41
|
+
var DefaultWorkflow = /** @class */ (function () {
|
|
42
|
+
function DefaultWorkflow(dbClient) {
|
|
43
|
+
this.dbClient = dbClient;
|
|
44
|
+
}
|
|
45
|
+
DefaultWorkflow.prototype.getWorkflowByID = function (workflowID) {
|
|
46
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
47
|
+
var res;
|
|
48
|
+
var _a;
|
|
49
|
+
return __generator(this, function (_b) {
|
|
50
|
+
switch (_b.label) {
|
|
51
|
+
case 0:
|
|
52
|
+
console.log("*** getWorkflowByID");
|
|
53
|
+
return [4 /*yield*/, ((_a = this.dbClient) === null || _a === void 0 ? void 0 : _a.query('SELECT * FROM workflows WHERE "workflow_id" = $1', [workflowID]))];
|
|
54
|
+
case 1:
|
|
55
|
+
res = _b.sent();
|
|
56
|
+
//console.log("WorkflowID=", workflowID);
|
|
57
|
+
//console.log("Workflow=", res.rows[0]);
|
|
58
|
+
return [2 /*return*/, res.rows.length > 0 ? res.rows[0] : null];
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
DefaultWorkflow.prototype.getInstanceByID = function (clientID, workflowID) {
|
|
64
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
65
|
+
var instance, query, res, workflow;
|
|
66
|
+
var _a;
|
|
67
|
+
return __generator(this, function (_b) {
|
|
68
|
+
switch (_b.label) {
|
|
69
|
+
case 0:
|
|
70
|
+
console.log("*** getInstanceByID");
|
|
71
|
+
instance = null;
|
|
72
|
+
query = 'SELECT * FROM instances WHERE "client_id" = $1 AND "workflow_id" = $2';
|
|
73
|
+
return [4 /*yield*/, ((_a = this.dbClient) === null || _a === void 0 ? void 0 : _a.query(query, [clientID, workflowID]))];
|
|
74
|
+
case 1:
|
|
75
|
+
res = _b.sent();
|
|
76
|
+
if (!(res.rows.length === 0)) return [3 /*break*/, 4];
|
|
77
|
+
return [4 /*yield*/, this.getWorkflowByID(workflowID)];
|
|
78
|
+
case 2:
|
|
79
|
+
workflow = _b.sent();
|
|
80
|
+
return [4 /*yield*/, this.newInstance(clientID, workflowID, workflow.initial_state)];
|
|
81
|
+
case 3:
|
|
82
|
+
// Create new instance with new instanceID, the initial state fromt he workflow, and empoty instance data
|
|
83
|
+
instance = _b.sent();
|
|
84
|
+
return [3 /*break*/, 5];
|
|
85
|
+
case 4:
|
|
86
|
+
instance = res.rows.length > 0 ? res.rows[0] : null;
|
|
87
|
+
_b.label = 5;
|
|
88
|
+
case 5:
|
|
89
|
+
//console.log("Instance=", instance);
|
|
90
|
+
return [2 /*return*/, instance];
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
DefaultWorkflow.prototype.newInstance = function (clientID, workflowID, stateID) {
|
|
96
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
97
|
+
var query, result, res;
|
|
98
|
+
var _a;
|
|
99
|
+
return __generator(this, function (_b) {
|
|
100
|
+
switch (_b.label) {
|
|
101
|
+
case 0:
|
|
102
|
+
console.log("*** newInstance=", clientID, workflowID, stateID);
|
|
103
|
+
query = 'INSERT INTO instances (instance_id, workflow_id, client_id, current_state, state_data) VALUES ($1, $2, $3, $4, $5)';
|
|
104
|
+
return [4 /*yield*/, ((_a = this.dbClient) === null || _a === void 0 ? void 0 : _a.query(query, [(0, uuid_1.v4)(), workflowID, clientID, stateID, {}]))];
|
|
105
|
+
case 1:
|
|
106
|
+
result = _b.sent();
|
|
107
|
+
return [4 /*yield*/, this.getInstanceByID(clientID, workflowID)];
|
|
108
|
+
case 2:
|
|
109
|
+
res = _b.sent();
|
|
110
|
+
return [2 /*return*/, res];
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
DefaultWorkflow.prototype.updateInstanceByID = function (clientID, workflowID, stateID, data) {
|
|
116
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
117
|
+
var instance, query;
|
|
118
|
+
var _a;
|
|
119
|
+
return __generator(this, function (_b) {
|
|
120
|
+
switch (_b.label) {
|
|
121
|
+
case 0:
|
|
122
|
+
console.log("*** updateInstance=", clientID, workflowID, stateID, data);
|
|
123
|
+
return [4 /*yield*/, this.getInstanceByID(clientID, workflowID)];
|
|
124
|
+
case 1:
|
|
125
|
+
instance = _b.sent();
|
|
126
|
+
query = "UPDATE instances SET current_state = $1, state_data = $2 WHERE workflow_id = $3 AND client_id = $4";
|
|
127
|
+
//console.log("query=", query);
|
|
128
|
+
//console.log("stateID=", stateID, " data=", data);
|
|
129
|
+
//console.log("workflowID=", stateID, " clientID=", clientID);
|
|
130
|
+
return [4 /*yield*/, ((_a = this.dbClient) === null || _a === void 0 ? void 0 : _a.query(query, [stateID, JSON.stringify(data), workflowID, clientID]))];
|
|
131
|
+
case 2:
|
|
132
|
+
//console.log("query=", query);
|
|
133
|
+
//console.log("stateID=", stateID, " data=", data);
|
|
134
|
+
//console.log("workflowID=", stateID, " clientID=", clientID);
|
|
135
|
+
_b.sent();
|
|
136
|
+
return [4 /*yield*/, this.getInstanceByID(clientID, workflowID)];
|
|
137
|
+
case 3:
|
|
138
|
+
instance = _b.sent();
|
|
139
|
+
return [2 /*return*/, instance];
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
return DefaultWorkflow;
|
|
145
|
+
}());
|
|
146
|
+
exports.DefaultWorkflow = DefaultWorkflow;
|