@nocobase/plugin-workflow-action-trigger 0.21.0-alpha.1 → 0.21.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.
- package/dist/client/ActionTrigger.d.ts +52 -2
- package/dist/client/index.js +1 -1
- package/dist/externalVersion.js +9 -9
- package/dist/locale/zh-CN.json +11 -3
- package/dist/server/ActionTrigger.d.ts +3 -2
- package/dist/server/ActionTrigger.js +54 -31
- package/package.json +6 -6
- package/src/client/ActionTrigger.tsx +81 -4
- package/src/client/__e2e__/workflowCRUD.test.ts +1 -1
- package/src/client/index.ts +2 -6
- package/src/locale/zh-CN.json +11 -3
- package/src/server/ActionTrigger.ts +56 -42
- package/src/server/__tests__/trigger.test.ts +120 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SchemaInitializerItemType, useCollectionDataSource } from '@nocobase/client';
|
|
2
|
-
import { Trigger, useWorkflowAnyExecuted } from '@nocobase/plugin-workflow/client';
|
|
2
|
+
import { Trigger, useWorkflowAnyExecuted, CheckboxGroupWithTooltip, RadioWithTooltip } from '@nocobase/plugin-workflow/client';
|
|
3
3
|
export default class extends Trigger {
|
|
4
4
|
title: string;
|
|
5
5
|
description: string;
|
|
@@ -8,10 +8,12 @@ export default class extends Trigger {
|
|
|
8
8
|
type: string;
|
|
9
9
|
required: boolean;
|
|
10
10
|
'x-decorator': string;
|
|
11
|
+
'x-decorator-props': {
|
|
12
|
+
tooltip: string;
|
|
13
|
+
};
|
|
11
14
|
'x-component': string;
|
|
12
15
|
'x-disabled': string;
|
|
13
16
|
title: string;
|
|
14
|
-
description: string;
|
|
15
17
|
'x-reactions': {
|
|
16
18
|
target: string;
|
|
17
19
|
effects: string[];
|
|
@@ -22,6 +24,50 @@ export default class extends Trigger {
|
|
|
22
24
|
};
|
|
23
25
|
}[];
|
|
24
26
|
};
|
|
27
|
+
global: {
|
|
28
|
+
type: string;
|
|
29
|
+
title: string;
|
|
30
|
+
'x-decorator': string;
|
|
31
|
+
'x-component': string;
|
|
32
|
+
'x-component-props': {
|
|
33
|
+
direction: string;
|
|
34
|
+
options: {
|
|
35
|
+
label: string;
|
|
36
|
+
value: boolean;
|
|
37
|
+
}[];
|
|
38
|
+
};
|
|
39
|
+
default: boolean;
|
|
40
|
+
'x-reactions': {
|
|
41
|
+
dependencies: string[];
|
|
42
|
+
fulfill: {
|
|
43
|
+
state: {
|
|
44
|
+
visible: string;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
}[];
|
|
48
|
+
};
|
|
49
|
+
actions: {
|
|
50
|
+
type: string;
|
|
51
|
+
title: string;
|
|
52
|
+
'x-decorator': string;
|
|
53
|
+
'x-component': string;
|
|
54
|
+
'x-component-props': {
|
|
55
|
+
direction: string;
|
|
56
|
+
options: {
|
|
57
|
+
label: string;
|
|
58
|
+
value: string;
|
|
59
|
+
}[];
|
|
60
|
+
};
|
|
61
|
+
required: boolean;
|
|
62
|
+
'x-reactions': {
|
|
63
|
+
dependencies: string[];
|
|
64
|
+
fulfill: {
|
|
65
|
+
state: {
|
|
66
|
+
visible: string;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
}[];
|
|
70
|
+
};
|
|
25
71
|
appends: {
|
|
26
72
|
type: string;
|
|
27
73
|
title: string;
|
|
@@ -47,6 +93,10 @@ export default class extends Trigger {
|
|
|
47
93
|
useCollectionDataSource: typeof useCollectionDataSource;
|
|
48
94
|
useWorkflowAnyExecuted: typeof useWorkflowAnyExecuted;
|
|
49
95
|
};
|
|
96
|
+
components: {
|
|
97
|
+
RadioWithTooltip: typeof RadioWithTooltip;
|
|
98
|
+
CheckboxGroupWithTooltip: typeof CheckboxGroupWithTooltip;
|
|
99
|
+
};
|
|
50
100
|
isActionTriggerable: (config: any, context: any) => boolean;
|
|
51
101
|
useVariables(config: any, options: any): import("@nocobase/plugin-workflow/client").VariableOption[];
|
|
52
102
|
useInitializers(config: any): SchemaInitializerItemType | null;
|
package/dist/client/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(o,e){typeof exports=="object"&&typeof module!="undefined"?e(exports,require("@nocobase/client"),require("@nocobase/plugin-workflow/client"),require("@formily/react"),require("react-i18next")):typeof define=="function"&&define.amd?define(["exports","@nocobase/client","@nocobase/plugin-workflow/client","@formily/react","react-i18next"],e):(o=typeof globalThis!="undefined"?globalThis:o||self,e(o["@nocobase/plugin-workflow-action-trigger"]={},o["@nocobase/client"],o["@nocobase/plugin-workflow"],o["@formily/react"],o["react-i18next"]))})(this,function(o,e,t,w,m){"use strict";var
|
|
1
|
+
(function(o,e){typeof exports=="object"&&typeof module!="undefined"?e(exports,require("@nocobase/client"),require("@nocobase/plugin-workflow/client"),require("@formily/react"),require("react-i18next")):typeof define=="function"&&define.amd?define(["exports","@nocobase/client","@nocobase/plugin-workflow/client","@formily/react","react-i18next"],e):(o=typeof globalThis!="undefined"?globalThis:o||self,e(o["@nocobase/plugin-workflow-action-trigger"]={},o["@nocobase/client"],o["@nocobase/plugin-workflow"],o["@formily/react"],o["react-i18next"]))})(this,function(o,e,t,w,m){"use strict";var E=Object.defineProperty,$=Object.defineProperties;var M=Object.getOwnPropertyDescriptors;var S=Object.getOwnPropertySymbols;var v=Object.prototype.hasOwnProperty,D=Object.prototype.propertyIsEnumerable;var k=(o,e,t)=>e in o?E(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t,g=(o,e)=>{for(var t in e||(e={}))v.call(e,t)&&k(o,t,e[t]);if(S)for(var t of S(e))D.call(e,t)&&k(o,t,e[t]);return o},f=(o,e)=>$(o,M(e));var s=(o,e,t)=>(k(o,typeof e!="symbol"?e+"":e,t),t);var F=(o,e,t)=>new Promise((w,m)=>{var i=r=>{try{c(t.next(r))}catch(l){m(l)}},a=r=>{try{c(t.throw(r))}catch(l){m(l)}},c=r=>r.done?w(r.value):Promise.resolve(r.value).then(i,a);c((t=t.apply(o,e)).next())});const i="workflow-action-trigger";function a(u,A={}){const{t:n}=c(A);return n(u)}function c(u){return m.useTranslation(i,u)}const r={CREATE:"create",UPDATE:"update",UPSERT:"updateOrCreate",DESTROY:"destroy"};class l extends t.Trigger{constructor(){super(...arguments);s(this,"title",`{{t("Post-action event", { ns: "${i}" })}}`);s(this,"description",`{{t('Triggered after the completion of a request initiated through an action button or API, such as after adding, updating, deleting data, or "submit to workflow". Suitable for data processing, sending notifications, etc., after actions are completed.', { ns: "${i}" })}}`);s(this,"fieldset",{collection:{type:"string",required:!0,"x-decorator":"FormItem","x-decorator-props":{tooltip:`{{t("The collection to which the triggered data belongs.", { ns: "${i}" })}}`},"x-component":"DataSourceCollectionCascader","x-disabled":"{{ useWorkflowAnyExecuted() }}",title:`{{t("Collection", { ns: "${i}" })}}`,"x-reactions":[{target:"appends",effects:["onFieldValueChange"],fulfill:{state:{value:[]}}}]},global:{type:"boolean",title:`{{t("Trigger mode", { ns: "${i}" })}}`,"x-decorator":"FormItem","x-component":"RadioWithTooltip","x-component-props":{direction:"vertical",options:[{label:`{{t("Local mode, triggered after the completion of actions bound to this workflow", { ns: "${i}" })}}`,value:!1},{label:`{{t("Global mode, triggered after the completion of the following actions", { ns: "${i}" })}}`,value:!0}]},default:!1,"x-reactions":[{dependencies:["collection"],fulfill:{state:{visible:"{{!!$deps[0]}}"}}}]},actions:{type:"number",title:`{{t("Select actions", { ns: "${i}" })}}`,"x-decorator":"FormItem","x-component":"CheckboxGroupWithTooltip","x-component-props":{direction:"vertical",options:[{label:`{{t("Create record action", { ns: "${i}" })}}`,value:r.CREATE},{label:`{{t("Update record action", { ns: "${i}" })}}`,value:r.UPDATE}]},required:!0,"x-reactions":[{dependencies:["collection","global"],fulfill:{state:{visible:"{{!!$deps[0] && !!$deps[1]}}"}}}]},appends:{type:"array",title:`{{t("Associations to use", { ns: "${i}" })}}`,description:'{{t("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.", { ns: "workflow" })}}',"x-decorator":"FormItem","x-component":"AppendsTreeSelect","x-component-props":{title:"Preload associations",multiple:!0,useCollection(){const{values:n}=w.useForm();return n==null?void 0:n.collection}},"x-reactions":[{dependencies:["collection"],fulfill:{state:{visible:"{{!!$deps[0]}}"}}}]}});s(this,"scope",{useCollectionDataSource:e.useCollectionDataSource,useWorkflowAnyExecuted:t.useWorkflowAnyExecuted});s(this,"components",{RadioWithTooltip:t.RadioWithTooltip,CheckboxGroupWithTooltip:t.CheckboxGroupWithTooltip});s(this,"isActionTriggerable",(n,d)=>d.action==="customize:triggerWorkflows"||["create","update","customize:update"].includes(d.action)&&!n.global)}useVariables(n,d){var y;const T=e.useCompile(),{getCollectionFields:I}=e.useCollectionManager_deprecated(),z=a("Trigger data"),x=a("User submitted action"),C=a("Role of user submitted action"),W=[{collectionName:n.collection,name:"data",type:"hasOne",target:n.collection,uiSchema:{title:z}},{collectionName:"users",name:"user",type:"hasOne",target:"users",uiSchema:{title:x}},{name:"roleName",uiSchema:{title:C}}];return t.getCollectionFieldOptions(f(g({appends:["data","user",...((y=n.appends)==null?void 0:y.map(R=>`data.${R}`))||[]]},d),{fields:W,compile:T,getCollectionFields:I}))}useInitializers(n){return n.collection?{name:"triggerData",type:"item",key:"triggerData",title:`{{t("Trigger data", { ns: "${i}" })}}`,Component:t.CollectionBlockInitializer,collection:n.collection,dataPath:"$context.data"}:null}}const h={name:"submitToWorkflow",title:'{{t("Submit to workflow", { ns: "workflow" })}}',Component:"CustomizeActionInitializer",schema:{title:'{{t("Submit to workflow", { ns: "workflow" })}}',"x-component":"Action","x-use-component-props":"useTriggerWorkflowsActionProps","x-designer":"Action.Designer","x-action-settings":{skipValidator:!1,onSuccess:{manualClose:!0,redirecting:!1,successMessage:'{{t("Submitted successfully")}}'},triggerWorkflows:[]},"x-action":"customize:triggerWorkflows"}},p={name:"submitToWorkflow",title:'{{t("Submit to workflow", { ns: "workflow" })}}',Component:"CustomizeActionInitializer",schema:{title:'{{t("Submit to workflow", { ns: "workflow" })}}',"x-component":"Action","x-use-component-props":"useRecordTriggerWorkflowsActionProps","x-designer":"Action.Designer","x-action-settings":{onSuccess:{manualClose:!0,redirecting:!1,successMessage:'{{t("Submitted successfully")}}'},triggerWorkflows:[]},"x-action":"customize:triggerWorkflows"}},b=f(g({},p),{schema:f(g({},p.schema),{"x-component":"Action.Link"})});class P extends e.Plugin{load(){return F(this,null,function*(){this.app.pm.get("workflow").registerTrigger("action",l),this.app.addScopes({useTriggerWorkflowsActionProps:t.useTriggerWorkflowsActionProps,useRecordTriggerWorkflowsActionProps:t.useRecordTriggerWorkflowsActionProps}),this.app.schemaInitializerManager.get("FormActionInitializers").add("customize.submitToWorkflow",h),this.app.schemaInitializerManager.get("createForm:configureActions").add("customize.submitToWorkflow",h),this.app.schemaInitializerManager.get("editForm:configureActions").add("customize.submitToWorkflow",h),this.app.schemaInitializerManager.get("detailsWithPaging:configureActions").add("customize.submitToWorkflow",p),this.app.schemaInitializerManager.get("details:configureActions").add("customize.submitToWorkflow",p),this.app.schemaInitializerManager.get("table:configureItemActions").add("customize.submitToWorkflow",b),this.app.schemaInitializerManager.get("gridCard:configureItemActions").add("customize.submitToWorkflow",b),this.app.schemaInitializerManager.get("list:configureItemActions").add("customize.submitToWorkflow",b)})}}o.default=P,Object.defineProperties(o,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
package/dist/externalVersion.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
"@formily/react": "2.3.0",
|
|
3
|
-
"@nocobase/client": "0.21.0-alpha.
|
|
4
|
-
"@nocobase/plugin-workflow": "0.21.0-alpha.
|
|
3
|
+
"@nocobase/client": "0.21.0-alpha.2",
|
|
4
|
+
"@nocobase/plugin-workflow": "0.21.0-alpha.2",
|
|
5
5
|
"react-i18next": "11.18.6",
|
|
6
6
|
"lodash": "4.17.21",
|
|
7
7
|
"sequelize": "6.35.2",
|
|
8
|
-
"@nocobase/database": "0.21.0-alpha.
|
|
9
|
-
"@nocobase/server": "0.21.0-alpha.
|
|
10
|
-
"@nocobase/actions": "0.21.0-alpha.
|
|
11
|
-
"@nocobase/data-source-manager": "0.21.0-alpha.
|
|
12
|
-
"@nocobase/plugin-workflow-test": "0.21.0-alpha.
|
|
13
|
-
"@nocobase/test": "0.21.0-alpha.
|
|
14
|
-
"@nocobase/utils": "0.21.0-alpha.
|
|
8
|
+
"@nocobase/database": "0.21.0-alpha.2",
|
|
9
|
+
"@nocobase/server": "0.21.0-alpha.2",
|
|
10
|
+
"@nocobase/actions": "0.21.0-alpha.2",
|
|
11
|
+
"@nocobase/data-source-manager": "0.21.0-alpha.2",
|
|
12
|
+
"@nocobase/plugin-workflow-test": "0.21.0-alpha.2",
|
|
13
|
+
"@nocobase/test": "0.21.0-alpha.2",
|
|
14
|
+
"@nocobase/utils": "0.21.0-alpha.2"
|
|
15
15
|
};
|
package/dist/locale/zh-CN.json
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
2
|
+
"Post-action event": "操作后事件",
|
|
3
|
+
"Triggered after the completion of a request initiated through an action button or API, such as after adding, updating, deleting data, or \"submit to workflow\". Suitable for data processing, sending notifications, etc., after actions are completed.":
|
|
4
|
+
"通过操作按钮或 API 发起请求并在执行完成后触发,比如新增、更新、删除数据或者“提交至工作流”之后。适用于在操作完成后进行数据处理、发送通知等。",
|
|
4
5
|
"Collection": "数据表",
|
|
5
|
-
"
|
|
6
|
+
"The collection to which the triggered data belongs.": "触发数据所属的数据表。",
|
|
7
|
+
"Trigger mode": "触发模式",
|
|
8
|
+
"Local mode, triggered after the completion of actions bound to this workflow": "局部模式,绑定该工作流的操作执行完成后触发",
|
|
9
|
+
"Global mode, triggered after the completion of the following actions": "全局模式,以下操作执行完成后都触发",
|
|
10
|
+
"Action to submit to workflow directly is only supported on bound buttons, and will not be affected under global mode.": "直接提交至工作流的操作仅支持使用按钮绑定,不受全局模式的影响。",
|
|
11
|
+
"Select actions": "选择操作",
|
|
12
|
+
"Create record action": "创建记录操作",
|
|
13
|
+
"Update record action": "更新记录操作",
|
|
6
14
|
"Associations to use": "待使用的关系数据",
|
|
7
15
|
"Trigger data": "触发器数据",
|
|
8
16
|
"User submitted action": "提交操作的用户",
|
|
@@ -4,10 +4,11 @@ import WorkflowPlugin, { Trigger, WorkflowModel } from '@nocobase/plugin-workflo
|
|
|
4
4
|
interface Context extends ActionContext, DefaultContext {
|
|
5
5
|
}
|
|
6
6
|
export default class extends Trigger {
|
|
7
|
+
static TYPE: string;
|
|
7
8
|
constructor(workflow: WorkflowPlugin);
|
|
8
|
-
|
|
9
|
+
workflowTriggerAction(context: Context, next: Next): Promise<void>;
|
|
9
10
|
middleware: (context: Context, next: Next) => Promise<void>;
|
|
10
|
-
private
|
|
11
|
+
private collectionTriggerAction;
|
|
11
12
|
on(workflow: WorkflowModel): void;
|
|
12
13
|
off(workflow: WorkflowModel): void;
|
|
13
14
|
}
|
|
@@ -25,40 +25,39 @@ var import_database = require("@nocobase/database");
|
|
|
25
25
|
var import_plugin_workflow = require("@nocobase/plugin-workflow");
|
|
26
26
|
var import_data_source_manager = require("@nocobase/data-source-manager");
|
|
27
27
|
class ActionTrigger_default extends import_plugin_workflow.Trigger {
|
|
28
|
+
static TYPE = "action";
|
|
28
29
|
constructor(workflow) {
|
|
29
30
|
super(workflow);
|
|
30
31
|
workflow.app.use(this.middleware, { after: "dataSource" });
|
|
31
32
|
}
|
|
32
|
-
async
|
|
33
|
+
async workflowTriggerAction(context, next) {
|
|
33
34
|
const { triggerWorkflows } = context.action.params;
|
|
34
35
|
if (!triggerWorkflows) {
|
|
35
36
|
return context.throw(400);
|
|
36
37
|
}
|
|
37
38
|
context.status = 202;
|
|
38
39
|
await next();
|
|
39
|
-
this.
|
|
40
|
+
return this.collectionTriggerAction(context);
|
|
40
41
|
}
|
|
41
42
|
middleware = async (context, next) => {
|
|
42
|
-
const {
|
|
43
|
-
resourceName,
|
|
44
|
-
actionName,
|
|
45
|
-
params: { triggerWorkflows }
|
|
46
|
-
} = context.action;
|
|
43
|
+
const { resourceName, actionName } = context.action;
|
|
47
44
|
if (resourceName === "workflows" && actionName === "trigger") {
|
|
48
|
-
return this.
|
|
45
|
+
return this.workflowTriggerAction(context, next);
|
|
49
46
|
}
|
|
50
47
|
await next();
|
|
51
|
-
if (!triggerWorkflows) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
48
|
if (!["create", "update"].includes(actionName)) {
|
|
55
49
|
return;
|
|
56
50
|
}
|
|
57
|
-
return this.
|
|
51
|
+
return this.collectionTriggerAction(context);
|
|
58
52
|
};
|
|
59
|
-
async
|
|
60
|
-
const {
|
|
53
|
+
async collectionTriggerAction(context) {
|
|
54
|
+
const {
|
|
55
|
+
resourceName,
|
|
56
|
+
actionName,
|
|
57
|
+
params: { triggerWorkflows = "", values }
|
|
58
|
+
} = context.action;
|
|
61
59
|
const dataSourceHeader = context.get("x-data-source") || "main";
|
|
60
|
+
const fullCollectionName = (0, import_data_source_manager.joinCollectionName)(dataSourceHeader, resourceName);
|
|
62
61
|
const { currentUser, currentRole } = context.state;
|
|
63
62
|
const { model: UserModel } = this.workflow.db.getCollection("users");
|
|
64
63
|
const userInfo = {
|
|
@@ -66,21 +65,42 @@ class ActionTrigger_default extends import_plugin_workflow.Trigger {
|
|
|
66
65
|
roleName: currentRole
|
|
67
66
|
};
|
|
68
67
|
const triggers = triggerWorkflows.split(",").map((trigger) => trigger.split("!"));
|
|
69
|
-
const
|
|
70
|
-
const workflows = (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
const triggersKeysMap = new Map(triggers);
|
|
69
|
+
const workflows = Array.from(this.workflow.enabledCache.values()).filter(
|
|
70
|
+
(item) => item.type === "action" && item.config.collection
|
|
71
|
+
);
|
|
72
|
+
const globalWorkflows = /* @__PURE__ */ new Map();
|
|
73
|
+
const localWorkflows = /* @__PURE__ */ new Map();
|
|
74
|
+
workflows.forEach((item) => {
|
|
75
|
+
var _a;
|
|
76
|
+
if (resourceName === "workflows" && actionName === "trigger") {
|
|
77
|
+
localWorkflows.set(item.key, item);
|
|
78
|
+
} else if (item.config.collection === fullCollectionName) {
|
|
79
|
+
if (item.config.global) {
|
|
80
|
+
if ((_a = item.config.actions) == null ? void 0 : _a.includes(actionName)) {
|
|
81
|
+
globalWorkflows.set(item.key, item);
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
localWorkflows.set(item.key, item);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
const triggeringLocalWorkflows = [];
|
|
89
|
+
const uniqueTriggersMap = /* @__PURE__ */ new Map();
|
|
90
|
+
triggers.forEach((trigger) => {
|
|
91
|
+
const [key] = trigger;
|
|
92
|
+
const workflow = localWorkflows.get(key);
|
|
93
|
+
if (workflow && !uniqueTriggersMap.has(key)) {
|
|
94
|
+
triggeringLocalWorkflows.push(workflow);
|
|
95
|
+
uniqueTriggersMap.set(key, true);
|
|
76
96
|
}
|
|
77
|
-
})
|
|
97
|
+
});
|
|
78
98
|
const syncGroup = [];
|
|
79
99
|
const asyncGroup = [];
|
|
80
|
-
for (const workflow of
|
|
100
|
+
for (const workflow of triggeringLocalWorkflows.concat(...globalWorkflows.values())) {
|
|
81
101
|
const { collection, appends = [] } = workflow.config;
|
|
82
102
|
const [dataSourceName, collectionName] = (0, import_data_source_manager.parseCollectionName)(collection);
|
|
83
|
-
const
|
|
103
|
+
const dataPath = triggersKeysMap.get(workflow.key);
|
|
84
104
|
const event = [workflow];
|
|
85
105
|
if (context.action.resourceName !== "workflows") {
|
|
86
106
|
if (!context.body) {
|
|
@@ -92,9 +112,12 @@ class ActionTrigger_default extends import_plugin_workflow.Trigger {
|
|
|
92
112
|
const { body: data } = context;
|
|
93
113
|
for (const row of Array.isArray(data) ? data : [data]) {
|
|
94
114
|
let payload = row;
|
|
95
|
-
if (
|
|
96
|
-
const paths =
|
|
115
|
+
if (dataPath) {
|
|
116
|
+
const paths = dataPath.split(".");
|
|
97
117
|
for (const field of paths) {
|
|
118
|
+
if (!payload) {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
98
121
|
if (payload.get(field)) {
|
|
99
122
|
payload = payload.get(field);
|
|
100
123
|
} else {
|
|
@@ -103,14 +126,14 @@ class ActionTrigger_default extends import_plugin_workflow.Trigger {
|
|
|
103
126
|
}
|
|
104
127
|
}
|
|
105
128
|
}
|
|
106
|
-
const model = payload.constructor;
|
|
107
129
|
if (payload instanceof import_database.Model) {
|
|
130
|
+
const model = payload.constructor;
|
|
108
131
|
if (collectionName !== model.collection.name) {
|
|
109
132
|
continue;
|
|
110
133
|
}
|
|
111
134
|
if (appends.length) {
|
|
112
135
|
payload = await model.collection.repository.findOne({
|
|
113
|
-
filterByTk: payload.get(model.
|
|
136
|
+
filterByTk: payload.get(model.collection.filterTargetKey),
|
|
114
137
|
appends
|
|
115
138
|
});
|
|
116
139
|
}
|
|
@@ -118,9 +141,9 @@ class ActionTrigger_default extends import_plugin_workflow.Trigger {
|
|
|
118
141
|
event.push({ data: (0, import_plugin_workflow.toJSON)(payload), ...userInfo });
|
|
119
142
|
}
|
|
120
143
|
} else {
|
|
121
|
-
const {
|
|
122
|
-
let data =
|
|
123
|
-
const pk = (0, import_lodash.get)(data,
|
|
144
|
+
const { filterTargetKey, repository } = context.app.dataSourceManager.dataSources.get(dataSourceName).collectionManager.getCollection(collectionName);
|
|
145
|
+
let data = dataPath ? (0, import_lodash.get)(values, dataPath) : values;
|
|
146
|
+
const pk = (0, import_lodash.get)(data, filterTargetKey);
|
|
124
147
|
if (appends.length && pk != null) {
|
|
125
148
|
data = await repository.findOne({
|
|
126
149
|
filterByTk: pk,
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/plugin-workflow-action-trigger",
|
|
3
|
-
"displayName": "Workflow:
|
|
4
|
-
"displayName.zh-CN": "
|
|
5
|
-
"description": "
|
|
6
|
-
"description.zh-CN": "
|
|
7
|
-
"version": "0.21.0-alpha.
|
|
3
|
+
"displayName": "Workflow: Post-action event",
|
|
4
|
+
"displayName.zh-CN": "工作流:操作后事件",
|
|
5
|
+
"description": "Triggered after the completion of a request initiated through an action button or API, such as after adding, updating, deleting data, or \"submit to workflow\". Suitable for data processing, sending notifications, etc., after actions are completed.",
|
|
6
|
+
"description.zh-CN": "通过操作按钮或 API 发起请求并在执行完成后触发,比如新增、更新、删除数据或者“提交至工作流”之后。适用于在操作完成后进行数据处理、发送通知等。",
|
|
7
|
+
"version": "0.21.0-alpha.2",
|
|
8
8
|
"license": "AGPL-3.0",
|
|
9
9
|
"main": "./dist/server/index.js",
|
|
10
10
|
"homepage": "https://docs.nocobase.com/plugins/workflow-action-trigger",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"@nocobase/server": "0.x",
|
|
22
22
|
"@nocobase/test": "0.x"
|
|
23
23
|
},
|
|
24
|
-
"gitHead": "
|
|
24
|
+
"gitHead": "90628f2e2da846208fb2d7966ddb4e467d187ffb",
|
|
25
25
|
"keywords": [
|
|
26
26
|
"Workflow"
|
|
27
27
|
]
|
|
@@ -11,21 +11,32 @@ import {
|
|
|
11
11
|
CollectionBlockInitializer,
|
|
12
12
|
getCollectionFieldOptions,
|
|
13
13
|
useWorkflowAnyExecuted,
|
|
14
|
+
CheckboxGroupWithTooltip,
|
|
15
|
+
RadioWithTooltip,
|
|
14
16
|
} from '@nocobase/plugin-workflow/client';
|
|
15
17
|
import { NAMESPACE, useLang } from '../locale';
|
|
16
18
|
|
|
19
|
+
const COLLECTION_TRIGGER_ACTION = {
|
|
20
|
+
CREATE: 'create',
|
|
21
|
+
UPDATE: 'update',
|
|
22
|
+
UPSERT: 'updateOrCreate',
|
|
23
|
+
DESTROY: 'destroy',
|
|
24
|
+
};
|
|
25
|
+
|
|
17
26
|
export default class extends Trigger {
|
|
18
|
-
title = `{{t("
|
|
19
|
-
description = `{{t(
|
|
27
|
+
title = `{{t("Post-action event", { ns: "${NAMESPACE}" })}}`;
|
|
28
|
+
description = `{{t('Triggered after the completion of a request initiated through an action button or API, such as after adding, updating, deleting data, or "submit to workflow". Suitable for data processing, sending notifications, etc., after actions are completed.', { ns: "${NAMESPACE}" })}}`;
|
|
20
29
|
fieldset = {
|
|
21
30
|
collection: {
|
|
22
31
|
type: 'string',
|
|
23
32
|
required: true,
|
|
24
33
|
'x-decorator': 'FormItem',
|
|
34
|
+
'x-decorator-props': {
|
|
35
|
+
tooltip: `{{t("The collection to which the triggered data belongs.", { ns: "${NAMESPACE}" })}}`,
|
|
36
|
+
},
|
|
25
37
|
'x-component': 'DataSourceCollectionCascader',
|
|
26
38
|
'x-disabled': '{{ useWorkflowAnyExecuted() }}',
|
|
27
39
|
title: `{{t("Collection", { ns: "${NAMESPACE}" })}}`,
|
|
28
|
-
description: `{{t("Which collection record belongs to.", { ns: "${NAMESPACE}" })}}`,
|
|
29
40
|
'x-reactions': [
|
|
30
41
|
{
|
|
31
42
|
target: 'appends',
|
|
@@ -38,6 +49,65 @@ export default class extends Trigger {
|
|
|
38
49
|
},
|
|
39
50
|
],
|
|
40
51
|
},
|
|
52
|
+
global: {
|
|
53
|
+
type: 'boolean',
|
|
54
|
+
title: `{{t("Trigger mode", { ns: "${NAMESPACE}" })}}`,
|
|
55
|
+
'x-decorator': 'FormItem',
|
|
56
|
+
'x-component': 'RadioWithTooltip',
|
|
57
|
+
'x-component-props': {
|
|
58
|
+
direction: 'vertical',
|
|
59
|
+
options: [
|
|
60
|
+
{
|
|
61
|
+
label: `{{t("Local mode, triggered after the completion of actions bound to this workflow", { ns: "${NAMESPACE}" })}}`,
|
|
62
|
+
value: false,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
label: `{{t("Global mode, triggered after the completion of the following actions", { ns: "${NAMESPACE}" })}}`,
|
|
66
|
+
value: true,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
default: false,
|
|
71
|
+
'x-reactions': [
|
|
72
|
+
{
|
|
73
|
+
dependencies: ['collection'],
|
|
74
|
+
fulfill: {
|
|
75
|
+
state: {
|
|
76
|
+
visible: '{{!!$deps[0]}}',
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
actions: {
|
|
83
|
+
type: 'number',
|
|
84
|
+
title: `{{t("Select actions", { ns: "${NAMESPACE}" })}}`,
|
|
85
|
+
'x-decorator': 'FormItem',
|
|
86
|
+
'x-component': 'CheckboxGroupWithTooltip',
|
|
87
|
+
'x-component-props': {
|
|
88
|
+
direction: 'vertical',
|
|
89
|
+
options: [
|
|
90
|
+
{ label: `{{t("Create record action", { ns: "${NAMESPACE}" })}}`, value: COLLECTION_TRIGGER_ACTION.CREATE },
|
|
91
|
+
{ label: `{{t("Update record action", { ns: "${NAMESPACE}" })}}`, value: COLLECTION_TRIGGER_ACTION.UPDATE },
|
|
92
|
+
// { label: `{{t("upsert", { ns: "${NAMESPACE}" })}}`, value: COLLECTION_TRIGGER_ACTION.UPSERT },
|
|
93
|
+
// {
|
|
94
|
+
// label: `{{t("Delete single or many records", { ns: "${NAMESPACE}" })}}`,
|
|
95
|
+
// value: COLLECTION_TRIGGER_ACTION.DESTROY,
|
|
96
|
+
// },
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
required: true,
|
|
100
|
+
'x-reactions': [
|
|
101
|
+
{
|
|
102
|
+
dependencies: ['collection', 'global'],
|
|
103
|
+
fulfill: {
|
|
104
|
+
state: {
|
|
105
|
+
visible: '{{!!$deps[0] && !!$deps[1]}}',
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
},
|
|
41
111
|
appends: {
|
|
42
112
|
type: 'array',
|
|
43
113
|
title: `{{t("Associations to use", { ns: "${NAMESPACE}" })}}`,
|
|
@@ -68,8 +138,15 @@ export default class extends Trigger {
|
|
|
68
138
|
useCollectionDataSource,
|
|
69
139
|
useWorkflowAnyExecuted,
|
|
70
140
|
};
|
|
141
|
+
components = {
|
|
142
|
+
RadioWithTooltip,
|
|
143
|
+
CheckboxGroupWithTooltip,
|
|
144
|
+
};
|
|
71
145
|
isActionTriggerable = (config, context) => {
|
|
72
|
-
return
|
|
146
|
+
return (
|
|
147
|
+
context.action === 'customize:triggerWorkflows' ||
|
|
148
|
+
(['create', 'update', 'customize:update'].includes(context.action) && !config.global)
|
|
149
|
+
);
|
|
73
150
|
};
|
|
74
151
|
useVariables(config, options) {
|
|
75
152
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
@@ -56,7 +56,7 @@ test.describe('Add new', () => {
|
|
|
56
56
|
const workFlowName = faker.string.alphanumeric(5);
|
|
57
57
|
await createWorkFlow.name.fill(workFlowName);
|
|
58
58
|
await createWorkFlow.triggerType.click();
|
|
59
|
-
await page.
|
|
59
|
+
await page.getByTitle('Post-action event').click();
|
|
60
60
|
await page.getByLabel('action-Action-Submit-workflows').click();
|
|
61
61
|
|
|
62
62
|
// 3、预期结果:列表中出现新建的工作流
|
package/src/client/index.ts
CHANGED
|
@@ -13,9 +13,7 @@ const submitToWorkflowActionInitializer: SchemaInitializerItemType = {
|
|
|
13
13
|
schema: {
|
|
14
14
|
title: '{{t("Submit to workflow", { ns: "workflow" })}}',
|
|
15
15
|
'x-component': 'Action',
|
|
16
|
-
'x-component-props':
|
|
17
|
-
useProps: '{{ useTriggerWorkflowsActionProps }}',
|
|
18
|
-
},
|
|
16
|
+
'x-use-component-props': 'useTriggerWorkflowsActionProps',
|
|
19
17
|
'x-designer': 'Action.Designer',
|
|
20
18
|
'x-action-settings': {
|
|
21
19
|
// assignedValues: {},
|
|
@@ -38,9 +36,7 @@ const recordTriggerWorkflowActionInitializer: SchemaInitializerItemType = {
|
|
|
38
36
|
schema: {
|
|
39
37
|
title: '{{t("Submit to workflow", { ns: "workflow" })}}',
|
|
40
38
|
'x-component': 'Action',
|
|
41
|
-
'x-component-props':
|
|
42
|
-
useProps: '{{ useRecordTriggerWorkflowsActionProps }}',
|
|
43
|
-
},
|
|
39
|
+
'x-use-component-props': 'useRecordTriggerWorkflowsActionProps',
|
|
44
40
|
'x-designer': 'Action.Designer',
|
|
45
41
|
'x-action-settings': {
|
|
46
42
|
// assignedValues: {},
|
package/src/locale/zh-CN.json
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
2
|
+
"Post-action event": "操作后事件",
|
|
3
|
+
"Triggered after the completion of a request initiated through an action button or API, such as after adding, updating, deleting data, or \"submit to workflow\". Suitable for data processing, sending notifications, etc., after actions are completed.":
|
|
4
|
+
"通过操作按钮或 API 发起请求并在执行完成后触发,比如新增、更新、删除数据或者“提交至工作流”之后。适用于在操作完成后进行数据处理、发送通知等。",
|
|
4
5
|
"Collection": "数据表",
|
|
5
|
-
"
|
|
6
|
+
"The collection to which the triggered data belongs.": "触发数据所属的数据表。",
|
|
7
|
+
"Trigger mode": "触发模式",
|
|
8
|
+
"Local mode, triggered after the completion of actions bound to this workflow": "局部模式,绑定该工作流的操作执行完成后触发",
|
|
9
|
+
"Global mode, triggered after the completion of the following actions": "全局模式,以下操作执行完成后都触发",
|
|
10
|
+
"Action to submit to workflow directly is only supported on bound buttons, and will not be affected under global mode.": "直接提交至工作流的操作仅支持使用按钮绑定,不受全局模式的影响。",
|
|
11
|
+
"Select actions": "选择操作",
|
|
12
|
+
"Create record action": "创建记录操作",
|
|
13
|
+
"Update record action": "更新记录操作",
|
|
6
14
|
"Associations to use": "待使用的关系数据",
|
|
7
15
|
"Trigger data": "触发器数据",
|
|
8
16
|
"User submitted action": "提交操作的用户",
|
|
@@ -5,18 +5,20 @@ import Application, { DefaultContext } from '@nocobase/server';
|
|
|
5
5
|
import { Context as ActionContext, Next } from '@nocobase/actions';
|
|
6
6
|
|
|
7
7
|
import WorkflowPlugin, { Trigger, WorkflowModel, toJSON } from '@nocobase/plugin-workflow';
|
|
8
|
-
import { parseCollectionName } from '@nocobase/data-source-manager';
|
|
8
|
+
import { joinCollectionName, parseCollectionName } from '@nocobase/data-source-manager';
|
|
9
9
|
|
|
10
10
|
interface Context extends ActionContext, DefaultContext {}
|
|
11
11
|
|
|
12
12
|
export default class extends Trigger {
|
|
13
|
+
static TYPE = 'action';
|
|
14
|
+
|
|
13
15
|
constructor(workflow: WorkflowPlugin) {
|
|
14
16
|
super(workflow);
|
|
15
17
|
|
|
16
18
|
workflow.app.use(this.middleware, { after: 'dataSource' });
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
async
|
|
21
|
+
async workflowTriggerAction(context: Context, next: Next) {
|
|
20
22
|
const { triggerWorkflows } = context.action.params;
|
|
21
23
|
|
|
22
24
|
if (!triggerWorkflows) {
|
|
@@ -26,37 +28,33 @@ export default class extends Trigger {
|
|
|
26
28
|
context.status = 202;
|
|
27
29
|
await next();
|
|
28
30
|
|
|
29
|
-
this.
|
|
31
|
+
return this.collectionTriggerAction(context);
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
middleware = async (context: Context, next: Next) => {
|
|
33
|
-
const {
|
|
34
|
-
resourceName,
|
|
35
|
-
actionName,
|
|
36
|
-
params: { triggerWorkflows },
|
|
37
|
-
} = context.action;
|
|
35
|
+
const { resourceName, actionName } = context.action;
|
|
38
36
|
|
|
39
37
|
if (resourceName === 'workflows' && actionName === 'trigger') {
|
|
40
|
-
return this.
|
|
38
|
+
return this.workflowTriggerAction(context, next);
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
await next();
|
|
44
42
|
|
|
45
|
-
if (!triggerWorkflows) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
43
|
if (!['create', 'update'].includes(actionName)) {
|
|
50
44
|
return;
|
|
51
45
|
}
|
|
52
46
|
|
|
53
|
-
return this.
|
|
47
|
+
return this.collectionTriggerAction(context);
|
|
54
48
|
};
|
|
55
49
|
|
|
56
|
-
private async
|
|
57
|
-
const {
|
|
50
|
+
private async collectionTriggerAction(context: Context) {
|
|
51
|
+
const {
|
|
52
|
+
resourceName,
|
|
53
|
+
actionName,
|
|
54
|
+
params: { triggerWorkflows = '', values },
|
|
55
|
+
} = context.action;
|
|
58
56
|
const dataSourceHeader = context.get('x-data-source') || 'main';
|
|
59
|
-
|
|
57
|
+
const fullCollectionName = joinCollectionName(dataSourceHeader, resourceName);
|
|
60
58
|
const { currentUser, currentRole } = context.state;
|
|
61
59
|
const { model: UserModel } = this.workflow.db.getCollection('users');
|
|
62
60
|
const userInfo = {
|
|
@@ -65,23 +63,41 @@ export default class extends Trigger {
|
|
|
65
63
|
};
|
|
66
64
|
|
|
67
65
|
const triggers = triggerWorkflows.split(',').map((trigger) => trigger.split('!'));
|
|
68
|
-
const
|
|
69
|
-
const workflows = (
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
})
|
|
78
|
-
|
|
66
|
+
const triggersKeysMap = new Map<string, string>(triggers);
|
|
67
|
+
const workflows = Array.from(this.workflow.enabledCache.values()).filter(
|
|
68
|
+
(item) => item.type === 'action' && item.config.collection,
|
|
69
|
+
);
|
|
70
|
+
const globalWorkflows = new Map();
|
|
71
|
+
const localWorkflows = new Map();
|
|
72
|
+
workflows.forEach((item) => {
|
|
73
|
+
if (resourceName === 'workflows' && actionName === 'trigger') {
|
|
74
|
+
localWorkflows.set(item.key, item);
|
|
75
|
+
} else if (item.config.collection === fullCollectionName) {
|
|
76
|
+
if (item.config.global) {
|
|
77
|
+
if (item.config.actions?.includes(actionName)) {
|
|
78
|
+
globalWorkflows.set(item.key, item);
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
localWorkflows.set(item.key, item);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
const triggeringLocalWorkflows = [];
|
|
86
|
+
const uniqueTriggersMap = new Map();
|
|
87
|
+
triggers.forEach((trigger) => {
|
|
88
|
+
const [key] = trigger;
|
|
89
|
+
const workflow = localWorkflows.get(key);
|
|
90
|
+
if (workflow && !uniqueTriggersMap.has(key)) {
|
|
91
|
+
triggeringLocalWorkflows.push(workflow);
|
|
92
|
+
uniqueTriggersMap.set(key, true);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
79
95
|
const syncGroup = [];
|
|
80
96
|
const asyncGroup = [];
|
|
81
|
-
for (const workflow of
|
|
97
|
+
for (const workflow of triggeringLocalWorkflows.concat(...globalWorkflows.values())) {
|
|
82
98
|
const { collection, appends = [] } = workflow.config;
|
|
83
99
|
const [dataSourceName, collectionName] = parseCollectionName(collection);
|
|
84
|
-
const
|
|
100
|
+
const dataPath = triggersKeysMap.get(workflow.key);
|
|
85
101
|
const event = [workflow];
|
|
86
102
|
if (context.action.resourceName !== 'workflows') {
|
|
87
103
|
if (!context.body) {
|
|
@@ -93,9 +109,12 @@ export default class extends Trigger {
|
|
|
93
109
|
const { body: data } = context;
|
|
94
110
|
for (const row of Array.isArray(data) ? data : [data]) {
|
|
95
111
|
let payload = row;
|
|
96
|
-
if (
|
|
97
|
-
const paths =
|
|
112
|
+
if (dataPath) {
|
|
113
|
+
const paths = dataPath.split('.');
|
|
98
114
|
for (const field of paths) {
|
|
115
|
+
if (!payload) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
99
118
|
if (payload.get(field)) {
|
|
100
119
|
payload = payload.get(field);
|
|
101
120
|
} else {
|
|
@@ -104,37 +123,32 @@ export default class extends Trigger {
|
|
|
104
123
|
}
|
|
105
124
|
}
|
|
106
125
|
}
|
|
107
|
-
const model = payload.constructor;
|
|
108
126
|
if (payload instanceof Model) {
|
|
127
|
+
const model = payload.constructor as unknown as Model;
|
|
109
128
|
if (collectionName !== model.collection.name) {
|
|
110
129
|
continue;
|
|
111
130
|
}
|
|
112
131
|
if (appends.length) {
|
|
113
132
|
payload = await model.collection.repository.findOne({
|
|
114
|
-
filterByTk: payload.get(model.
|
|
133
|
+
filterByTk: payload.get(model.collection.filterTargetKey),
|
|
115
134
|
appends,
|
|
116
135
|
});
|
|
117
136
|
}
|
|
118
137
|
}
|
|
119
|
-
// this.workflow.trigger(workflow, { data: toJSON(payload), ...userInfo });
|
|
120
138
|
event.push({ data: toJSON(payload), ...userInfo });
|
|
121
139
|
}
|
|
122
140
|
} else {
|
|
123
|
-
const {
|
|
141
|
+
const { filterTargetKey, repository } = (<Application>context.app).dataSourceManager.dataSources
|
|
124
142
|
.get(dataSourceName)
|
|
125
143
|
.collectionManager.getCollection(collectionName);
|
|
126
|
-
let data =
|
|
127
|
-
const pk = get(data,
|
|
144
|
+
let data = dataPath ? get(values, dataPath) : values;
|
|
145
|
+
const pk = get(data, filterTargetKey);
|
|
128
146
|
if (appends.length && pk != null) {
|
|
129
147
|
data = await repository.findOne({
|
|
130
148
|
filterByTk: pk,
|
|
131
149
|
appends,
|
|
132
150
|
});
|
|
133
151
|
}
|
|
134
|
-
// this.workflow.trigger(workflow, {
|
|
135
|
-
// data,
|
|
136
|
-
// ...userInfo,
|
|
137
|
-
// });
|
|
138
152
|
event.push({ data, ...userInfo });
|
|
139
153
|
}
|
|
140
154
|
(workflow.sync ? syncGroup : asyncGroup).push(event);
|
|
@@ -572,6 +572,126 @@ describe('workflow > action-trigger', () => {
|
|
|
572
572
|
});
|
|
573
573
|
});
|
|
574
574
|
|
|
575
|
+
describe('global workflow', () => {
|
|
576
|
+
it('no action configured should not be triggered', async () => {
|
|
577
|
+
const workflow = await WorkflowModel.create({
|
|
578
|
+
enabled: true,
|
|
579
|
+
type: 'action',
|
|
580
|
+
config: {
|
|
581
|
+
collection: 'posts',
|
|
582
|
+
global: true,
|
|
583
|
+
},
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
const res1 = await userAgents[0].resource('posts').create({
|
|
587
|
+
values: { title: 't1' },
|
|
588
|
+
});
|
|
589
|
+
expect(res1.status).toBe(200);
|
|
590
|
+
|
|
591
|
+
await sleep(500);
|
|
592
|
+
|
|
593
|
+
const e1 = await workflow.getExecutions();
|
|
594
|
+
expect(e1.length).toBe(0);
|
|
595
|
+
|
|
596
|
+
const res2 = await userAgents[0].resource('posts').create({
|
|
597
|
+
values: { title: 't1' },
|
|
598
|
+
triggerWorkflows: `${workflow.key}`,
|
|
599
|
+
});
|
|
600
|
+
expect(res2.status).toBe(200);
|
|
601
|
+
|
|
602
|
+
await sleep(500);
|
|
603
|
+
|
|
604
|
+
const e2 = await workflow.getExecutions();
|
|
605
|
+
expect(e2.length).toBe(0);
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
it('trigger on both create and update actions', async () => {
|
|
609
|
+
const workflow = await WorkflowModel.create({
|
|
610
|
+
enabled: true,
|
|
611
|
+
type: 'action',
|
|
612
|
+
config: {
|
|
613
|
+
collection: 'posts',
|
|
614
|
+
global: true,
|
|
615
|
+
actions: ['create', 'update'],
|
|
616
|
+
},
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
const res1 = await userAgents[0].resource('posts').create({
|
|
620
|
+
values: { title: 't1' },
|
|
621
|
+
});
|
|
622
|
+
expect(res1.status).toBe(200);
|
|
623
|
+
|
|
624
|
+
await sleep(500);
|
|
625
|
+
|
|
626
|
+
const e1 = await workflow.getExecutions();
|
|
627
|
+
expect(e1.length).toBe(1);
|
|
628
|
+
expect(e1[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
629
|
+
expect(e1[0].context.data).toMatchObject({ title: 't1' });
|
|
630
|
+
|
|
631
|
+
const res2 = await userAgents[0].resource('posts').update({
|
|
632
|
+
filterByTk: res1.body.data.id,
|
|
633
|
+
values: { title: 't2' },
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
await sleep(500);
|
|
637
|
+
|
|
638
|
+
const e2 = await workflow.getExecutions({ order: [['id', 'ASC']] });
|
|
639
|
+
expect(e2.length).toBe(2);
|
|
640
|
+
expect(e2[1].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
641
|
+
expect(e2[1].context.data).toMatchObject({ title: 't2' });
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
it('trigger on action when bound to button', async () => {
|
|
645
|
+
const workflow = await WorkflowModel.create({
|
|
646
|
+
enabled: true,
|
|
647
|
+
type: 'action',
|
|
648
|
+
config: {
|
|
649
|
+
collection: 'posts',
|
|
650
|
+
global: true,
|
|
651
|
+
actions: ['create', 'update'],
|
|
652
|
+
},
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
const res1 = await userAgents[0].resource('posts').create({
|
|
656
|
+
values: { title: 't1' },
|
|
657
|
+
triggerWorkflows: `${workflow.key}`,
|
|
658
|
+
});
|
|
659
|
+
expect(res1.status).toBe(200);
|
|
660
|
+
|
|
661
|
+
await sleep(500);
|
|
662
|
+
|
|
663
|
+
const e1 = await workflow.getExecutions();
|
|
664
|
+
expect(e1.length).toBe(1);
|
|
665
|
+
expect(e1[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
666
|
+
expect(e1[0].context.data).toMatchObject({ title: 't1' });
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
it('trigger on action directly submit to workflow', async () => {
|
|
670
|
+
const workflow = await WorkflowModel.create({
|
|
671
|
+
enabled: true,
|
|
672
|
+
type: 'action',
|
|
673
|
+
config: {
|
|
674
|
+
collection: 'posts',
|
|
675
|
+
global: true,
|
|
676
|
+
actions: ['create', 'update'],
|
|
677
|
+
},
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
const res1 = await userAgents[0].resource('workflows').trigger({
|
|
681
|
+
values: { title: 't1' },
|
|
682
|
+
triggerWorkflows: `${workflow.key}`,
|
|
683
|
+
});
|
|
684
|
+
expect(res1.status).toBe(202);
|
|
685
|
+
|
|
686
|
+
await sleep(500);
|
|
687
|
+
|
|
688
|
+
const e1 = await workflow.getExecutions();
|
|
689
|
+
expect(e1.length).toBe(1);
|
|
690
|
+
expect(e1[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
691
|
+
expect(e1[0].context.data).toMatchObject({ title: 't1' });
|
|
692
|
+
});
|
|
693
|
+
});
|
|
694
|
+
|
|
575
695
|
describe('multiple data source', () => {
|
|
576
696
|
it('trigger on different data source', async () => {
|
|
577
697
|
const workflow = await WorkflowModel.create({
|