@nocobase/plugin-workflow 1.5.0-beta.9 → 1.6.0-alpha.10

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 (39) hide show
  1. package/dist/client/4147131201cde30c.js +10 -0
  2. package/dist/client/{e7b9d67c6a964bec.js → 6dc5d1b15d6a5026.js} +1 -1
  3. package/dist/client/FlowContext.d.ts +2 -0
  4. package/dist/client/WorkflowTasks.d.ts +17 -0
  5. package/dist/client/a0f7941b557d9712.js +10 -0
  6. package/dist/client/index.d.ts +3 -0
  7. package/dist/client/index.js +1 -1
  8. package/dist/client/nodes/output.d.ts +31 -0
  9. package/dist/client/triggers/schedule/ScheduleModes.d.ts +5 -2
  10. package/dist/client/triggers/schedule/index.d.ts +2 -0
  11. package/dist/client/variable.d.ts +17 -6
  12. package/dist/externalVersion.js +10 -10
  13. package/dist/locale/zh-CN.json +4 -2
  14. package/dist/node_modules/cron-parser/package.json +1 -1
  15. package/dist/node_modules/lru-cache/package.json +1 -1
  16. package/dist/server/Plugin.d.ts +5 -2
  17. package/dist/server/Plugin.js +41 -8
  18. package/dist/server/Processor.d.ts +1 -0
  19. package/dist/server/Processor.js +2 -1
  20. package/dist/server/actions/workflows.js +5 -2
  21. package/dist/server/collections/executions.js +9 -0
  22. package/dist/server/collections/flow_nodes.js +1 -0
  23. package/dist/server/collections/jobs.js +1 -0
  24. package/dist/server/collections/workflows.js +1 -0
  25. package/dist/server/instructions/CreateInstruction.js +1 -1
  26. package/dist/server/instructions/DestroyInstruction.js +1 -1
  27. package/dist/server/instructions/UpdateInstruction.js +1 -1
  28. package/dist/server/triggers/CollectionTrigger.d.ts +3 -6
  29. package/dist/server/triggers/CollectionTrigger.js +43 -31
  30. package/dist/server/triggers/ScheduleTrigger/DateFieldScheduleTrigger.d.ts +1 -0
  31. package/dist/server/triggers/ScheduleTrigger/DateFieldScheduleTrigger.js +27 -1
  32. package/dist/server/triggers/ScheduleTrigger/StaticScheduleTrigger.d.ts +1 -0
  33. package/dist/server/triggers/ScheduleTrigger/StaticScheduleTrigger.js +3 -0
  34. package/dist/server/triggers/ScheduleTrigger/index.d.ts +1 -2
  35. package/dist/server/triggers/ScheduleTrigger/index.js +6 -3
  36. package/dist/server/triggers/index.d.ts +1 -1
  37. package/package.json +3 -3
  38. package/dist/client/5ed8ff0f70ed5911.js +0 -10
  39. package/dist/client/92877729dbcede8f.js +0 -10
