@tachybase/module-workflow 0.23.40 → 0.23.47

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 (40) hide show
  1. package/dist/client/components/ExecutionRetryAction.d.ts +3 -0
  2. package/dist/client/components/ExecutionTime.d.ts +2 -1
  3. package/dist/client/components/index.d.ts +2 -1
  4. package/dist/client/features/dynamic-calculation/DynamicExpression.d.ts +2 -2
  5. package/dist/client/features/trigger-instruction/TriggerInstruction.d.ts +4 -2
  6. package/dist/client/index.d.ts +1 -2
  7. package/dist/client/index.js +58 -58
  8. package/dist/client/schemas/executions.d.ts +16 -6
  9. package/dist/externalVersion.js +15 -15
  10. package/dist/locale/zh-CN.json +8 -0
  11. package/dist/node_modules/@babel/core/package.json +1 -1
  12. package/dist/node_modules/cron-parser/package.json +1 -1
  13. package/dist/node_modules/form-data/package.json +1 -1
  14. package/dist/node_modules/jsonata/package.json +1 -1
  15. package/dist/node_modules/lru-cache/package.json +1 -1
  16. package/dist/node_modules/mime-types/package.json +1 -1
  17. package/dist/node_modules/qrcode/package.json +1 -1
  18. package/dist/server/Plugin.js +80 -76
  19. package/dist/server/Processor.js +15 -17
  20. package/dist/server/actions/executions.d.ts +2 -1
  21. package/dist/server/actions/executions.js +48 -2
  22. package/dist/server/actions/workflows.d.ts +1 -0
  23. package/dist/server/actions/workflows.js +66 -0
  24. package/dist/server/collections/executions.js +4 -0
  25. package/dist/server/features/_deprecated-json-parse/JSONParse.instruction.js +4 -1
  26. package/dist/server/features/delay/DelayInstruction.js +36 -36
  27. package/dist/server/features/interception/RequestInterceptionTrigger.js +81 -80
  28. package/dist/server/features/manual/ManualInstruction.js +1 -1
  29. package/dist/server/features/notice/plugin.js +0 -1
  30. package/dist/server/features/omni-trigger/CustomActionTrigger.js +122 -121
  31. package/dist/server/migrations/20241118104303-add-initAt.js +6 -3
  32. package/dist/server/migrations/20241206122842-add-createdBy.js +6 -3
  33. package/dist/server/migrations/20241220001154-bigInt.js +6 -3
  34. package/dist/server/triggers/CollectionTrigger.js +4 -1
  35. package/dist/server/triggers/ScheduleTrigger/DateFieldScheduleTrigger.js +5 -5
  36. package/dist/server/triggers/ScheduleTrigger/StaticScheduleTrigger.js +1 -1
  37. package/dist/server/triggers/ScheduleTrigger/index.js +2 -2
  38. package/dist/server/triggers/index.js +0 -1
  39. package/package.json +17 -17
  40. /package/dist/client/{ExecutionLink.d.ts → components/ExecutionLink.d.ts} +0 -0
