@tachybase/module-workflow 0.23.41 → 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.
- package/dist/client/components/ExecutionRetryAction.d.ts +3 -0
- package/dist/client/components/ExecutionTime.d.ts +2 -1
- package/dist/client/components/index.d.ts +2 -1
- package/dist/client/features/dynamic-calculation/DynamicExpression.d.ts +2 -2
- package/dist/client/features/trigger-instruction/TriggerInstruction.d.ts +4 -2
- package/dist/client/index.d.ts +1 -2
- package/dist/client/index.js +58 -58
- package/dist/client/schemas/executions.d.ts +16 -6
- package/dist/externalVersion.js +15 -15
- package/dist/locale/zh-CN.json +8 -0
- package/dist/node_modules/@babel/core/package.json +1 -1
- package/dist/node_modules/cron-parser/package.json +1 -1
- package/dist/node_modules/form-data/package.json +1 -1
- package/dist/node_modules/jsonata/package.json +1 -1
- package/dist/node_modules/lru-cache/package.json +1 -1
- package/dist/node_modules/mime-types/package.json +1 -1
- package/dist/node_modules/qrcode/package.json +1 -1
- package/dist/server/Plugin.js +80 -76
- package/dist/server/Processor.js +15 -17
- package/dist/server/actions/executions.d.ts +2 -1
- package/dist/server/actions/executions.js +48 -2
- package/dist/server/actions/workflows.d.ts +1 -0
- package/dist/server/actions/workflows.js +66 -0
- package/dist/server/collections/executions.js +4 -0
- package/dist/server/features/_deprecated-json-parse/JSONParse.instruction.js +4 -1
- package/dist/server/features/delay/DelayInstruction.js +36 -36
- package/dist/server/features/interception/RequestInterceptionTrigger.js +81 -80
- package/dist/server/features/manual/ManualInstruction.js +1 -1
- package/dist/server/features/notice/plugin.js +0 -1
- package/dist/server/features/omni-trigger/CustomActionTrigger.js +122 -121
- package/dist/server/migrations/20241118104303-add-initAt.js +6 -3
- package/dist/server/migrations/20241206122842-add-createdBy.js +6 -3
- package/dist/server/migrations/20241220001154-bigInt.js +6 -3
- package/dist/server/triggers/CollectionTrigger.js +4 -1
- package/dist/server/triggers/ScheduleTrigger/DateFieldScheduleTrigger.js +5 -5
- package/dist/server/triggers/ScheduleTrigger/StaticScheduleTrigger.js +1 -1
- package/dist/server/triggers/ScheduleTrigger/index.js +2 -2
- package/dist/server/triggers/index.js +0 -1
- package/package.json +17 -17
- /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,
|
|
@@ -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
|
-
|
|
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
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
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
|
|
89
|
-
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (
|
|
114
|
-
return
|
|
77
|
+
if (aIndex === -1) {
|
|
78
|
+
return 1;
|
|
79
|
+
}
|
|
80
|
+
if (bIndex === -1) {
|
|
81
|
+
return -1;
|
|
115
82
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
`
|