@@ -0,0 +1,31 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import { Instruction } from '.';
10
+ import { WorkflowVariableInput } from '../variable';
11
+ export default class extends Instruction {
12
+ title: string;
13
+ type: string;
14
+ group: string;
15
+ description: string;
16
+ fieldset: {
17
+ result: {
18
+ type: string;
19
+ title: string;
20
+ 'x-decorator': string;
21
+ 'x-component': string;
22
+ 'x-component-props': {
23
+ useTypedConstant: boolean;
24
+ };
25
+ required: boolean;
26
+ };
27
+ };
28
+ components: {
29
+ WorkflowVariableInput: typeof WorkflowVariableInput;
30
+ };
31
+ }
@@ -6,6 +6,7 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
+ import React from 'react';
9
10
  export declare const ScheduleModes: {
10
11
  [x: number]: {
11
12
  fieldset: {
@@ -63,12 +64,14 @@ export declare const ScheduleModes: {
63
64
  'x-decorator': string;
64
65
  'x-component': string;
65
66
  'x-component-props': {
66
- showTime: boolean;
67
- placeholder: string;
67
+ nullable: boolean;
68
+ changeOnSelect: boolean;
69
+ render(props: any): React.JSX.Element;
68
70
  };
69
71
  };
70
72
  data?: undefined;
71
73
  };
74
+ validate(config: any): boolean;
72
75
  } | {
73
76
  fieldset: {
74
77
  collection: {
@@ -10,6 +10,7 @@
10
10
  import { SchemaInitializerItemType, useCollectionDataSource } from '@nocobase/client';
11
11
  import { Trigger } from '..';
12
12
  import { TriggerScheduleConfig } from './TriggerScheduleConfig';
13
+ import { WorkflowVariableWrapper } from '../../variable';
13
14
  import { TriggerCollectionRecordSelect } from '../../components/TriggerCollectionRecordSelect';
14
15
  declare function useVariables(config: any, opts: any): any[];
15
16
  export default class extends Trigger {
@@ -37,6 +38,7 @@ export default class extends Trigger {
37
38
  ScheduleConfig: () => import("react").JSX.Element;
38
39
  TriggerScheduleConfig: typeof TriggerScheduleConfig;
39
40
  TriggerCollectionRecordSelect: typeof TriggerCollectionRecordSelect;
41
+ WorkflowVariableWrapper: typeof WorkflowVariableWrapper;
40
42
  };
41
43
  useVariables: typeof useVariables;
42
44
  useInitializers(config: any): SchemaInitializerItemType | null;
@@ -6,7 +6,7 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
- /// <reference types="react" />
9
+ import React from 'react';
10
10
  export type VariableOption = {
11
11
  key?: string;
12
12
  value?: string;
@@ -59,17 +59,16 @@ export declare const systemOptions: {
59
59
  value: string;
60
60
  useOptions(options: UseVariableOptions): any;
61
61
  };
62
+ /**
63
+ * @deprecated
64
+ */
62
65
  export declare const BaseTypeSets: {
63
66
  boolean: Set<string>;
64
67
  number: Set<string>;
65
68
  string: Set<string>;
66
69
  date: Set<string>;
67
70
  };
68
- export declare function useWorkflowVariableOptions(options?: UseVariableOptions): {
69
- [x: number]: any;
70
- key: any;
71
- disabled: boolean;
72
- }[];
71
+ export declare function useWorkflowVariableOptions(options?: UseVariableOptions): any[];
73
72
  export declare function getCollectionFieldOptions(options: any): VariableOption[];
74
73
  export declare function useGetCollectionFields(dataSourceName?: any): (collectionName: any) => import("@nocobase/client").CollectionFieldOptions[];
75
74
  export declare function WorkflowVariableInput({ variableOptions, ...props }: {
@@ -88,3 +87,15 @@ export declare function WorkflowVariableJSON({ variableOptions, ...props }: {
88
87
  [x: string]: any;
89
88
  variableOptions: any;
90
89
  }): JSX.Element;
90
+ /**
91
+ * @experimental
92
+ */
93
+ export declare function WorkflowVariableWrapper(props: any): JSX.Element;
94
+ /**
95
+ * @experimental
96
+ */
97
+ export declare const HideVariableContext: React.Context<boolean>;
98
+ /**
99
+ * @experimental
100
+ */
101
+ export declare function useHideVariable(): boolean;
@@ -11,24 +11,24 @@ module.exports = {
11
11
  "react": "18.2.0",
12
12
  "@formily/core": "2.3.0",
13
13
  "@formily/react": "2.3.0",
14
- "@nocobase/client": "1.5.0-beta.9",
15
- "@nocobase/utils": "1.5.0-beta.9",
14
+ "@nocobase/client": "1.6.0-alpha.10",
15
+ "@nocobase/utils": "1.6.0-alpha.10",
16
16
  "antd": "5.12.8",
17
17
  "@ant-design/icons": "5.2.6",
18
18
  "react-router-dom": "6.21.0",
19
19
  "react-i18next": "11.18.6",
20
20
  "@formily/shared": "2.3.2",
21
21
  "lodash": "4.17.21",
22
- "@nocobase/database": "1.5.0-beta.9",
23
- "@nocobase/server": "1.5.0-beta.9",
24
- "@nocobase/logger": "1.5.0-beta.9",
25
- "@nocobase/actions": "1.5.0-beta.9",
26
- "@nocobase/data-source-manager": "1.5.0-beta.9",
27
- "@nocobase/evaluators": "1.5.0-beta.9",
22
+ "@nocobase/database": "1.6.0-alpha.10",
23
+ "@nocobase/server": "1.6.0-alpha.10",
24
+ "@nocobase/logger": "1.6.0-alpha.10",
25
+ "@nocobase/actions": "1.6.0-alpha.10",
26
+ "@nocobase/data-source-manager": "1.6.0-alpha.10",
27
+ "@nocobase/evaluators": "1.6.0-alpha.10",
28
28
  "@formily/antd-v5": "1.1.9",
29
29
  "@formily/reactive": "2.3.0",
30
30
  "dayjs": "1.11.10",
31
31
  "sequelize": "6.35.2",
32
- "@nocobase/plugin-workflow-test": "1.5.0-beta.9",
33
- "@nocobase/test": "1.5.0-beta.9"
32
+ "@nocobase/plugin-workflow-test": "1.6.0-alpha.10",
33
+ "@nocobase/test": "1.6.0-alpha.10"
34
34
  };
@@ -73,7 +73,7 @@
73
73
  "Preload associations": "预加载关联数据",
74
74
  "Please select the associated fields that need to be accessed in subsequent nodes. With more than two levels of to-many associations may cause performance issue, please use with caution.":
75
75
  "请选中需要在后续节点中被访问的关系字段。超过两层的对多关联可能会导致性能问题,请谨慎使用。",
76
- "Choose a record of the collection to trigger.": "选择数据表中的一行记录来触发。",
76
+ "Choose a record or primary key of a record in the collection to trigger.": "选择数据表中的一行记录或者记录的主键来触发。",
77
77
 
78
78
  "Schedule event": "定时任务",
79
79
  "Triggered according to preset time conditions. Suitable for one-time or periodic tasks, such as sending notifications and cleaning data on a schedule.": "按预设的时间条件定时触发。适用于一次性或周期性的任务,如定时发送通知、清理数据等。",
@@ -227,5 +227,7 @@
227
227
  "Add node": "添加节点",
228
228
  "Move all downstream nodes to": "将所有下游节点移至",
229
229
  "After end of branches": "分支结束后",
230
- "Inside of branch": "分支内"
230
+ "Inside of branch": "分支内",
231
+
232
+ "Workflow todos": "流程待办"
231
233
  }
@@ -1 +1 @@
1
- {"name":"cron-parser","version":"4.4.0","description":"Node.js library for parsing crontab instructions","main":"lib/parser.js","types":"index.d.ts","typesVersions":{"<4.1":{"*":["types/ts3/*"]}},"directories":{"test":"test"},"scripts":{"test:tsd":"tsd","test:unit":"TZ=UTC tap ./test/*.js","test:cover":"TZ=UTC tap --coverage-report=html ./test/*.js","lint":"eslint .","lint:fix":"eslint --fix .","test":"npm run lint && npm run test:unit && npm run test:tsd"},"repository":{"type":"git","url":"https://github.com/harrisiirak/cron-parser.git"},"keywords":["cron","crontab","parser"],"author":"Harri Siirak","contributors":["Nicholas Clawson","Daniel Prentis <daniel@salsitasoft.com>","Renault John Lecoultre","Richard Astbury <richard.astbury@gmail.com>","Meaglin Wasabi <Meaglin.wasabi@gmail.com>","Mike Kusold <hello@mikekusold.com>","Alex Kit <alex.kit@atmajs.com>","Santiago Gimeno <santiago.gimeno@gmail.com>","Daniel <darc.tec@gmail.com>","Christian Steininger <christian.steininger.cs@gmail.com>","Mykola Piskovyi <m.piskovyi@gmail.com>","Brian Vaughn <brian.david.vaughn@gmail.com>","Nicholas Clawson <nickclaw@gmail.com>","Yasuhiroki <yasuhiroki.duck@gmail.com>","Nicholas Clawson <nickclaw@gmail.com>","Brendan Warkentin <faazshift@gmail.com>","Charlie Fish <fishcharlie.code@gmail.com>","Ian Graves <ian+diskimage@iangrav.es>","Andy Thompson <me@andytson.com>","Regev Brody <regevbr@gmail.com>"],"license":"MIT","dependencies":{"luxon":"^1.28.0"},"devDependencies":{"eslint":"^8.2.0","sinon":"^10.0.0","tap":"^16.0.1","tsd":"^0.19.0"},"engines":{"node":">=0.8"},"browser":{"fs":false},"tap":{"check-coverage":false},"tsd":{"directory":"test","compilerOptions":{"lib":["es2017","dom"]}},"_lastModified":"2024-12-15T11:59:31.756Z"}
1
+ {"name":"cron-parser","version":"4.4.0","description":"Node.js library for parsing crontab instructions","main":"lib/parser.js","types":"index.d.ts","typesVersions":{"<4.1":{"*":["types/ts3/*"]}},"directories":{"test":"test"},"scripts":{"test:tsd":"tsd","test:unit":"TZ=UTC tap ./test/*.js","test:cover":"TZ=UTC tap --coverage-report=html ./test/*.js","lint":"eslint .","lint:fix":"eslint --fix .","test":"npm run lint && npm run test:unit && npm run test:tsd"},"repository":{"type":"git","url":"https://github.com/harrisiirak/cron-parser.git"},"keywords":["cron","crontab","parser"],"author":"Harri Siirak","contributors":["Nicholas Clawson","Daniel Prentis <daniel@salsitasoft.com>","Renault John Lecoultre","Richard Astbury <richard.astbury@gmail.com>","Meaglin Wasabi <Meaglin.wasabi@gmail.com>","Mike Kusold <hello@mikekusold.com>","Alex Kit <alex.kit@atmajs.com>","Santiago Gimeno <santiago.gimeno@gmail.com>","Daniel <darc.tec@gmail.com>","Christian Steininger <christian.steininger.cs@gmail.com>","Mykola Piskovyi <m.piskovyi@gmail.com>","Brian Vaughn <brian.david.vaughn@gmail.com>","Nicholas Clawson <nickclaw@gmail.com>","Yasuhiroki <yasuhiroki.duck@gmail.com>","Nicholas Clawson <nickclaw@gmail.com>","Brendan Warkentin <faazshift@gmail.com>","Charlie Fish <fishcharlie.code@gmail.com>","Ian Graves <ian+diskimage@iangrav.es>","Andy Thompson <me@andytson.com>","Regev Brody <regevbr@gmail.com>"],"license":"MIT","dependencies":{"luxon":"^1.28.0"},"devDependencies":{"eslint":"^8.2.0","sinon":"^10.0.0","tap":"^16.0.1","tsd":"^0.19.0"},"engines":{"node":">=0.8"},"browser":{"fs":false},"tap":{"check-coverage":false},"tsd":{"directory":"test","compilerOptions":{"lib":["es2017","dom"]}},"_lastModified":"2025-01-08T06:47:28.926Z"}
@@ -1 +1 @@
1
- {"name":"lru-cache","description":"A cache object that deletes the least-recently-used items.","version":"8.0.5","author":"Isaac Z. Schlueter <i@izs.me>","keywords":["mru","lru","cache"],"sideEffects":false,"scripts":{"build":"npm run prepare","preprepare":"rm -rf dist","prepare":"tsc -p tsconfig.json && tsc -p tsconfig-esm.json","postprepare":"bash fixup.sh","pretest":"npm run prepare","presnap":"npm run prepare","test":"c8 tap","snap":"c8 tap","preversion":"npm test","postversion":"npm publish","prepublishOnly":"git push origin --follow-tags","format":"prettier --write .","typedoc":"typedoc --tsconfig tsconfig-esm.json ./src/*.ts","benchmark-results-typedoc":"bash scripts/benchmark-results-typedoc.sh","prebenchmark":"npm run prepare","benchmark":"make -C benchmark","preprofile":"npm run prepare","profile":"make -C benchmark profile"},"main":"./dist/cjs/index-cjs.js","module":"./dist/mjs/index.js","types":"./dist/mjs/index.d.ts","exports":{"./min":{"import":{"types":"./dist/mjs/index.d.ts","default":"./dist/mjs/index.min.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.min.js"}},".":{"import":{"types":"./dist/mjs/index.d.ts","default":"./dist/mjs/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index-cjs.js"}}},"repository":"git://github.com/isaacs/node-lru-cache.git","devDependencies":{"@size-limit/preset-small-lib":"^7.0.8","@types/node":"^17.0.31","@types/tap":"^15.0.6","benchmark":"^2.1.4","c8":"^7.11.2","clock-mock":"^1.0.6","esbuild":"^0.17.11","eslint-config-prettier":"^8.5.0","marked":"^4.2.12","mkdirp":"^2.1.5","prettier":"^2.6.2","size-limit":"^7.0.8","tap":"^16.3.4","ts-node":"^10.7.0","tslib":"^2.4.0","typedoc":"^0.23.24","typescript":"^4.6.4"},"license":"ISC","files":["dist"],"engines":{"node":">=16.14"},"prettier":{"semi":false,"printWidth":70,"tabWidth":2,"useTabs":false,"singleQuote":true,"jsxSingleQuote":false,"bracketSameLine":true,"arrowParens":"avoid","endOfLine":"lf"},"tap":{"coverage":false,"node-arg":["--expose-gc","--no-warnings","--loader","ts-node/esm"],"ts":false},"size-limit":[{"path":"./dist/mjs/index.js"}],"_lastModified":"2024-12-15T11:59:31.341Z"}
1
+ {"name":"lru-cache","description":"A cache object that deletes the least-recently-used items.","version":"8.0.5","author":"Isaac Z. Schlueter <i@izs.me>","keywords":["mru","lru","cache"],"sideEffects":false,"scripts":{"build":"npm run prepare","preprepare":"rm -rf dist","prepare":"tsc -p tsconfig.json && tsc -p tsconfig-esm.json","postprepare":"bash fixup.sh","pretest":"npm run prepare","presnap":"npm run prepare","test":"c8 tap","snap":"c8 tap","preversion":"npm test","postversion":"npm publish","prepublishOnly":"git push origin --follow-tags","format":"prettier --write .","typedoc":"typedoc --tsconfig tsconfig-esm.json ./src/*.ts","benchmark-results-typedoc":"bash scripts/benchmark-results-typedoc.sh","prebenchmark":"npm run prepare","benchmark":"make -C benchmark","preprofile":"npm run prepare","profile":"make -C benchmark profile"},"main":"./dist/cjs/index-cjs.js","module":"./dist/mjs/index.js","types":"./dist/mjs/index.d.ts","exports":{"./min":{"import":{"types":"./dist/mjs/index.d.ts","default":"./dist/mjs/index.min.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.min.js"}},".":{"import":{"types":"./dist/mjs/index.d.ts","default":"./dist/mjs/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index-cjs.js"}}},"repository":"git://github.com/isaacs/node-lru-cache.git","devDependencies":{"@size-limit/preset-small-lib":"^7.0.8","@types/node":"^17.0.31","@types/tap":"^15.0.6","benchmark":"^2.1.4","c8":"^7.11.2","clock-mock":"^1.0.6","esbuild":"^0.17.11","eslint-config-prettier":"^8.5.0","marked":"^4.2.12","mkdirp":"^2.1.5","prettier":"^2.6.2","size-limit":"^7.0.8","tap":"^16.3.4","ts-node":"^10.7.0","tslib":"^2.4.0","typedoc":"^0.23.24","typescript":"^4.6.4"},"license":"ISC","files":["dist"],"engines":{"node":">=16.14"},"prettier":{"semi":false,"printWidth":70,"tabWidth":2,"useTabs":false,"singleQuote":true,"jsxSingleQuote":false,"bracketSameLine":true,"arrowParens":"avoid","endOfLine":"lf"},"tap":{"coverage":false,"node-arg":["--expose-gc","--no-warnings","--loader","ts-node/esm"],"ts":false},"size-limit":[{"path":"./dist/mjs/index.js"}],"_lastModified":"2025-01-08T06:47:28.536Z"}
@@ -15,13 +15,15 @@ import { CustomFunction } from './functions';
15
15
  import Trigger from './triggers';
16
16
  import { InstructionInterface } from './instructions';
17
17
  import type { ExecutionModel, WorkflowModel } from './types';
18
- import { Context } from '@nocobase/actions';
19
18
  type ID = number | string;
20
19
  export type EventOptions = {
21
20
  eventKey?: string;
22
21
  context?: any;
23
22
  deferred?: boolean;
24
23
  manually?: boolean;
24
+ force?: boolean;
25
+ stack?: Array<ID>;
26
+ onTriggerFail?: Function;
25
27
  [key: string]: any;
26
28
  } & Transactionable;
27
29
  export default class PluginWorkflowServer extends Plugin {
@@ -72,11 +74,12 @@ export default class PluginWorkflowServer extends Plugin {
72
74
  */
73
75
  start(execution: ExecutionModel): void;
74
76
  createProcessor(execution: ExecutionModel, options?: {}): Processor;
77
+ private validateEvent;
75
78
  private createExecution;
76
79
  private prepare;
77
80
  private dispatch;
78
81
  private process;
79
- execute(workflow: WorkflowModel, context: Context, options?: EventOptions): Promise<void | Processor>;
82
+ execute(workflow: WorkflowModel, values: any, options?: EventOptions): Promise<void | Processor>;
80
83
  /**
81
84
  * @experimental
82
85
  * @param {string} dataSourceName
@@ -268,6 +268,10 @@ class PluginWorkflowServer extends import_server.Plugin {
268
268
  this.checker = setInterval(() => {
269
269
  this.dispatch();
270
270
  }, 3e5);
271
+ this.app.on("workflow:dispatch", () => {
272
+ this.app.logger.info("workflow:dispatch");
273
+ this.dispatch();
274
+ });
271
275
  this.dispatch();
272
276
  });
273
277
  this.app.on("beforeStop", async () => {
@@ -323,7 +327,7 @@ class PluginWorkflowServer extends import_server.Plugin {
323
327
  logger.debug(`ignored event data:`, context);
324
328
  return;
325
329
  }
326
- if (!options.manually && !workflow.enabled) {
330
+ if (!options.force && !options.manually && !workflow.enabled) {
327
331
  logger.warn(`workflow ${workflow.id} is not enabled, event will be ignored`);
328
332
  return;
329
333
  }
@@ -383,17 +387,42 @@ class PluginWorkflowServer extends import_server.Plugin {
383
387
  createProcessor(execution, options = {}) {
384
388
  return new import_Processor.default(execution, { ...options, plugin: this });
385
389
  }
390
+ async validateEvent(workflow, context, options) {
391
+ const trigger = this.triggers.get(workflow.type);
392
+ const triggerValid = await trigger.validateEvent(workflow, context, options);
393
+ if (!triggerValid) {
394
+ return false;
395
+ }
396
+ const { stack } = options;
397
+ let valid = true;
398
+ if ((stack == null ? void 0 : stack.length) > 0) {
399
+ const existed = await workflow.countExecutions({
400
+ where: {
401
+ id: stack
402
+ },
403
+ transaction: options.transaction
404
+ });
405
+ if (existed) {
406
+ this.getLogger(workflow.id).warn(
407
+ `workflow ${workflow.id} has already been triggered in stacks executions (${stack}), and newly triggering will be skipped.`
408
+ );
409
+ valid = false;
410
+ }
411
+ }
412
+ return valid;
413
+ }
386
414
  async createExecution(workflow, context, options) {
415
+ var _a;
387
416
  const { deferred } = options;
388
417
  const transaction = await this.useDataSourceTransaction("main", options.transaction, true);
389
418
  const sameTransaction = options.transaction === transaction;
390
- const trigger = this.triggers.get(workflow.type);
391
- const valid = await trigger.validateEvent(workflow, context, { ...options, transaction });
419
+ const valid = await this.validateEvent(workflow, context, { ...options, transaction });
392
420
  if (!valid) {
393
421
  if (!sameTransaction) {
394
422
  await transaction.commit();
395
423
  }
396
- return null;
424
+ (_a = options.onTriggerFail) == null ? void 0 : _a.call(options, workflow, context, options);
425
+ return Promise.reject(new Error("event is not valid"));
397
426
  }
398
427
  let execution;
399
428
  try {
@@ -402,6 +431,7 @@ class PluginWorkflowServer extends import_server.Plugin {
402
431
  context,
403
432
  key: workflow.key,
404
433
  eventKey: options.eventKey ?? (0, import_crypto.randomUUID)(),
434
+ stack: options.stack,
405
435
  status: deferred ? import_constants.EXECUTION_STATUS.STARTED : import_constants.EXECUTION_STATUS.QUEUEING
406
436
  },
407
437
  { transaction }
@@ -451,8 +481,8 @@ class PluginWorkflowServer extends import_server.Plugin {
451
481
  if ((execution == null ? void 0 : execution.status) === import_constants.EXECUTION_STATUS.QUEUEING && !this.executing && !this.pending.length) {
452
482
  this.pending.push([execution]);
453
483
  }
454
- } catch (err) {
455
- logger.error(`failed to create execution: ${err.message}`, err);
484
+ } catch (error) {
485
+ logger.error(`failed to create execution:`, { error });
456
486
  }
457
487
  if (this.events.length) {
458
488
  await this.prepare();
@@ -498,8 +528,11 @@ class PluginWorkflowServer extends import_server.Plugin {
498
528
  if (next) {
499
529
  await this.process(...next);
500
530
  }
531
+ } catch (err) {
532
+ console.error(err);
501
533
  } finally {
502
534
  this.executing = null;
535
+ this.getLogger("dispatcher").info(`execution dispatched finished`);
503
536
  if (next) {
504
537
  this.dispatch();
505
538
  }
@@ -526,7 +559,7 @@ class PluginWorkflowServer extends import_server.Plugin {
526
559
  }
527
560
  return processor;
528
561
  }
529
- async execute(workflow, context, options = {}) {
562
+ async execute(workflow, values, options = {}) {
530
563
  const trigger = this.triggers.get(workflow.type);
531
564
  if (!trigger) {
532
565
  throw new Error(`trigger type "${workflow.type}" of workflow ${workflow.id} is not registered`);
@@ -534,7 +567,7 @@ class PluginWorkflowServer extends import_server.Plugin {
534
567
  if (!trigger.execute) {
535
568
  throw new Error(`"execute" method of trigger ${workflow.type} is not implemented`);
536
569
  }
537
- return trigger.execute(workflow, context, options);
570
+ return trigger.execute(workflow, values, options);
538
571
  }
539
572
  /**
540
573
  * @experimental
@@ -109,6 +109,7 @@ export default class Processor {
109
109
  };
110
110
  $system: {};
111
111
  $scopes: {};
112
+ $env: {};
112
113
  };
113
114
  /**
114
115
  * @experimental
@@ -369,7 +369,8 @@ class Processor {
369
369
  $context: this.execution.context,
370
370
  $jobsMapByNodeKey: this.jobsMapByNodeKey,
371
371
  $system: systemFns,
372
- $scopes
372
+ $scopes,
373
+ $env: this.options.plugin.app.environment.getVariables()
373
374
  };
374
375
  }
375
376
  /**
@@ -121,7 +121,10 @@ async function trigger(context, next) {
121
121
  }
122
122
  async function execute(context, next) {
123
123
  const plugin = context.app.pm.get(import_Plugin.default);
124
- const { filterByTk, autoRevision } = context.action.params;
124
+ const { filterByTk, values, autoRevision } = context.action.params;
125
+ if (!values) {
126
+ return context.throw(400, "values is required");
127
+ }
125
128
  if (!filterByTk) {
126
129
  return context.throw(400, "filterByTk is required");
127
130
  }
@@ -137,7 +140,7 @@ async function execute(context, next) {
137
140
  const { executed } = workflow;
138
141
  let processor;
139
142
  try {
140
- processor = await plugin.execute(workflow, context, { manually: true });
143
+ processor = await plugin.execute(workflow, values, { manually: true });
141
144
  if (!processor) {
142
145
  return context.throw(400, "workflow not triggered");
143
146
  }
@@ -33,6 +33,7 @@ var executions_default = {
33
33
  dumpRules: {
34
34
  group: "log"
35
35
  },
36
+ migrationRules: ["schema-only", "skip"],
36
37
  name: "executions",
37
38
  shared: true,
38
39
  fields: [
@@ -61,6 +62,14 @@ var executions_default = {
61
62
  {
62
63
  type: "integer",
63
64
  name: "status"
65
+ },
66
+ {
67
+ type: "json",
68
+ name: "stack"
69
+ },
70
+ {
71
+ type: "json",
72
+ name: "output"
64
73
  }
65
74
  ]
66
75
  };
@@ -31,6 +31,7 @@ __export(flow_nodes_exports, {
31
31
  module.exports = __toCommonJS(flow_nodes_exports);
32
32
  var flow_nodes_default = {
33
33
  dumpRules: "required",
34
+ migrationRules: ["overwrite", "skip"],
34
35
  name: "flow_nodes",
35
36
  shared: true,
36
37
  fields: [
@@ -33,6 +33,7 @@ var jobs_default = {
33
33
  dumpRules: {
34
34
  group: "log"
35
35
  },
36
+ migrationRules: ["schema-only", "skip"],
36
37
  name: "jobs",
37
38
  shared: true,
38
39
  fields: [
@@ -32,6 +32,7 @@ module.exports = __toCommonJS(workflows_exports);
32
32
  function workflows_default() {
33
33
  return {
34
34
  dumpRules: "required",
35
+ migrationRules: ["overwrite", "skip"],
35
36
  name: "workflows",
36
37
  shared: true,
37
38
  repository: "WorkflowRepository",
@@ -44,7 +44,7 @@ class CreateInstruction extends import__.Instruction {
44
44
  const created = await repository.create({
45
45
  ...options,
46
46
  context: {
47
- stack: Array.from(new Set((processor.execution.context.stack ?? []).concat(processor.execution.id)))
47
+ stack: Array.from(new Set((processor.execution.stack ?? []).concat(processor.execution.id)))
48
48
  },
49
49
  transaction
50
50
  });
@@ -42,7 +42,7 @@ class DestroyInstruction extends import__.Instruction {
42
42
  const result = await repository.destroy({
43
43
  ...options,
44
44
  context: {
45
- stack: Array.from(new Set((processor.execution.context.stack ?? []).concat(processor.execution.id)))
45
+ stack: Array.from(new Set((processor.execution.stack ?? []).concat(processor.execution.id)))
46
46
  },
47
47
  transaction: this.workflow.useDataSourceTransaction(dataSourceName, processor.transaction)
48
48
  });
@@ -42,7 +42,7 @@ class UpdateInstruction extends import__.Instruction {
42
42
  const result = await repository.update({
43
43
  ...options,
44
44
  context: {
45
- stack: Array.from(new Set((processor.execution.context.stack ?? []).concat(processor.execution.id)))
45
+ stack: Array.from(new Set((processor.execution.stack ?? []).concat(processor.execution.id)))
46
46
  },
47
47
  transaction: this.workflow.useDataSourceTransaction(dataSourceName, processor.transaction)
48
48
  });
@@ -6,11 +6,10 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
- import { Model, Transactionable } from '@nocobase/database';
9
+ import { Model } from '@nocobase/database';
10
10
  import Trigger from '.';
11
11
  import type { WorkflowModel } from '../types';
12
12
  import type { EventOptions } from '../Plugin';
13
- import { Context } from '@nocobase/actions';
14
13
  export interface CollectionChangeTriggerConfig {
15
14
  collection: string;
16
15
  mode: number;
@@ -19,12 +18,10 @@ export interface CollectionChangeTriggerConfig {
19
18
  export default class CollectionTrigger extends Trigger {
20
19
  events: Map<any, any>;
21
20
  private static handler;
22
- prepare(workflow: WorkflowModel, data: Model | Record<string, any>, options: any): Promise<{
21
+ prepare(workflow: WorkflowModel, data: Model | Record<string, any> | string | number, options: any): Promise<{
23
22
  data: any;
24
- stack: any;
25
23
  }>;
26
24
  on(workflow: WorkflowModel): void;
27
25
  off(workflow: WorkflowModel): void;
28
- validateEvent(workflow: WorkflowModel, context: any, options: Transactionable): Promise<boolean>;
29
- execute(workflow: WorkflowModel, context: Context, options: EventOptions): Promise<void | import("..").Processor>;
26
+ execute(workflow: WorkflowModel, values: any, options: EventOptions): Promise<void | import("..").Processor>;
30
27
  }
@@ -74,17 +74,19 @@ class CollectionTrigger extends import__.default {
74
74
  if (!ctx) {
75
75
  return;
76
76
  }
77
+ const { stack } = options.context ?? {};
77
78
  if (workflow.sync) {
78
79
  await this.workflow.trigger(workflow, ctx, {
79
- transaction
80
+ transaction,
81
+ stack
80
82
  });
81
83
  } else {
82
84
  if (transaction) {
83
85
  transaction.afterCommit(() => {
84
- this.workflow.trigger(workflow, ctx);
86
+ this.workflow.trigger(workflow, ctx, { stack });
85
87
  });
86
88
  } else {
87
- this.workflow.trigger(workflow, ctx);
89
+ this.workflow.trigger(workflow, ctx, { stack });
88
90
  }
89
91
  }
90
92
  }
@@ -95,13 +97,24 @@ class CollectionTrigger extends import__.default {
95
97
  const collection = collectionManager.getCollection(collectionName);
96
98
  const { transaction, context } = options;
97
99
  const { repository, filterTargetKey } = collection;
98
- if (data instanceof import_database.Model && changed && changed.length && changed.filter((name) => {
100
+ let target = data;
101
+ let filterByTk;
102
+ let loadNeeded = false;
103
+ if (target && typeof target === "object") {
104
+ filterByTk = Array.isArray(filterTargetKey) ? (0, import_lodash.pick)(
105
+ target,
106
+ filterTargetKey.sort((a, b) => a.localeCompare(b))
107
+ ) : target[filterTargetKey];
108
+ } else {
109
+ filterByTk = target;
110
+ loadNeeded = true;
111
+ }
112
+ if (target instanceof import_database.Model && changed && changed.length && changed.filter((name) => {
99
113
  const field = collection.getField(name);
100
114
  return field && !["linkTo", "hasOne", "hasMany", "belongsToMany"].includes(field.options.type);
101
- }).every((name) => !data.changedWithAssociations(getFieldRawName(collection, name)))) {
115
+ }).every((name) => !target.changedWithAssociations(getFieldRawName(collection, name)))) {
102
116
  return null;
103
117
  }
104
- const filterByTk = Array.isArray(filterTargetKey) ? (0, import_lodash.pick)(data, filterTargetKey) : { [filterTargetKey]: data[filterTargetKey] };
105
118
  if ((0, import_utils.isValidFilter)(condition) && !(mode & MODE_BITMAP.DESTROY)) {
106
119
  const count = await repository.count({
107
120
  filterByTk,
@@ -113,22 +126,20 @@ class CollectionTrigger extends import__.default {
113
126
  return null;
114
127
  }
115
128
  }
116
- let result = data;
117
- if ((appends == null ? void 0 : appends.length) && !(mode & MODE_BITMAP.DESTROY)) {
129
+ if (loadNeeded || (appends == null ? void 0 : appends.length) && !(mode & MODE_BITMAP.DESTROY)) {
118
130
  const includeFields = appends.reduce((set, field) => {
119
131
  set.add(field.split(".")[0]);
120
132
  set.add(field);
121
133
  return set;
122
134
  }, /* @__PURE__ */ new Set());
123
- result = await repository.findOne({
135
+ target = await repository.findOne({
124
136
  filterByTk,
125
137
  appends: Array.from(includeFields),
126
138
  transaction
127
139
  });
128
140
  }
129
141
  return {
130
- data: (0, import_utils2.toJSON)(result),
131
- stack: context == null ? void 0 : context.stack
142
+ data: (0, import_utils2.toJSON)(target)
132
143
  };
133
144
  }
134
145
  on(workflow) {
@@ -182,26 +193,27 @@ class CollectionTrigger extends import__.default {
182
193
  }
183
194
  }
184
195
  }
185
- async validateEvent(workflow, context, options) {
186
- if (context.stack) {
187
- const existed = await workflow.countExecutions({
188
- where: {
189
- id: context.stack
190
- },
191
- transaction: options.transaction
192
- });
193
- if (existed) {
194
- this.workflow.getLogger(workflow.id).warn(
195
- `workflow ${workflow.id} has already been triggered in stack executions (${context.stack}), and newly triggering will be skipped.`
196
- );
197
- return false;
198
- }
199
- }
200
- return true;
201
- }
202
- async execute(workflow, context, options) {
203
- var _a;
204
- const ctx = await this.prepare(workflow, (_a = context.action.params.values) == null ? void 0 : _a.data, options);
196
+ // async validateEvent(workflow: WorkflowModel, context: any, options: Transactionable): Promise<boolean> {
197
+ // if (context.stack) {
198
+ // const existed = await workflow.countExecutions({
199
+ // where: {
200
+ // id: context.stack,
201
+ // },
202
+ // transaction: options.transaction,
203
+ // });
204
+ // if (existed) {
205
+ // this.workflow
206
+ // .getLogger(workflow.id)
207
+ // .warn(
208
+ // `workflow ${workflow.id} has already been triggered in stack executions (${context.stack}), and newly triggering will be skipped.`,
209
+ // );
210
+ // return false;
211
+ // }
212
+ // }
213
+ // return true;
214
+ // }
215
+ async execute(workflow, values, options) {
216
+ const ctx = await this.prepare(workflow, values == null ? void 0 : values.data, options);
205
217
  const [dataSourceName] = (0, import_data_source_manager.parseCollectionName)(workflow.config.collection);
206
218
  const { transaction } = options;
207
219
  return this.workflow.trigger(workflow, ctx, {
@@ -36,4 +36,5 @@ export default class DateFieldScheduleTrigger {
36
36
  trigger(workflow: WorkflowModel, record: any, nextTime: any, { transaction }?: Transactionable): Promise<void>;
37
37
  on(workflow: WorkflowModel): void;
38
38
  off(workflow: WorkflowModel): void;
39
+ execute(workflow: any, values: any, options: any): Promise<void | import("../..").Processor>;
39
40
  }