@@ -30,6 +30,7 @@ __export(workflows_exports, {
30
30
  destroy: () => destroy,
31
31
  dump: () => dump,
32
32
  load: () => load,
33
+ moveWorkflow: () => moveWorkflow,
33
34
  retry: () => retry,
34
35
  revision: () => revision,
35
36
  sync: () => sync,
@@ -344,11 +345,76 @@ async function trigger(ctx, next) {
344
345
  await next();
345
346
  }
346
347
  }
348
+ async function moveWorkflow(ctx, next) {
349
+ const { id, targetKey } = ctx.action.params;
350
+ if (!id || !targetKey) {
351
+ ctx.throw(400, "params error");
352
+ }
353
+ const workflowRepo = ctx.db.getRepository("workflows");
354
+ const targetWorkflow = await workflowRepo.findOne({
355
+ filter: {
356
+ key: targetKey,
357
+ enabled: true
358
+ }
359
+ });
360
+ if (!targetWorkflow) {
361
+ ctx.throw(400, "target workflow not found");
362
+ }
363
+ const sourceWorkflow = await workflowRepo.findOne({
364
+ filter: {
365
+ id
366
+ }
367
+ });
368
+ if (!sourceWorkflow) {
369
+ ctx.throw(400, "source workflow not found");
370
+ }
371
+ if (sourceWorkflow.key === targetKey) {
372
+ ctx.throw(400, "same workflow");
373
+ }
374
+ if (sourceWorkflow.current) {
375
+ ctx.throw(400, "cannot move current workflow");
376
+ }
377
+ if (sourceWorkflow.type !== targetWorkflow.type) {
378
+ ctx.throw(400, "the type is different");
379
+ }
380
+ const { allExecuted } = targetWorkflow;
381
+ const transaction = await ctx.db.sequelize.transaction();
382
+ await workflowRepo.update({
383
+ values: { key: targetKey, current: null, allExecuted },
384
+ filter: { id },
385
+ hooks: false,
386
+ // 不触发钩子
387
+ transaction
388
+ });
389
+ const executionRepo = ctx.db.getRepository("executions");
390
+ await executionRepo.update({
391
+ values: { key: targetKey },
392
+ filter: { workflow: { id } },
393
+ silent: true,
394
+ // 不修改updatedAt等数据
395
+ hooks: false,
396
+ // 不触发钩子
397
+ transaction
398
+ });
399
+ const repo = ctx.db.getRepository("approvals");
400
+ if (repo) {
401
+ await repo.update({
402
+ values: { workflowKey: targetKey },
403
+ filter: { workflowId: id },
404
+ hooks: false,
405
+ // 不触发钩子
406
+ transaction
407
+ });
408
+ }
409
+ await transaction.commit();
410
+ ctx.body = {};
411
+ }
347
412
  // Annotate the CommonJS export names for ESM import in node:
348
413
  0 && (module.exports = {
349
414
  destroy,
350
415
  dump,
351
416
  load,
417
+ moveWorkflow,
352
418
  retry,
353
419
  revision,
354
420
  sync,
@@ -52,6 +52,10 @@ var executions_default = {
52
52
  type: "bigInt",
53
53
  name: "parentNode"
54
54
  },
55
+ {
56
+ type: "bigInt",
57
+ name: "executionCost"
58
+ },
55
59
  {
56
60
  type: "belongsTo",
57
61
  name: "parent",
@@ -34,7 +34,10 @@ var import_jsonata = __toESM(require("jsonata"));
34
34
  var import_lodash = __toESM(require("lodash"));
35
35
  var import__ = require("../..");
36
36
  class JSONParseInstruction extends import__.Instruction {
37
- engine = (expression, scope) => (0, import_jsonata.default)(expression).evaluate(scope);
37
+ constructor() {
38
+ super(...arguments);
39
+ this.engine = (expression, scope) => (0, import_jsonata.default)(expression).evaluate(scope);
40
+ }
38
41
  async run(node, input, processor) {
39
42
  const { source = "", expression = "", model } = node.config;
40
43
  const data = processor.getParsedValue(source, node.id);
@@ -25,45 +25,45 @@ class DelayInstruction_default extends import__.Instruction {
25
25
  constructor(workflow) {
26
26
  super(workflow);
27
27
  this.workflow = workflow;
28
+ this.timers = /* @__PURE__ */ new Map();
29
+ this.load = async () => {
30
+ const { model } = this.workflow.app.db.getCollection("jobs");
31
+ const jobs = await model.findAll({
32
+ where: {
33
+ status: import__.JOB_STATUS.PENDING
34
+ },
35
+ include: [
36
+ {
37
+ association: "execution",
38
+ attributes: [],
39
+ where: {
40
+ status: import__.EXECUTION_STATUS.STARTED
41
+ },
42
+ required: true
43
+ },
44
+ {
45
+ association: "node",
46
+ attributes: ["config"],
47
+ where: {
48
+ type: "delay"
49
+ },
50
+ required: true
51
+ }
52
+ ]
53
+ });
54
+ jobs.forEach((job) => {
55
+ this.schedule(job);
56
+ });
57
+ };
58
+ this.unload = () => {
59
+ for (const timer of this.timers.values()) {
60
+ clearTimeout(timer);
61
+ }
62
+ this.timers = /* @__PURE__ */ new Map();
63
+ };
28
64
  workflow.app.on("afterStart", this.load);
29
65
  workflow.app.on("beforeStop", this.unload);
30
66
  }
31
- timers = /* @__PURE__ */ new Map();
32
- load = async () => {
33
- const { model } = this.workflow.app.db.getCollection("jobs");
34
- const jobs = await model.findAll({
35
- where: {
36
- status: import__.JOB_STATUS.PENDING
37
- },
38
- include: [
39
- {
40
- association: "execution",
41
- attributes: [],
42
- where: {
43
- status: import__.EXECUTION_STATUS.STARTED
44
- },
45
- required: true
46
- },
47
- {
48
- association: "node",
49
- attributes: ["config"],
50
- where: {
51
- type: "delay"
52
- },
53
- required: true
54
- }
55
- ]
56
- });
57
- jobs.forEach((job) => {
58
- this.schedule(job);
59
- });
60
- };
61
- unload = () => {
62
- for (const timer of this.timers.values()) {
63
- clearTimeout(timer);
64
- }
65
- this.timers = /* @__PURE__ */ new Map();
66
- };
67
67
  schedule(job) {
68
68
  const now = /* @__PURE__ */ new Date();
69
69
  const createdAt = Date.parse(job.createdAt);
@@ -35,95 +35,94 @@ var import_module_error_handler = __toESM(require("@tachybase/module-error-handl
35
35
  var import_constants = require("../../constants");
36
36
  var import_triggers = __toESM(require("../../triggers"));
37
37
  class RequestInterceptionError extends Error {
38
- status = 400;
39
- messages = [];
40
38
  constructor(message) {
41
39
  super(message);
40
+ this.status = 400;
41
+ this.messages = [];
42
42
  this.name = "RequestInterceptionError";
43
43
  }
44
44
  }
45
- class RequestInterceptionTrigger extends import_triggers.default {
46
- static TYPE = "request-interception";
47
- sync = true;
48
- middleware = async (context, next) => {
49
- const {
50
- resourceName,
51
- actionName,
52
- params: { filterByTk, filter, values, triggerWorkflows = "" }
53
- } = context.action;
54
- const dataSourceHeader = context.get("x-data-source");
55
- const jointCollectionName = (0, import_data_source.joinCollectionName)(dataSourceHeader, resourceName);
56
- const triggerWorkflowsMap = /* @__PURE__ */ new Map();
57
- const triggerWorkflowsArray = [];
58
- for (const trigger of triggerWorkflows.split(",")) {
59
- const [key, path] = trigger.split("!");
60
- triggerWorkflowsMap.set(key, path);
61
- triggerWorkflowsArray.push(key);
62
- }
63
- const workflows = Array.from(this.workflow.enabledCache.values()).filter(
64
- (item) => item.type === RequestInterceptionTrigger.TYPE && item.config.collection === jointCollectionName
65
- );
66
- const globalWorkflows = workflows.filter((item) => {
67
- var _a;
68
- return item.config.global && ((_a = item.config.actions) == null ? void 0 : _a.includes(actionName));
69
- }).sort((a, b) => a.id - b.id);
70
- const localWorkflows = workflows.filter((item) => !item.config.global).sort((a, b) => {
71
- const aIndex = triggerWorkflowsArray.indexOf(a.key);
72
- const bIndex = triggerWorkflowsArray.indexOf(b.key);
73
- if (aIndex === -1 && bIndex === -1) {
74
- return a.id - b.id;
75
- }
76
- if (aIndex === -1) {
77
- return 1;
78
- }
79
- if (bIndex === -1) {
80
- return -1;
81
- }
82
- return aIndex - bIndex;
83
- });
84
- for (const workflow of localWorkflows.concat(globalWorkflows)) {
85
- if (!workflow.config.global && !triggerWorkflowsMap.has(workflow.key)) {
86
- continue;
45
+ const _RequestInterceptionTrigger = class _RequestInterceptionTrigger extends import_triggers.default {
46
+ constructor(workflow) {
47
+ super(workflow);
48
+ this.sync = true;
49
+ this.middleware = async (context, next) => {
50
+ const {
51
+ resourceName,
52
+ actionName,
53
+ params: { filterByTk, filter, values, triggerWorkflows = "" }
54
+ } = context.action;
55
+ const dataSourceHeader = context.get("x-data-source");
56
+ const jointCollectionName = (0, import_data_source.joinCollectionName)(dataSourceHeader, resourceName);
57
+ const triggerWorkflowsMap = /* @__PURE__ */ new Map();
58
+ const triggerWorkflowsArray = [];
59
+ for (const trigger of triggerWorkflows.split(",")) {
60
+ const [key, path] = trigger.split("!");
61
+ triggerWorkflowsMap.set(key, path);
62
+ triggerWorkflowsArray.push(key);
87
63
  }
88
- const processor = await this.workflow.trigger(
89
- workflow,
90
- {
91
- user: context.state.currentUser,
92
- roleName: context.state.currentRole,
93
- params: {
94
- filterByTk,
95
- filter,
96
- values
97
- }
98
- },
99
- { httpContext: context }
64
+ const workflows = Array.from(this.workflow.enabledCache.values()).filter(
65
+ (item) => item.type === _RequestInterceptionTrigger.TYPE && item.config.collection === jointCollectionName
100
66
  );
101
- if (!processor) {
102
- return context.throw(500);
103
- }
104
- const { lastSavedJob, nodesMap } = processor;
105
- const lastNode = nodesMap.get(lastSavedJob == null ? void 0 : lastSavedJob.nodeId);
106
- if (processor.execution.status === import_constants.EXECUTION_STATUS.RESOLVED) {
107
- if ((lastNode == null ? void 0 : lastNode.type) === "end") {
108
- return;
67
+ const globalWorkflows = workflows.filter((item) => {
68
+ var _a;
69
+ return item.config.global && ((_a = item.config.actions) == null ? void 0 : _a.includes(actionName));
70
+ }).sort((a, b) => a.id - b.id);
71
+ const localWorkflows = workflows.filter((item) => !item.config.global).sort((a, b) => {
72
+ const aIndex = triggerWorkflowsArray.indexOf(a.key);
73
+ const bIndex = triggerWorkflowsArray.indexOf(b.key);
74
+ if (aIndex === -1 && bIndex === -1) {
75
+ return a.id - b.id;
109
76
  }
110
- continue;
111
- }
112
- if (processor.execution.status < import_constants.EXECUTION_STATUS.STARTED) {
113
- if ((lastNode == null ? void 0 : lastNode.type) !== "end") {
114
- return context.throw(500, "Workflow on your action failed, please contact the administrator");
77
+ if (aIndex === -1) {
78
+ return 1;
79
+ }
80
+ if (bIndex === -1) {
81
+ return -1;
115
82
  }
116
- const err = new RequestInterceptionError("Request is intercepted by workflow");
117
- err.status = 400;
118
- err.messages = context.state.messages;
119
- return context.throw(err.status, err);
83
+ return aIndex - bIndex;
84
+ });
85
+ for (const workflow of localWorkflows.concat(globalWorkflows)) {
86
+ if (!workflow.config.global && !triggerWorkflowsMap.has(workflow.key)) {
87
+ continue;
88
+ }
89
+ const processor = await this.workflow.trigger(
90
+ workflow,
91
+ {
92
+ user: context.state.currentUser,
93
+ roleName: context.state.currentRole,
94
+ params: {
95
+ filterByTk,
96
+ filter,
97
+ values
98
+ }
99
+ },
100
+ { httpContext: context }
101
+ );
102
+ if (!processor) {
103
+ return context.throw(500);
104
+ }
105
+ const { lastSavedJob, nodesMap } = processor;
106
+ const lastNode = nodesMap.get(lastSavedJob == null ? void 0 : lastSavedJob.nodeId);
107
+ if (processor.execution.status === import_constants.EXECUTION_STATUS.RESOLVED) {
108
+ if ((lastNode == null ? void 0 : lastNode.type) === "end") {
109
+ return;
110
+ }
111
+ continue;
112
+ }
113
+ if (processor.execution.status < import_constants.EXECUTION_STATUS.STARTED) {
114
+ if ((lastNode == null ? void 0 : lastNode.type) !== "end") {
115
+ return context.throw(500, "Workflow on your action failed, please contact the administrator");
116
+ }
117
+ const err = new RequestInterceptionError("Request is intercepted by workflow");
118
+ err.status = 400;
119
+ err.messages = context.state.messages;
120
+ return context.throw(err.status, err);
121
+ }
122
+ return context.throw(500, "Workflow on your action hangs, please contact the administrator");
120
123
  }
121
- return context.throw(500, "Workflow on your action hangs, please contact the administrator");
122
- }
123
- await next();
124
- };
125
- constructor(workflow) {
126
- super(workflow);
124
+ await next();
125
+ };
127
126
  workflow.app.use(this.middleware, { tag: "workflowFilter", after: "dataSource" });
128
127
  workflow.app.pm.get(import_module_error_handler.default).errorHandler.register(
129
128
  (err) => err instanceof RequestInterceptionError,
@@ -139,7 +138,9 @@ class RequestInterceptionTrigger extends import_triggers.default {
139
138
  }
140
139
  off() {
141
140
  }
142
- }
141
+ };
142
+ _RequestInterceptionTrigger.TYPE = "request-interception";
143
+ let RequestInterceptionTrigger = _RequestInterceptionTrigger;
143
144
  // Annotate the CommonJS export names for ESM import in node:
144
145
  0 && (module.exports = {
145
146
  RequestInterceptionTrigger
@@ -95,9 +95,9 @@ class ManualInstruction_default extends import__.Instruction {
95
95
  constructor(workflow) {
96
96
  super(workflow);
97
97
  this.workflow = workflow;
98
+ this.formTypes = new import_utils.Registry();
98
99
  (0, import_forms.default)(this);
99
100
  }
100
- formTypes = new import_utils.Registry();
101
101
  async run(node, prevJob, processor) {
102
102
  const { mode, ...config } = node.config;
103
103
  const assignees = [...new Set(processor.getParsedValue(config.assignees, node.id).flat().filter(Boolean))];
@@ -39,7 +39,6 @@ var import_actions = require("./actions");
39
39
  var import_workflowNotice = require("./collections/workflowNotice");
40
40
  var import_NoticeInstruction = __toESM(require("./NoticeInstruction"));
41
41
  class PluginWorkflowNoticeServer extends import_server.Plugin {
42
- workflow;
43
42
  async afterAdd() {
44
43
  }
45
44
  async beforeLoad() {
@@ -38,17 +38,131 @@ var import_constants = require("../../constants");
38
38
  var import_triggers = __toESM(require("../../triggers"));
39
39
  var import_utils = require("../../utils");
40
40
  class CustomActionInterceptionError extends Error {
41
- status = 400;
42
- messages = [];
43
41
  constructor(message) {
44
42
  super(message);
43
+ this.status = 400;
44
+ this.messages = [];
45
45
  this.name = "CustomActionInterceptionError";
46
46
  }
47
47
  }
48
- class OmniTrigger extends import_triggers.default {
49
- static TYPE = "general-action";
48
+ const _OmniTrigger = class _OmniTrigger extends import_triggers.default {
50
49
  constructor(workflow) {
51
50
  super(workflow);
51
+ this.triggerAction = async (context, next) => {
52
+ const {
53
+ params: { filterByTk, values, triggerWorkflows = "", filter, resourceName, actionName }
54
+ } = context.action;
55
+ if (actionName !== "trigger" || resourceName === "workflows") {
56
+ return next();
57
+ }
58
+ const { currentUser, currentRole } = context.state;
59
+ const { model: UserModel } = this.workflow.db.getCollection("users");
60
+ const userInfo = {
61
+ user: UserModel.build(currentUser).desensitize(),
62
+ roleName: currentRole
63
+ };
64
+ const dataSourceHeader = context.get("x-data-source");
65
+ const jointCollectionName = (0, import_data_source.joinCollectionName)(dataSourceHeader, resourceName);
66
+ const triggerWorkflowsMap = /* @__PURE__ */ new Map();
67
+ const triggerWorkflowsArray = [];
68
+ for (const trigger of triggerWorkflows.split(",")) {
69
+ const [key, path] = trigger.split("!");
70
+ triggerWorkflowsMap.set(key, path);
71
+ triggerWorkflowsArray.push(key);
72
+ }
73
+ const workflows = Array.from(this.workflow.enabledCache.values()).filter(
74
+ (item) => item.type === _OmniTrigger.TYPE && item.config.collection === jointCollectionName && triggerWorkflowsArray.includes(item.key)
75
+ ).sort((a, b) => {
76
+ const aIndex = triggerWorkflowsArray.indexOf(a.key);
77
+ const bIndex = triggerWorkflowsArray.indexOf(b.key);
78
+ if (aIndex === -1 && bIndex === -1) {
79
+ return a.id - b.id;
80
+ }
81
+ if (aIndex === -1) {
82
+ return 1;
83
+ }
84
+ if (bIndex === -1) {
85
+ return -1;
86
+ }
87
+ return aIndex - bIndex;
88
+ });
89
+ const syncGroup = [];
90
+ const asyncGroup = [];
91
+ for (const workflow of workflows) {
92
+ const { appends = [] } = workflow.config;
93
+ const [dataSourceName, collectionName] = (0, import_data_source.parseCollectionName)(workflow.config.collection);
94
+ const dataPath = triggerWorkflowsMap.get(workflow.key);
95
+ const event = [workflow];
96
+ const { repository } = context.app.dataSourceManager.dataSources.get(dataSourceName).collectionManager.getCollection(collectionName);
97
+ const formData = dataPath ? import_lodash.default.get(values, dataPath) : values;
98
+ let data = formData;
99
+ if (filterByTk != null) {
100
+ if ((0, import_lodash.isArray)(filterByTk)) {
101
+ data = await repository.find({ filterByTk, appends });
102
+ } else {
103
+ data = await repository.findOne({ filterByTk, appends });
104
+ }
105
+ if (!data) {
106
+ continue;
107
+ }
108
+ Object.assign(data, formData);
109
+ } else if (filter != null) {
110
+ data = await repository.find({ filter, appends });
111
+ if (!data) {
112
+ continue;
113
+ }
114
+ Object.assign(data, formData);
115
+ }
116
+ event.push({ data: (0, import_utils.toJSON)(data), ...userInfo });
117
+ (workflow.sync ? syncGroup : asyncGroup).push(event);
118
+ }
119
+ for (const event of syncGroup) {
120
+ const processor = await this.workflow.trigger(event[0], event[1], { httpContext: context });
121
+ if (!processor) {
122
+ return context.throw(500);
123
+ }
124
+ const { lastSavedJob, nodesMap } = processor;
125
+ const lastNode = nodesMap.get(lastSavedJob == null ? void 0 : lastSavedJob.nodeId);
126
+ if (processor.execution.status === import_constants.EXECUTION_STATUS.RESOLVED) {
127
+ if ((lastNode == null ? void 0 : lastNode.type) === "end") {
128
+ return;
129
+ }
130
+ continue;
131
+ }
132
+ if (processor.execution.status < import_constants.EXECUTION_STATUS.STARTED) {
133
+ if ((lastNode == null ? void 0 : lastNode.type) !== "end") {
134
+ return context.throw(500, "Workflow on your action failed, please contact the administrator");
135
+ }
136
+ const err = new CustomActionInterceptionError("Request is intercepted by workflow");
137
+ err.status = 400;
138
+ err.messages = context.state.messages;
139
+ return context.throw(err.status, err);
140
+ }
141
+ return context.throw(500, "Workflow on your action hangs, please contact the administrator");
142
+ }
143
+ for (const event of asyncGroup) {
144
+ this.workflow.trigger(event[0], event[1]);
145
+ }
146
+ await next();
147
+ };
148
+ this.middleware = async (context, next) => {
149
+ const {
150
+ resourceName,
151
+ actionName,
152
+ params: { triggerWorkflows }
153
+ } = context.action;
154
+ if (resourceName === "workflows" && actionName === "trigger") {
155
+ return this.triggerAction(context, next);
156
+ }
157
+ await next();
158
+ if (!triggerWorkflows) {
159
+ return;
160
+ }
161
+ if (!["create", "update"].includes(actionName)) {
162
+ return;
163
+ }
164
+ return this.trigger(context);
165
+ };
52
166
  this.workflow.app.resourcer.registerActionHandler("trigger", this.triggerAction);
53
167
  this.workflow.app.acl.allow("*", "trigger", "loggedIn");
54
168
  this.workflow.app.pm.get(import_module_error_handler.default).errorHandler.register(
@@ -60,123 +174,8 @@ class OmniTrigger extends import_triggers.default {
60
174
  ctx.status = err.status;
61
175
  }
62
176
  );
63
- workflow.app.use(this.middleware, { tag: "workflowTrigger", after: "dataSource" });
177
+ workflow.app.resourcer.use(this.middleware, { tag: "workflowTrigger", after: "dataSource" });
64
178
  }
65
- triggerAction = async (context, next) => {
66
- const {
67
- params: { filterByTk, values, triggerWorkflows = "", filter, resourceName, actionName }
68
- } = context.action;
69
- if (actionName !== "trigger" || resourceName === "workflows") {
70
- return next();
71
- }
72
- const { currentUser, currentRole } = context.state;
73
- const { model: UserModel } = this.workflow.db.getCollection("users");
74
- const userInfo = {
75
- user: UserModel.build(currentUser).desensitize(),
76
- roleName: currentRole
77
- };
78
- const dataSourceHeader = context.get("x-data-source");
79
- const jointCollectionName = (0, import_data_source.joinCollectionName)(dataSourceHeader, resourceName);
80
- const triggerWorkflowsMap = /* @__PURE__ */ new Map();
81
- const triggerWorkflowsArray = [];
82
- for (const trigger of triggerWorkflows.split(",")) {
83
- const [key, path] = trigger.split("!");
84
- triggerWorkflowsMap.set(key, path);
85
- triggerWorkflowsArray.push(key);
86
- }
87
- const workflows = Array.from(this.workflow.enabledCache.values()).filter(
88
- (item) => item.type === OmniTrigger.TYPE && item.config.collection === jointCollectionName && triggerWorkflowsArray.includes(item.key)
89
- ).sort((a, b) => {
90
- const aIndex = triggerWorkflowsArray.indexOf(a.key);
91
- const bIndex = triggerWorkflowsArray.indexOf(b.key);
92
- if (aIndex === -1 && bIndex === -1) {
93
- return a.id - b.id;
94
- }
95
- if (aIndex === -1) {
96
- return 1;
97
- }
98
- if (bIndex === -1) {
99
- return -1;
100
- }
101
- return aIndex - bIndex;
102
- });
103
- const syncGroup = [];
104
- const asyncGroup = [];
105
- for (const workflow of workflows) {
106
- const { appends = [] } = workflow.config;
107
- const [dataSourceName, collectionName] = (0, import_data_source.parseCollectionName)(workflow.config.collection);
108
- const dataPath = triggerWorkflowsMap.get(workflow.key);
109
- const event = [workflow];
110
- const { repository } = context.app.dataSourceManager.dataSources.get(dataSourceName).collectionManager.getCollection(collectionName);
111
- const formData = dataPath ? import_lodash.default.get(values, dataPath) : values;
112
- let data = formData;
113
- if (filterByTk != null) {
114
- if ((0, import_lodash.isArray)(filterByTk)) {
115
- data = await repository.find({ filterByTk, appends });
116
- } else {
117
- data = await repository.findOne({ filterByTk, appends });
118
- }
119
- if (!data) {
120
- continue;
121
- }
122
- Object.assign(data, formData);
123
- } else if (filter != null) {
124
- data = await repository.find({ filter, appends });
125
- if (!data) {
126
- continue;
127
- }
128
- Object.assign(data, formData);
129
- }
130
- event.push({ data: (0, import_utils.toJSON)(data), ...userInfo });
131
- (workflow.sync ? syncGroup : asyncGroup).push(event);
132
- }
133
- for (const event of syncGroup) {
134
- const processor = await this.workflow.trigger(event[0], event[1], { httpContext: context });
135
- if (!processor) {
136
- return context.throw(500);
137
- }
138
- const { lastSavedJob, nodesMap } = processor;
139
- const lastNode = nodesMap.get(lastSavedJob == null ? void 0 : lastSavedJob.nodeId);
140
- if (processor.execution.status === import_constants.EXECUTION_STATUS.RESOLVED) {
141
- if ((lastNode == null ? void 0 : lastNode.type) === "end") {
142
- return;
143
- }
144
- continue;
145
- }
146
- if (processor.execution.status < import_constants.EXECUTION_STATUS.STARTED) {
147
- if ((lastNode == null ? void 0 : lastNode.type) !== "end") {
148
- return context.throw(500, "Workflow on your action failed, please contact the administrator");
149
- }
150
- const err = new CustomActionInterceptionError("Request is intercepted by workflow");
151
- err.status = 400;
152
- err.messages = context.state.messages;
153
- return context.throw(err.status, err);
154
- }
155
- return context.throw(500, "Workflow on your action hangs, please contact the administrator");
156
- }
157
- for (const event of asyncGroup) {
158
- this.workflow.trigger(event[0], event[1]);
159
- }
160
- await next();
161
- };
162
- middleware = async (context, next) => {
163
- const {
164
- resourceName,
165
- actionName,
166
- params: { triggerWorkflows }
167
- } = context.action;
168
- if (resourceName === "workflows" && actionName === "trigger") {
169
- return this.triggerAction(context, next);
170
- }
171
- await next();
172
- if (!triggerWorkflows) {
173
- return;
174
- }
175
- if (!["create", "update"].includes(actionName)) {
176
- return;
177
- }
178
- return this.trigger(context);
179
- };
180
179
  async trigger(context) {
181
180
  const { triggerWorkflows = "", values } = context.action.params;
182
181
  const dataSourceHeader = context.get("x-data-source") || "main";
@@ -263,7 +262,9 @@ class OmniTrigger extends import_triggers.default {
263
262
  }
264
263
  off() {
265
264
  }
266
- }
265
+ };
266
+ _OmniTrigger.TYPE = "general-action";
267
+ let OmniTrigger = _OmniTrigger;
267
268
  // Annotate the CommonJS export names for ESM import in node:
268
269
  0 && (module.exports = {
269
270
  OmniTrigger
@@ -24,9 +24,12 @@ var import_server = require("@tachybase/server");
24
24
  var import_sequelize = require("sequelize");
25
25
  var import_constants = require("../constants");
26
26
  class add_initAt_default extends import_server.Migration {
27
- on = "afterLoad";
28
- // 'beforeLoad' or 'afterLoad'
29
- appVersion = "<0.22.38";
27
+ constructor() {
28
+ super(...arguments);
29
+ this.on = "afterLoad";
30
+ // 'beforeLoad' or 'afterLoad'
31
+ this.appVersion = "<0.22.38";
32
+ }
30
33
  async up() {
31
34
  const result = await this.app.db.sequelize.query(
32
35
  `