@nocobase/plugin-workflow 0.8.1-alpha.4 → 0.9.0-alpha.2

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.
@@ -123,6 +123,7 @@ const WorkflowProvider = props => {
123
123
  title: (0, _locale.lang)('Workflow'),
124
124
  tabs: {
125
125
  workflows: {
126
+ isBookmark: true,
126
127
  title: (0, _locale.lang)('Workflow'),
127
128
  component: WorkflowPane
128
129
  }
@@ -1,14 +1,21 @@
1
1
  declare const _default: {
2
2
  Workflow: string;
3
3
  "Execution history": string;
4
+ Executed: string;
4
5
  "Trigger type": string;
5
6
  Status: string;
6
7
  On: string;
7
8
  Off: string;
8
9
  Version: string;
9
10
  "Copy to new version": string;
11
+ Duplicate: string;
12
+ Loading: string;
10
13
  "Load failed": string;
11
14
  Trigger: string;
15
+ "Trigger variables": string;
16
+ "Trigger data": string;
17
+ "Trigger time": string;
18
+ "Triggered at": string;
12
19
  "Collection event": string;
13
20
  "Trigger on": string;
14
21
  "After record added": string;
@@ -24,6 +31,7 @@ declare const _default: {
24
31
  "Based on date field of collection": string;
25
32
  "Starts on": string;
26
33
  "Ends on": string;
34
+ "No end": string;
27
35
  "Exactly at": string;
28
36
  "Repeat mode": string;
29
37
  "Repeat limit": string;
@@ -45,36 +53,51 @@ declare const _default: {
45
53
  "By custom date": string;
46
54
  Advanced: string;
47
55
  End: string;
48
- "Trigger variables": string;
49
56
  "Node result": string;
50
57
  Constant: string;
58
+ Null: string;
51
59
  Boolean: string;
52
60
  String: string;
61
+ Calculator: string;
53
62
  "Arithmetic calculation": string;
54
63
  "String operation": string;
64
+ "Executed at": string;
65
+ Queueing: string;
55
66
  "On going": string;
56
67
  Succeeded: string;
57
68
  Failed: string;
69
+ Pending: string;
58
70
  Canceled: string;
59
71
  "This node contains branches, deleting will also be preformed to them, are you sure?": string;
60
72
  Control: string;
61
73
  "Collection operations": string;
74
+ "Extended types": string;
62
75
  "Node type": string;
63
76
  Calculation: string;
64
77
  "Configure calculation": string;
65
78
  "Calculation result": string;
66
79
  True: string;
67
80
  False: string;
81
+ concat: string;
68
82
  Condition: string;
69
83
  Mode: string;
70
84
  "Continue when \"Yes\"": string;
71
85
  "Branch into \"Yes\" and \"No\"": string;
72
86
  Conditions: string;
73
87
  "Parallel branch": string;
88
+ "Add branch": string;
74
89
  "All succeeded": string;
75
90
  "Any succeeded": string;
91
+ "Any succeeded or failed": string;
76
92
  "Continue after all branches succeeded": string;
77
93
  "Continue after any branch succeeded": string;
94
+ "Continue after any branch succeeded, or exit after any branch failed": string;
95
+ Delay: string;
96
+ Duration: string;
97
+ "End Status": string;
98
+ "Select status": string;
99
+ "Succeed and continue": string;
100
+ "Fail and exit": string;
78
101
  "Create record": string;
79
102
  "Update record": string;
80
103
  "Query record": string;
@@ -84,22 +107,24 @@ declare const _default: {
84
107
  "Fields that are not assigned a value will be set to the default value, and those that do not have a default value are set to null.": string;
85
108
  "Trigger in executed workflow cannot be modified": string;
86
109
  "Node in executed workflow cannot be modified": string;
87
- 'HTTP request': string;
110
+ "Can not delete": string;
111
+ "The result of this node has been referenced by other nodes ({{nodes}}), please remove the usage before deleting.": string;
112
+ "HTTP request": string;
88
113
  URL: string;
89
- 'You can use the above available variables in URL.': string;
90
- 'Request headers': string;
91
- 'Name(e.g. Content-Type)': string;
92
- 'Value(e.g. Application/json)': string;
93
- 'Add request header': string;
94
- 'HTTP method': string;
95
- 'Request data': string;
96
- 'Input request data': string;
97
- 'You can use the above available variables in request data.': string;
98
- 'Copy success!': string;
99
- 'Copy variable output template statement': string;
100
- 'Default headers is Content-Type: application/json': string;
101
- 'Ignore fail request and continue workflow': string;
102
- 'Syntax see': string;
103
- 'Show available variable tool': string;
114
+ "You can use the above available variables in URL.": string;
115
+ "Request headers": string;
116
+ "Name(e.g. Content-Type)": string;
117
+ "Value(e.g. Application/json)": string;
118
+ "Add request header": string;
119
+ "HTTP method": string;
120
+ "Request data": string;
121
+ "Input request data": string;
122
+ "You can use the above available variables in request data.": string;
123
+ "Copy success!": string;
124
+ "Copy variable output template statement": string;
125
+ "Default headers is Content-Type: application/json": string;
126
+ "Ignore fail request and continue workflow": string;
127
+ "Syntax see": string;
128
+ "Show available variable tool": string;
104
129
  };
105
130
  export default _default;
@@ -7,14 +7,21 @@ exports.default = void 0;
7
7
  var _default = {
8
8
  "Workflow": "Workflow",
9
9
  "Execution history": "Execution history",
10
+ "Executed": "Executed",
10
11
  "Trigger type": "Trigger type",
11
12
  "Status": "Status",
12
13
  "On": "On",
13
14
  "Off": "Off",
14
15
  "Version": "Version",
15
16
  "Copy to new version": "Copy to new version",
17
+ "Duplicate": "Duplicate",
18
+ "Loading": "Loading",
16
19
  "Load failed": "Load failed",
17
20
  "Trigger": "Trigger",
21
+ "Trigger variables": "Trigger variables",
22
+ "Trigger data": "Trigger data",
23
+ "Trigger time": "Trigger time",
24
+ "Triggered at": "Triggered at",
18
25
  "Collection event": "Collection event",
19
26
  "Trigger on": "Trigger on",
20
27
  "After record added": "After record added",
@@ -30,6 +37,7 @@ var _default = {
30
37
  "Based on date field of collection": "Based on date field of collection",
31
38
  "Starts on": "Starts on",
32
39
  "Ends on": "Ends on",
40
+ "No end": "No end",
33
41
  "Exactly at": "Exactly at",
34
42
  "Repeat mode": "Repeat mode",
35
43
  "Repeat limit": "Repeat limit",
@@ -51,36 +59,51 @@ var _default = {
51
59
  "By custom date": "By custom date",
52
60
  "Advanced": "Advanced",
53
61
  "End": "End",
54
- "Trigger variables": "Trigger variables",
55
62
  "Node result": "Node result",
56
63
  "Constant": "Constant",
64
+ "Null": "Null",
57
65
  "Boolean": "Boolean",
58
66
  "String": "String",
67
+ "Calculator": "Calculator",
59
68
  "Arithmetic calculation": "Arithmetic calculation",
60
69
  "String operation": "String operation",
70
+ "Executed at": "Executed at",
71
+ "Queueing": "Queueing",
61
72
  "On going": "On going",
62
73
  "Succeeded": "Succeeded",
63
74
  "Failed": "Failed",
75
+ "Pending": "Pending",
64
76
  "Canceled": "Canceled",
65
77
  "This node contains branches, deleting will also be preformed to them, are you sure?": "This node contains branches, deleting will also be preformed to them, are you sure?",
66
78
  "Control": "Control",
67
79
  "Collection operations": "Collection operations",
80
+ "Extended types": "Extended types",
68
81
  "Node type": "Node type",
69
82
  "Calculation": "Calculation",
70
83
  "Configure calculation": "Configure calculation",
71
84
  "Calculation result": "Calculation result",
72
85
  "True": "True",
73
86
  "False": "False",
87
+ "concat": "concat",
74
88
  "Condition": "Condition",
75
89
  "Mode": "Mode",
76
90
  "Continue when \"Yes\"": "Continue when \"Yes\"",
77
91
  "Branch into \"Yes\" and \"No\"": "Branch into \"Yes\" and \"No\"",
78
92
  "Conditions": "Conditions",
79
93
  "Parallel branch": "Parallel branch",
94
+ "Add branch": "Add branch",
80
95
  "All succeeded": "All succeeded",
81
96
  "Any succeeded": "Any succeeded",
97
+ "Any succeeded or failed": "Any succeeded or failed",
82
98
  "Continue after all branches succeeded": "Continue after all branches succeeded",
83
99
  "Continue after any branch succeeded": "Continue after any branch succeeded",
100
+ "Continue after any branch succeeded, or exit after any branch failed": "Continue after any branch succeeded, or exit after any branch failed",
101
+ "Delay": "Delay",
102
+ "Duration": "Duration",
103
+ "End Status": "End Status",
104
+ "Select status": "Select status",
105
+ "Succeed and continue": "Succeed and continue",
106
+ "Fail and exit": "Fail and exit",
84
107
  "Create record": "Create record",
85
108
  "Update record": "Update record",
86
109
  "Query record": "Query record",
@@ -90,22 +113,24 @@ var _default = {
90
113
  "Fields that are not assigned a value will be set to the default value, and those that do not have a default value are set to null.": "Fields that are not assigned a value will be set to the default value, and those that do not have a default value are set to null.",
91
114
  "Trigger in executed workflow cannot be modified": "Trigger in executed workflow cannot be modified",
92
115
  "Node in executed workflow cannot be modified": "Node in executed workflow cannot be modified",
93
- 'HTTP request': 'HTTP request',
94
- 'URL': 'URL',
95
- 'You can use the above available variables in URL.': 'You can use the above available variables in URL.',
96
- 'Request headers': 'Request headers',
97
- 'Name(e.g. Content-Type)': 'Name(e.g. Content-Type)',
98
- 'Value(e.g. Application/json)': 'Value(e.g. Application/json)',
99
- 'Add request header': 'Add request header',
100
- 'HTTP method': 'HTTP method',
101
- 'Request data': 'Request data',
102
- 'Input request data': 'Input request data',
103
- 'You can use the above available variables in request data.': 'You can use the above available variables in request data.',
104
- 'Copy success!': 'Copy success!',
105
- 'Copy variable output template statement': 'Copy variable output template statement',
106
- 'Default headers is Content-Type: application/json': 'Default headers is Content-Type: application/json',
107
- 'Ignore fail request and continue workflow': 'Ignore fail request and continue workflow',
108
- 'Syntax see': 'Syntax see',
109
- 'Show available variable tool': 'Show available variable tool'
116
+ "Can not delete": "Can not delete",
117
+ "The result of this node has been referenced by other nodes ({{nodes}}), please remove the usage before deleting.": "The result of this node has been referenced by other nodes ({{nodes}}), please remove the usage before deleting.",
118
+ "HTTP request": "HTTP request",
119
+ "URL": "URL",
120
+ "You can use the above available variables in URL.": "You can use the above available variables in URL.",
121
+ "Request headers": "Request headers",
122
+ "Name(e.g. Content-Type)": "Name(e.g. Content-Type)",
123
+ "Value(e.g. Application/json)": "Value(e.g. Application/json)",
124
+ "Add request header": "Add request header",
125
+ "HTTP method": "HTTP method",
126
+ "Request data": "Request data",
127
+ "Input request data": "Input request data",
128
+ "You can use the above available variables in request data.": "You can use the above available variables in request data.",
129
+ "Copy success!": "Copy success!",
130
+ "Copy variable output template statement": "Copy variable output template statement",
131
+ "Default headers is Content-Type: application/json": "Default headers is Content-Type: application/json",
132
+ "Ignore fail request and continue workflow": "Ignore fail request and continue workflow",
133
+ "Syntax see": "Syntax see",
134
+ "Show available variable tool": "Show available variable tool"
110
135
  };
111
136
  exports.default = _default;
@@ -7,56 +7,39 @@ exports.NAMESPACE = void 0;
7
7
  exports.lang = lang;
8
8
  exports.useWorkflowTranslation = useWorkflowTranslation;
9
9
 
10
- function _reactI18next() {
11
- const data = require("react-i18next");
10
+ function _client() {
11
+ const data = require("@nocobase/client");
12
12
 
13
- _reactI18next = function _reactI18next() {
13
+ _client = function _client() {
14
14
  return data;
15
15
  };
16
16
 
17
17
  return data;
18
18
  }
19
19
 
20
- function _client() {
21
- const data = require("@nocobase/client");
20
+ function _reactI18next() {
21
+ const data = require("react-i18next");
22
22
 
23
- _client = function _client() {
23
+ _reactI18next = function _reactI18next() {
24
24
  return data;
25
25
  };
26
26
 
27
27
  return data;
28
28
  }
29
29
 
30
- var _zhCN = _interopRequireDefault(require("./zh-CN"));
31
-
32
- var _enUS = _interopRequireDefault(require("./en-US"));
33
-
34
- var _jaJP = _interopRequireDefault(require("./ja-JP"));
35
-
36
- var _ruRU = _interopRequireDefault(require("./ru-RU"));
37
-
38
- var _trTR = _interopRequireDefault(require("./tr-TR"));
39
-
40
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
41
-
42
30
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
43
31
 
44
32
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
45
33
 
46
34
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
47
35
 
48
- const NAMESPACE = 'workflow';
49
- exports.NAMESPACE = NAMESPACE;
50
-
51
- _client().i18n.addResources('zh-CN', NAMESPACE, _zhCN.default);
52
-
53
- _client().i18n.addResources('en-US', NAMESPACE, _enUS.default);
36
+ const NAMESPACE = 'workflow'; // i18n.addResources('zh-CN', NAMESPACE, zhCN);
37
+ // i18n.addResources('en-US', NAMESPACE, enUS);
38
+ // i18n.addResources('ja-JP', NAMESPACE, jaJP);
39
+ // i18n.addResources('ru-RU', NAMESPACE, ruRU);
40
+ // i18n.addResources('tr-TR', NAMESPACE, trTR);
54
41
 
55
- _client().i18n.addResources('ja-JP', NAMESPACE, _jaJP.default);
56
-
57
- _client().i18n.addResources('ru-RU', NAMESPACE, _ruRU.default);
58
-
59
- _client().i18n.addResources('tr-TR', NAMESPACE, _trTR.default);
42
+ exports.NAMESPACE = NAMESPACE;
60
43
 
61
44
  function lang(key, options = {}) {
62
45
  return _client().i18n.t(key, _objectSpread(_objectSpread({}, options), {}, {
@@ -2,9 +2,9 @@ import { Plugin } from '@nocobase/server';
2
2
  import { Registry } from '@nocobase/utils';
3
3
  import { Instruction } from './instructions';
4
4
  import ExecutionModel from './models/Execution';
5
+ import JobModel from './models/Job';
5
6
  import WorkflowModel from './models/Workflow';
6
7
  import { Trigger } from './triggers';
7
- import JobModel from './models/Job';
8
8
  declare type Pending = [ExecutionModel, JobModel?];
9
9
  export default class WorkflowPlugin extends Plugin {
10
10
  instructions: Registry<Instruction>;
@@ -164,6 +164,8 @@ class WorkflowPlugin extends _server().Plugin {
164
164
  context = _event[1],
165
165
  options = _event[2];
166
166
 
167
+ let valid = true;
168
+
167
169
  if ((_options$context = options.context) === null || _options$context === void 0 ? void 0 : _options$context.executionId) {
168
170
  // NOTE: no transaction here for read-uncommitted execution
169
171
  const existed = yield workflow.countExecutions({
@@ -173,57 +175,63 @@ class WorkflowPlugin extends _server().Plugin {
173
175
  });
174
176
 
175
177
  if (existed) {
176
- console.warn(`workflow ${workflow.id} has already been triggered in same execution (${options.context.executionId}), and newly triggering will be skipped.`);
177
- return;
178
+ _this.app.logger.warn(`[Workflow] workflow ${workflow.id} has already been triggered in same execution (${options.context.executionId}), and newly triggering will be skipped.`);
179
+
180
+ valid = false;
178
181
  }
179
182
  }
180
183
 
181
- const execution = yield _this.db.sequelize.transaction( /*#__PURE__*/function () {
182
- var _ref3 = _asyncToGenerator(function* (transaction) {
183
- const execution = yield workflow.createExecution({
184
- context,
185
- key: workflow.key,
186
- status: _constants.EXECUTION_STATUS.CREATED,
187
- useTransaction: workflow.useTransaction
188
- }, {
189
- transaction
184
+ if (valid) {
185
+ const execution = yield _this.db.sequelize.transaction( /*#__PURE__*/function () {
186
+ var _ref3 = _asyncToGenerator(function* (transaction) {
187
+ const execution = yield workflow.createExecution({
188
+ context,
189
+ key: workflow.key,
190
+ status: _constants.EXECUTION_STATUS.CREATED,
191
+ useTransaction: workflow.useTransaction
192
+ }, {
193
+ transaction
194
+ });
195
+ const executed = yield workflow.countExecutions({
196
+ transaction
197
+ }); // NOTE: not to trigger afterUpdate hook here
198
+
199
+ yield workflow.update({
200
+ executed
201
+ }, {
202
+ transaction,
203
+ hooks: false
204
+ });
205
+ const allExecuted = yield execution.constructor.count({
206
+ where: {
207
+ key: workflow.key
208
+ },
209
+ transaction
210
+ });
211
+ yield workflow.constructor.update({
212
+ allExecuted
213
+ }, {
214
+ where: {
215
+ key: workflow.key
216
+ },
217
+ individualHooks: true,
218
+ transaction
219
+ });
220
+ execution.workflow = workflow;
221
+ return execution;
190
222
  });
191
- const executed = yield workflow.countExecutions({
192
- transaction
193
- }); // NOTE: not to trigger afterUpdate hook here
194
223
 
195
- yield workflow.update({
196
- executed
197
- }, {
198
- transaction,
199
- hooks: false
200
- });
201
- const allExecuted = yield execution.constructor.count({
202
- where: {
203
- key: workflow.key
204
- },
205
- transaction
206
- });
207
- yield workflow.constructor.update({
208
- allExecuted
209
- }, {
210
- where: {
211
- key: workflow.key
212
- },
213
- individualHooks: true,
214
- transaction
215
- });
216
- execution.workflow = workflow;
217
- return execution;
218
- });
224
+ return function (_x3) {
225
+ return _ref3.apply(this, arguments);
226
+ };
227
+ }());
219
228
 
220
- return function (_x3) {
221
- return _ref3.apply(this, arguments);
222
- };
223
- }()); // NOTE: cache first execution for most cases
229
+ _this.app.logger.debug(`[Workflow] execution of workflow ${workflow.id} created as ${execution.id}`); // NOTE: cache first execution for most cases
224
230
 
225
- if (!_this.executing && !_this.pending.length) {
226
- _this.pending.push([execution]);
231
+
232
+ if (!_this.executing && !_this.pending.length) {
233
+ _this.pending.push([execution]);
234
+ }
227
235
  }
228
236
 
229
237
  if (_this.events.length) {
@@ -240,6 +248,14 @@ class WorkflowPlugin extends _server().Plugin {
240
248
  return _asyncToGenerator(function* () {
241
249
  const db = _this2.db,
242
250
  options = _this2.options;
251
+
252
+ _this2.app.acl.registerSnippet({
253
+ name: `pm.${_this2.name}.workflows`,
254
+ actions: ['workflows:*', 'workflows.nodes:*', 'executions:list', 'executions:get', 'flow_nodes:update', 'flow_nodes:destroy']
255
+ });
256
+
257
+ _this2.app.acl.allow('users_jobs', ['list', 'get', 'submit'], 'loggedIn');
258
+
243
259
  yield db.import({
244
260
  directory: _path().default.resolve(__dirname, 'collections')
245
261
  });
@@ -320,6 +336,7 @@ class WorkflowPlugin extends _server().Plugin {
320
336
  }
321
337
 
322
338
  this.events.push([workflow, context, options]);
339
+ this.app.logger.debug(`[Workflow] new event triggered, now events: ${this.events.length}`);
323
340
 
324
341
  if (this.events.length > 1) {
325
342
  return;
@@ -390,8 +407,14 @@ class WorkflowPlugin extends _server().Plugin {
390
407
 
391
408
  const processor = _this5.createProcessor(execution);
392
409
 
393
- console.log('workflow processing:', new Date(), execution.workflowId, execution.id);
394
- yield job ? processor.resume(job) : processor.start();
410
+ _this5.app.logger.info(`[Workflow] execution ${execution.id} ${job ? 'resuming' : 'starting'} ...`);
411
+
412
+ try {
413
+ yield job ? processor.resume(job) : processor.start();
414
+ } catch (err) {
415
+ _this5.app.logger.error(`[Workflow] ${err.message}`, err);
416
+ }
417
+
395
418
  _this5.executing = null;
396
419
 
397
420
  _this5.dispatch();
@@ -250,15 +250,13 @@ class Processor {
250
250
 
251
251
  return _asyncToGenerator(function* () {
252
252
  const instructions = _this7.options.plugin.instructions;
253
+ const instruction = instructions.get(node.type);
253
254
 
254
- const _instructions$get = instructions.get(node.type),
255
- run = _instructions$get.run;
256
-
257
- if (typeof run !== 'function') {
255
+ if (typeof instruction.run !== 'function') {
258
256
  return Promise.reject(new Error('`run` should be implemented for customized execution of the node'));
259
257
  }
260
258
 
261
- return _this7.exec(run, node, input);
259
+ return _this7.exec(instruction.run.bind(instruction), node, input);
262
260
  })();
263
261
  } // parent node should take over the control
264
262
 
@@ -286,15 +284,13 @@ class Processor {
286
284
 
287
285
  return _asyncToGenerator(function* () {
288
286
  const instructions = _this9.options.plugin.instructions;
287
+ const instruction = instructions.get(node.type);
289
288
 
290
- const _instructions$get2 = instructions.get(node.type),
291
- resume = _instructions$get2.resume;
292
-
293
- if (typeof resume !== 'function') {
289
+ if (typeof instruction.resume !== 'function') {
294
290
  return Promise.reject(new Error('`resume` should be implemented'));
295
291
  }
296
292
 
297
- return _this9.exec(resume, node, job);
293
+ return _this9.exec(instruction.resume.bind(instruction), node, job);
298
294
  })();
299
295
  }
300
296
 
@@ -2,13 +2,16 @@ import { AxiosRequestConfig } from 'axios';
2
2
  import { Instruction } from './index';
3
3
  export interface Header {
4
4
  name: string;
5
- value: any;
5
+ value: string;
6
6
  }
7
7
  export declare type RequestConfig = Pick<AxiosRequestConfig, 'url' | 'method' | 'data' | 'timeout'> & {
8
8
  headers: Array<Header>;
9
9
  ignoreFail: boolean;
10
10
  };
11
11
  export default class implements Instruction {
12
+ plugin: any;
13
+ constructor(plugin: any);
14
+ request: (node: any, job: any, processor: any) => Promise<any>;
12
15
  run(node: any, input: any, processor: any): Promise<any>;
13
16
  resume(node: any, job: any, processor: any): Promise<any>;
14
17
  }