@nocobase/plugin-workflow-action-trigger 1.0.0-alpha.2 → 1.0.0-alpha.3
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 +8 -0
- package/dist/client/index.d.ts +8 -0
- package/dist/client/index.js +9 -0
- package/dist/externalVersion.js +18 -9
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/locale/index.d.ts +8 -0
- package/dist/locale/index.js +9 -0
- package/dist/server/ActionTrigger.d.ts +8 -0
- package/dist/server/ActionTrigger.js +9 -0
- package/dist/server/Plugin.d.ts +8 -0
- package/dist/server/Plugin.js +9 -0
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.js +9 -0
- package/dist/server/migrations/20240307215012-change-name.d.ts +8 -0
- package/dist/server/migrations/20240307215012-change-name.js +9 -0
- package/package.json +2 -2
- package/src/client/ActionTrigger.tsx +0 -213
- package/src/client/__e2e__/configuration.test.ts +0 -675
- package/src/client/__e2e__/workflowCRUD.test.ts +0 -178
- package/src/client/index.ts +0 -96
- package/src/index.ts +0 -2
- package/src/locale/en-US.json +0 -9
- package/src/locale/index.ts +0 -12
- package/src/locale/ko_KR.json +0 -9
- package/src/locale/zh-CN.json +0 -18
- package/src/server/ActionTrigger.ts +0 -177
- package/src/server/Plugin.ts +0 -11
- package/src/server/__tests__/trigger.test.ts +0 -778
- package/src/server/index.ts +0 -1
- package/src/server/migrations/20240307215012-change-name.ts +0 -22
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { faker } from '@faker-js/faker';
|
|
2
|
-
import {
|
|
3
|
-
CreateWorkFlow,
|
|
4
|
-
EditWorkFlow,
|
|
5
|
-
FormEventTriggerNode,
|
|
6
|
-
WorkflowListRecords,
|
|
7
|
-
apiCreateRecordTriggerFormEvent,
|
|
8
|
-
apiCreateWorkflow,
|
|
9
|
-
apiDeleteWorkflow,
|
|
10
|
-
apiGetWorkflow,
|
|
11
|
-
apiUpdateWorkflowTrigger,
|
|
12
|
-
appendJsonCollectionName,
|
|
13
|
-
generalWithNoRelationalFields,
|
|
14
|
-
} from '@nocobase/plugin-workflow-test/e2e';
|
|
15
|
-
import { expect, test } from '@nocobase/test/e2e';
|
|
16
|
-
import { dayjs } from '@nocobase/utils';
|
|
17
|
-
|
|
18
|
-
test.describe('Filter', () => {
|
|
19
|
-
test('filter workflow name', async ({ page }) => {
|
|
20
|
-
//添加工作流
|
|
21
|
-
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
22
|
-
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
23
|
-
const workflowData = {
|
|
24
|
-
current: true,
|
|
25
|
-
options: { deleteExecutionOnStatus: [] },
|
|
26
|
-
title: workFlowName,
|
|
27
|
-
type: 'action',
|
|
28
|
-
enabled: true,
|
|
29
|
-
};
|
|
30
|
-
const workflow = await apiCreateWorkflow(workflowData);
|
|
31
|
-
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
32
|
-
const workflowId = workflowObj.id;
|
|
33
|
-
|
|
34
|
-
// 2、筛选工作流
|
|
35
|
-
await page.goto('/admin/settings/workflow');
|
|
36
|
-
await page.waitForLoadState('networkidle');
|
|
37
|
-
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
|
|
38
|
-
await page.getByRole('textbox').fill(workFlowName);
|
|
39
|
-
await page.getByRole('button', { name: 'Submit' }).click();
|
|
40
|
-
|
|
41
|
-
// 3、预期结果:列表中出现筛选的工作流
|
|
42
|
-
await expect(page.getByText(workFlowName)).toBeAttached();
|
|
43
|
-
|
|
44
|
-
// 4、后置处理:删除工作流
|
|
45
|
-
await apiDeleteWorkflow(workflowId);
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test.describe('Add new', () => {
|
|
50
|
-
test('add new Action event', async ({ page }) => {
|
|
51
|
-
// 添加工作流
|
|
52
|
-
await page.goto('/admin/settings/workflow');
|
|
53
|
-
await page.waitForLoadState('networkidle');
|
|
54
|
-
await page.getByLabel('action-Action-Add new-workflows').click();
|
|
55
|
-
const createWorkFlow = new CreateWorkFlow(page);
|
|
56
|
-
const workFlowName = faker.string.alphanumeric(5);
|
|
57
|
-
await createWorkFlow.name.fill(workFlowName);
|
|
58
|
-
await createWorkFlow.triggerType.click();
|
|
59
|
-
await page.getByTitle('Post-action event').click();
|
|
60
|
-
await page.getByLabel('action-Action-Submit-workflows').click();
|
|
61
|
-
|
|
62
|
-
// 3、预期结果:列表中出现新建的工作流
|
|
63
|
-
await expect(page.getByText(workFlowName)).toBeVisible();
|
|
64
|
-
|
|
65
|
-
// 4、后置处理:删除工作流
|
|
66
|
-
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
|
|
67
|
-
await page.getByRole('textbox').fill(workFlowName);
|
|
68
|
-
await page.getByRole('button', { name: 'Submit' }).click();
|
|
69
|
-
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
|
|
70
|
-
await page.getByRole('button', { name: 'OK', exact: true }).click();
|
|
71
|
-
await expect(page.getByText(workFlowName)).toBeHidden();
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test.describe('Sync', () => {});
|
|
76
|
-
|
|
77
|
-
test.describe('Delete', () => {
|
|
78
|
-
test('delete Action event', async ({ page }) => {
|
|
79
|
-
//添加工作流
|
|
80
|
-
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
81
|
-
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
82
|
-
const workflowData = {
|
|
83
|
-
current: true,
|
|
84
|
-
options: { deleteExecutionOnStatus: [] },
|
|
85
|
-
title: workFlowName,
|
|
86
|
-
type: 'action',
|
|
87
|
-
enabled: true,
|
|
88
|
-
};
|
|
89
|
-
const workflow = await apiCreateWorkflow(workflowData);
|
|
90
|
-
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
91
|
-
const workflowId = workflowObj.id;
|
|
92
|
-
|
|
93
|
-
// 删除工作流
|
|
94
|
-
await page.goto('/admin/settings/workflow');
|
|
95
|
-
await page.waitForLoadState('networkidle');
|
|
96
|
-
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
|
|
97
|
-
await page.getByRole('textbox').fill(workFlowName);
|
|
98
|
-
await page.getByRole('button', { name: 'Submit' }).click();
|
|
99
|
-
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
|
|
100
|
-
await page.getByRole('button', { name: 'OK', exact: true }).click();
|
|
101
|
-
|
|
102
|
-
// 3、预期结果:列表中出现筛选的工作流
|
|
103
|
-
await expect(page.getByText(workFlowName)).toBeHidden();
|
|
104
|
-
|
|
105
|
-
// 4、后置处理:删除工作流
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
test.describe('Edit', () => {
|
|
110
|
-
test('edit Action event name', async ({ page }) => {
|
|
111
|
-
//添加工作流
|
|
112
|
-
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
113
|
-
let workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
114
|
-
const workflowData = {
|
|
115
|
-
current: true,
|
|
116
|
-
options: { deleteExecutionOnStatus: [] },
|
|
117
|
-
title: workFlowName,
|
|
118
|
-
type: 'action',
|
|
119
|
-
enabled: true,
|
|
120
|
-
};
|
|
121
|
-
const workflow = await apiCreateWorkflow(workflowData);
|
|
122
|
-
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
123
|
-
const workflowId = workflowObj.id;
|
|
124
|
-
|
|
125
|
-
// 编辑工作流
|
|
126
|
-
await page.goto('/admin/settings/workflow');
|
|
127
|
-
await page.waitForLoadState('networkidle');
|
|
128
|
-
await page.getByLabel(`action-Action.Link-Edit-workflows-${workFlowName}`).click();
|
|
129
|
-
const editWorkFlow = new EditWorkFlow(page, workFlowName);
|
|
130
|
-
workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
131
|
-
await editWorkFlow.name.fill(workFlowName);
|
|
132
|
-
await page.getByLabel('action-Action-Submit-workflows').click();
|
|
133
|
-
await page.waitForLoadState('networkidle');
|
|
134
|
-
// 3、预期结果:编辑成功,列表中出现编辑后的工作流
|
|
135
|
-
await expect(page.getByText(workFlowName)).toBeAttached();
|
|
136
|
-
|
|
137
|
-
// 4、后置处理:删除工作流
|
|
138
|
-
await apiDeleteWorkflow(workflowId);
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
test.describe('Duplicate', () => {
|
|
143
|
-
test('Duplicate Action event triggers with only unconfigured trigger nodes', async ({ page }) => {
|
|
144
|
-
//添加工作流
|
|
145
|
-
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
146
|
-
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
147
|
-
const workflowData = {
|
|
148
|
-
current: true,
|
|
149
|
-
options: { deleteExecutionOnStatus: [] },
|
|
150
|
-
title: workFlowName,
|
|
151
|
-
type: 'action',
|
|
152
|
-
enabled: true,
|
|
153
|
-
};
|
|
154
|
-
const workflow = await apiCreateWorkflow(workflowData);
|
|
155
|
-
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
156
|
-
const workflowId = workflowObj.id;
|
|
157
|
-
|
|
158
|
-
// 2、复制工作流
|
|
159
|
-
await page.goto('/admin/settings/workflow');
|
|
160
|
-
await page.waitForLoadState('networkidle');
|
|
161
|
-
await page.getByLabel(`action-Action.Link-Duplicate-workflows-${workFlowName}`).click();
|
|
162
|
-
await page.getByLabel(`action-Action-Submit-workflows-${workFlowName}`).click();
|
|
163
|
-
await page.waitForLoadState('networkidle');
|
|
164
|
-
// 3、预期结果:列表中出现筛选的工作流
|
|
165
|
-
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
|
|
166
|
-
await page.getByRole('textbox').fill(workFlowName);
|
|
167
|
-
await page.getByRole('button', { name: 'Submit', exact: true }).click();
|
|
168
|
-
await expect(page.getByText(`${workFlowName} copy`)).toBeAttached();
|
|
169
|
-
|
|
170
|
-
// 4、后置处理:删除工作流
|
|
171
|
-
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName} copy`).click();
|
|
172
|
-
await page.getByRole('button', { name: 'OK', exact: true }).click();
|
|
173
|
-
await expect(page.getByText(`${workFlowName} copy`)).toBeHidden();
|
|
174
|
-
await apiDeleteWorkflow(workflowId);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test.describe('Executed', () => {});
|
package/src/client/index.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { Plugin, SchemaInitializerItemType } from '@nocobase/client';
|
|
2
|
-
import WorkflowPlugin, {
|
|
3
|
-
useRecordTriggerWorkflowsActionProps,
|
|
4
|
-
useTriggerWorkflowsActionProps,
|
|
5
|
-
} from '@nocobase/plugin-workflow/client';
|
|
6
|
-
|
|
7
|
-
import ActionTrigger from './ActionTrigger';
|
|
8
|
-
|
|
9
|
-
const submitToWorkflowActionInitializer: SchemaInitializerItemType = {
|
|
10
|
-
name: 'submitToWorkflow',
|
|
11
|
-
title: '{{t("Submit to workflow", { ns: "workflow" })}}',
|
|
12
|
-
Component: 'CustomizeActionInitializer',
|
|
13
|
-
schema: {
|
|
14
|
-
title: '{{t("Submit to workflow", { ns: "workflow" })}}',
|
|
15
|
-
'x-component': 'Action',
|
|
16
|
-
'x-use-component-props': 'useTriggerWorkflowsActionProps',
|
|
17
|
-
'x-designer': 'Action.Designer',
|
|
18
|
-
'x-action-settings': {
|
|
19
|
-
// assignedValues: {},
|
|
20
|
-
skipValidator: false,
|
|
21
|
-
onSuccess: {
|
|
22
|
-
manualClose: true,
|
|
23
|
-
redirecting: false,
|
|
24
|
-
successMessage: '{{t("Submitted successfully")}}',
|
|
25
|
-
},
|
|
26
|
-
triggerWorkflows: [],
|
|
27
|
-
},
|
|
28
|
-
'x-action': 'customize:triggerWorkflows',
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const recordTriggerWorkflowActionInitializer: SchemaInitializerItemType = {
|
|
33
|
-
name: 'submitToWorkflow',
|
|
34
|
-
title: '{{t("Submit to workflow", { ns: "workflow" })}}',
|
|
35
|
-
Component: 'CustomizeActionInitializer',
|
|
36
|
-
schema: {
|
|
37
|
-
title: '{{t("Submit to workflow", { ns: "workflow" })}}',
|
|
38
|
-
'x-component': 'Action',
|
|
39
|
-
'x-use-component-props': 'useRecordTriggerWorkflowsActionProps',
|
|
40
|
-
'x-designer': 'Action.Designer',
|
|
41
|
-
'x-action-settings': {
|
|
42
|
-
// assignedValues: {},
|
|
43
|
-
onSuccess: {
|
|
44
|
-
manualClose: true,
|
|
45
|
-
redirecting: false,
|
|
46
|
-
successMessage: '{{t("Submitted successfully")}}',
|
|
47
|
-
},
|
|
48
|
-
triggerWorkflows: [],
|
|
49
|
-
},
|
|
50
|
-
'x-action': 'customize:triggerWorkflows',
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const recordTriggerWorkflowActionLinkInitializer = {
|
|
55
|
-
...recordTriggerWorkflowActionInitializer,
|
|
56
|
-
schema: {
|
|
57
|
-
...recordTriggerWorkflowActionInitializer.schema,
|
|
58
|
-
'x-component': 'Action.Link',
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export default class extends Plugin {
|
|
63
|
-
async load() {
|
|
64
|
-
const workflow = this.app.pm.get('workflow') as WorkflowPlugin;
|
|
65
|
-
workflow.registerTrigger('action', ActionTrigger);
|
|
66
|
-
|
|
67
|
-
this.app.addScopes({
|
|
68
|
-
useTriggerWorkflowsActionProps,
|
|
69
|
-
useRecordTriggerWorkflowsActionProps,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
const FormActionInitializers = this.app.schemaInitializerManager.get('FormActionInitializers');
|
|
73
|
-
FormActionInitializers.add('customize.submitToWorkflow', submitToWorkflowActionInitializer);
|
|
74
|
-
|
|
75
|
-
const CreateFormActionInitializers = this.app.schemaInitializerManager.get('createForm:configureActions');
|
|
76
|
-
CreateFormActionInitializers.add('customize.submitToWorkflow', submitToWorkflowActionInitializer);
|
|
77
|
-
|
|
78
|
-
const UpdateFormActionInitializers = this.app.schemaInitializerManager.get('editForm:configureActions');
|
|
79
|
-
UpdateFormActionInitializers.add('customize.submitToWorkflow', submitToWorkflowActionInitializer);
|
|
80
|
-
|
|
81
|
-
const DetailsActionInitializers = this.app.schemaInitializerManager.get('detailsWithPaging:configureActions');
|
|
82
|
-
DetailsActionInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionInitializer);
|
|
83
|
-
|
|
84
|
-
const ReadPrettyFormActionInitializers = this.app.schemaInitializerManager.get('details:configureActions');
|
|
85
|
-
ReadPrettyFormActionInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionInitializer);
|
|
86
|
-
|
|
87
|
-
const TableActionColumnInitializers = this.app.schemaInitializerManager.get('table:configureItemActions');
|
|
88
|
-
TableActionColumnInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionLinkInitializer);
|
|
89
|
-
|
|
90
|
-
const GridCardItemActionInitializers = this.app.schemaInitializerManager.get('gridCard:configureItemActions');
|
|
91
|
-
GridCardItemActionInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionLinkInitializer);
|
|
92
|
-
|
|
93
|
-
const ListItemActionInitializers = this.app.schemaInitializerManager.get('list:configureItemActions');
|
|
94
|
-
ListItemActionInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionLinkInitializer);
|
|
95
|
-
}
|
|
96
|
-
}
|
package/src/index.ts
DELETED
package/src/locale/en-US.json
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"Form event": "Form event",
|
|
3
|
-
"Event triggers when submitted a workflow bound form action.": "Event triggers when submitted a workflow bound form action.",
|
|
4
|
-
"Form data model": "Form data model",
|
|
5
|
-
"Use a collection to match form data.": "Use a collection to match form data.",
|
|
6
|
-
"Associations to use": "Associations to use",
|
|
7
|
-
"User submitted form": "User submitted form",
|
|
8
|
-
"Role of user submitted form": "Role of user submitted form"
|
|
9
|
-
}
|
package/src/locale/index.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { useTranslation } from 'react-i18next';
|
|
2
|
-
|
|
3
|
-
export const NAMESPACE = 'workflow-action-trigger';
|
|
4
|
-
|
|
5
|
-
export function useLang(key: string, options = {}) {
|
|
6
|
-
const { t } = usePluginTranslation(options);
|
|
7
|
-
return t(key);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function usePluginTranslation(options) {
|
|
11
|
-
return useTranslation(NAMESPACE, options);
|
|
12
|
-
}
|
package/src/locale/ko_KR.json
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"Form event": "폼 이벤트",
|
|
3
|
-
"Event triggers when submitted a workflow bound form action.": "작업 흐름에 바인딩된 폼 작업이 제출될 때 이벤트가 트리거됩니다.",
|
|
4
|
-
"Form data model": "폼 데이터 모델",
|
|
5
|
-
"Use a collection to match form data.": "폼 데이터를 일치시키기 위해 데이터 테이블을 사용합니다.",
|
|
6
|
-
"Associations to use": "사용할 관련 데이터",
|
|
7
|
-
"User submitted form": "사용자가 제출한 폼",
|
|
8
|
-
"Role of user submitted form": "사용자 제출 폼의 역할"
|
|
9
|
-
}
|
package/src/locale/zh-CN.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
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 发起请求并在执行完成后触发,比如新增、更新、删除数据或者“提交至工作流”之后。适用于在操作完成后进行数据处理、发送通知等。",
|
|
5
|
-
"Collection": "数据表",
|
|
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": "更新记录操作",
|
|
14
|
-
"Associations to use": "待使用的关系数据",
|
|
15
|
-
"Trigger data": "触发器数据",
|
|
16
|
-
"User submitted action": "提交操作的用户",
|
|
17
|
-
"Role of user submitted action": "提交操作用户的角色"
|
|
18
|
-
}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { get } from 'lodash';
|
|
2
|
-
import { BelongsTo, HasOne } from 'sequelize';
|
|
3
|
-
import { Model, modelAssociationByKey } from '@nocobase/database';
|
|
4
|
-
import Application, { DefaultContext } from '@nocobase/server';
|
|
5
|
-
import { Context as ActionContext, Next } from '@nocobase/actions';
|
|
6
|
-
|
|
7
|
-
import WorkflowPlugin, { Trigger, WorkflowModel, toJSON } from '@nocobase/plugin-workflow';
|
|
8
|
-
import { joinCollectionName, parseCollectionName } from '@nocobase/data-source-manager';
|
|
9
|
-
|
|
10
|
-
interface Context extends ActionContext, DefaultContext {}
|
|
11
|
-
|
|
12
|
-
export default class extends Trigger {
|
|
13
|
-
static TYPE = 'action';
|
|
14
|
-
|
|
15
|
-
constructor(workflow: WorkflowPlugin) {
|
|
16
|
-
super(workflow);
|
|
17
|
-
|
|
18
|
-
workflow.app.use(this.middleware, { after: 'dataSource' });
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async workflowTriggerAction(context: Context, next: Next) {
|
|
22
|
-
const { triggerWorkflows } = context.action.params;
|
|
23
|
-
|
|
24
|
-
if (!triggerWorkflows) {
|
|
25
|
-
return context.throw(400);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
context.status = 202;
|
|
29
|
-
await next();
|
|
30
|
-
|
|
31
|
-
return this.collectionTriggerAction(context);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
middleware = async (context: Context, next: Next) => {
|
|
35
|
-
const { resourceName, actionName } = context.action;
|
|
36
|
-
|
|
37
|
-
if (resourceName === 'workflows' && actionName === 'trigger') {
|
|
38
|
-
return this.workflowTriggerAction(context, next);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
await next();
|
|
42
|
-
|
|
43
|
-
if (!['create', 'update'].includes(actionName)) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return this.collectionTriggerAction(context);
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
private async collectionTriggerAction(context: Context) {
|
|
51
|
-
const {
|
|
52
|
-
resourceName,
|
|
53
|
-
actionName,
|
|
54
|
-
params: { triggerWorkflows = '', values },
|
|
55
|
-
} = context.action;
|
|
56
|
-
const dataSourceHeader = context.get('x-data-source') || 'main';
|
|
57
|
-
const collection = context.app.dataSourceManager.dataSources
|
|
58
|
-
.get(dataSourceHeader)
|
|
59
|
-
.collectionManager.getCollection(resourceName);
|
|
60
|
-
|
|
61
|
-
if (!collection) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const fullCollectionName = joinCollectionName(dataSourceHeader, collection.name);
|
|
66
|
-
const { currentUser, currentRole } = context.state;
|
|
67
|
-
const { model: UserModel } = this.workflow.db.getCollection('users');
|
|
68
|
-
const userInfo = {
|
|
69
|
-
user: UserModel.build(currentUser).desensitize(),
|
|
70
|
-
roleName: currentRole,
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const triggers = triggerWorkflows.split(',').map((trigger) => trigger.split('!'));
|
|
74
|
-
const triggersKeysMap = new Map<string, string>(triggers);
|
|
75
|
-
const workflows = Array.from(this.workflow.enabledCache.values()).filter(
|
|
76
|
-
(item) => item.type === 'action' && item.config.collection,
|
|
77
|
-
);
|
|
78
|
-
const globalWorkflows = new Map();
|
|
79
|
-
const localWorkflows = new Map();
|
|
80
|
-
workflows.forEach((item) => {
|
|
81
|
-
if (resourceName === 'workflows' && actionName === 'trigger') {
|
|
82
|
-
localWorkflows.set(item.key, item);
|
|
83
|
-
} else if (item.config.collection === fullCollectionName) {
|
|
84
|
-
if (item.config.global) {
|
|
85
|
-
if (item.config.actions?.includes(actionName)) {
|
|
86
|
-
globalWorkflows.set(item.key, item);
|
|
87
|
-
}
|
|
88
|
-
} else {
|
|
89
|
-
localWorkflows.set(item.key, item);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
const triggeringLocalWorkflows = [];
|
|
94
|
-
const uniqueTriggersMap = new Map();
|
|
95
|
-
triggers.forEach((trigger) => {
|
|
96
|
-
const [key] = trigger;
|
|
97
|
-
const workflow = localWorkflows.get(key);
|
|
98
|
-
if (workflow && !uniqueTriggersMap.has(key)) {
|
|
99
|
-
triggeringLocalWorkflows.push(workflow);
|
|
100
|
-
uniqueTriggersMap.set(key, true);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
const syncGroup = [];
|
|
104
|
-
const asyncGroup = [];
|
|
105
|
-
for (const workflow of triggeringLocalWorkflows.concat(...globalWorkflows.values())) {
|
|
106
|
-
const { appends = [] } = workflow.config;
|
|
107
|
-
const [dataSourceName, collectionName] = parseCollectionName(workflow.config.collection);
|
|
108
|
-
const dataPath = triggersKeysMap.get(workflow.key);
|
|
109
|
-
const event = [workflow];
|
|
110
|
-
if (context.action.resourceName !== 'workflows') {
|
|
111
|
-
if (!context.body) {
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
if (dataSourceName !== dataSourceHeader) {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
const { body: data } = context;
|
|
118
|
-
for (const row of Array.isArray(data) ? data : [data]) {
|
|
119
|
-
let payload = row;
|
|
120
|
-
if (dataPath) {
|
|
121
|
-
const paths = dataPath.split('.');
|
|
122
|
-
for (const field of paths) {
|
|
123
|
-
if (!payload) {
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
126
|
-
if (payload.get(field)) {
|
|
127
|
-
payload = payload.get(field);
|
|
128
|
-
} else {
|
|
129
|
-
const association = <HasOne | BelongsTo>modelAssociationByKey(payload, field);
|
|
130
|
-
payload = await payload[association.accessors.get]();
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
if (payload instanceof Model) {
|
|
135
|
-
const model = payload.constructor as unknown as Model;
|
|
136
|
-
if (collectionName !== model.collection.name) {
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
if (appends.length) {
|
|
140
|
-
payload = await model.collection.repository.findOne({
|
|
141
|
-
filterByTk: payload.get(model.collection.filterTargetKey),
|
|
142
|
-
appends,
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
event.push({ data: toJSON(payload), ...userInfo });
|
|
147
|
-
}
|
|
148
|
-
} else {
|
|
149
|
-
const { filterTargetKey, repository } = (<Application>context.app).dataSourceManager.dataSources
|
|
150
|
-
.get(dataSourceName)
|
|
151
|
-
.collectionManager.getCollection(collectionName);
|
|
152
|
-
let data = dataPath ? get(values, dataPath) : values;
|
|
153
|
-
const pk = get(data, filterTargetKey);
|
|
154
|
-
if (appends.length && pk != null) {
|
|
155
|
-
data = await repository.findOne({
|
|
156
|
-
filterByTk: pk,
|
|
157
|
-
appends,
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
event.push({ data, ...userInfo });
|
|
161
|
-
}
|
|
162
|
-
(workflow.sync ? syncGroup : asyncGroup).push(event);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
for (const event of syncGroup) {
|
|
166
|
-
await this.workflow.trigger(event[0], event[1], { httpContext: context });
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
for (const event of asyncGroup) {
|
|
170
|
-
this.workflow.trigger(event[0], event[1]);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
on(workflow: WorkflowModel) {}
|
|
175
|
-
|
|
176
|
-
off(workflow: WorkflowModel) {}
|
|
177
|
-
}
|
package/src/server/Plugin.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Plugin } from '@nocobase/server';
|
|
2
|
-
import WorkflowPlugin from '@nocobase/plugin-workflow';
|
|
3
|
-
|
|
4
|
-
import ActionTrigger from './ActionTrigger';
|
|
5
|
-
|
|
6
|
-
export default class extends Plugin {
|
|
7
|
-
async load() {
|
|
8
|
-
const workflowPlugin = this.app.pm.get(WorkflowPlugin) as WorkflowPlugin;
|
|
9
|
-
workflowPlugin.triggers.register('action', new ActionTrigger(workflowPlugin));
|
|
10
|
-
}
|
|
11
|
-
}
|