@nocobase/plugin-workflow-manual 0.20.0-alpha.16 → 0.20.0-alpha.17
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/index.js +4 -4
- package/dist/externalVersion.js +9 -9
- package/dist/server/forms/create.d.ts +2 -1
- package/dist/server/forms/create.js +4 -4
- package/dist/server/forms/update.d.ts +2 -1
- package/dist/server/forms/update.js +4 -4
- package/dist/server/migrations/20240325213145-fix-schema.d.ts +4 -0
- package/dist/server/migrations/20240325213145-fix-schema.js +88 -0
- package/package.json +2 -2
- package/src/client/WorkflowTodo.tsx +1 -1
- package/src/client/__e2e__/createRecordForm.test.ts +65 -0
- package/src/client/__e2e__/updateRecordForm.test.ts +53 -0
- package/src/client/__e2e__/workflowTodo.test.ts +9 -0
- package/src/client/instruction/SchemaConfig.tsx +3 -20
- package/src/client/instruction/forms/custom.tsx +32 -13
- package/src/client/instruction/index.tsx +1 -1
- package/src/server/__tests__/data-source.test.ts +223 -0
- package/src/server/__tests__/{instruction.test.ts → form.test.ts} +0 -510
- package/src/server/__tests__/mode.test.ts +561 -0
- package/src/server/forms/create.ts +10 -3
- package/src/server/forms/update.ts +10 -3
- package/src/server/migrations/20240325213145-fix-schema.ts +81 -0
- package/dist/client/instruction/DetailsBlockProvider.d.ts +0 -2
- package/src/client/instruction/DetailsBlockProvider.tsx +0 -87
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
apiUpdateWorkflowTrigger,
|
|
11
11
|
appendJsonCollectionName,
|
|
12
12
|
generalWithNoRelationalFields,
|
|
13
|
+
apiGetDataSourceCount,
|
|
13
14
|
} from '@nocobase/plugin-workflow-test/e2e';
|
|
14
15
|
import { expect, test } from '@nocobase/test/e2e';
|
|
15
16
|
import { dayjs } from '@nocobase/utils';
|
|
@@ -97,6 +98,10 @@ test.describe('field data update', () => {
|
|
|
97
98
|
await manualNode.configureUserInterfaceButton.click();
|
|
98
99
|
await manualNode.addBlockButton.hover();
|
|
99
100
|
await manualNode.updateRecordFormMenu.hover();
|
|
101
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
102
|
+
if (dataSourcesCount > 1) {
|
|
103
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
104
|
+
}
|
|
100
105
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
101
106
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
102
107
|
await page
|
|
@@ -249,6 +254,10 @@ test.describe('field data update', () => {
|
|
|
249
254
|
await manualNode.configureUserInterfaceButton.click();
|
|
250
255
|
await manualNode.addBlockButton.hover();
|
|
251
256
|
await manualNode.updateRecordFormMenu.hover();
|
|
257
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
258
|
+
if (dataSourcesCount > 1) {
|
|
259
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
260
|
+
}
|
|
252
261
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
253
262
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
254
263
|
await page
|
|
@@ -401,6 +410,10 @@ test.describe('field data update', () => {
|
|
|
401
410
|
await manualNode.configureUserInterfaceButton.click();
|
|
402
411
|
await manualNode.addBlockButton.hover();
|
|
403
412
|
await manualNode.updateRecordFormMenu.hover();
|
|
413
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
414
|
+
if (dataSourcesCount > 1) {
|
|
415
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
416
|
+
}
|
|
404
417
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
405
418
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
406
419
|
await page
|
|
@@ -553,6 +566,10 @@ test.describe('field data update', () => {
|
|
|
553
566
|
await manualNode.configureUserInterfaceButton.click();
|
|
554
567
|
await manualNode.addBlockButton.hover();
|
|
555
568
|
await manualNode.updateRecordFormMenu.hover();
|
|
569
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
570
|
+
if (dataSourcesCount > 1) {
|
|
571
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
572
|
+
}
|
|
556
573
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
557
574
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
558
575
|
await page
|
|
@@ -705,6 +722,10 @@ test.describe('field data update', () => {
|
|
|
705
722
|
await manualNode.configureUserInterfaceButton.click();
|
|
706
723
|
await manualNode.addBlockButton.hover();
|
|
707
724
|
await manualNode.updateRecordFormMenu.hover();
|
|
725
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
726
|
+
if (dataSourcesCount > 1) {
|
|
727
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
728
|
+
}
|
|
708
729
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
709
730
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
710
731
|
await page
|
|
@@ -857,6 +878,10 @@ test.describe('field data update', () => {
|
|
|
857
878
|
await manualNode.configureUserInterfaceButton.click();
|
|
858
879
|
await manualNode.addBlockButton.hover();
|
|
859
880
|
await manualNode.updateRecordFormMenu.hover();
|
|
881
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
882
|
+
if (dataSourcesCount > 1) {
|
|
883
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
884
|
+
}
|
|
860
885
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
861
886
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
862
887
|
await page
|
|
@@ -1025,6 +1050,10 @@ test.describe('field data update', () => {
|
|
|
1025
1050
|
await manualNode.configureUserInterfaceButton.click();
|
|
1026
1051
|
await manualNode.addBlockButton.hover();
|
|
1027
1052
|
await manualNode.updateRecordFormMenu.hover();
|
|
1053
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
1054
|
+
if (dataSourcesCount > 1) {
|
|
1055
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
1056
|
+
}
|
|
1028
1057
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
1029
1058
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
1030
1059
|
await page
|
|
@@ -1193,6 +1222,10 @@ test.describe('field data update', () => {
|
|
|
1193
1222
|
await manualNode.configureUserInterfaceButton.click();
|
|
1194
1223
|
await manualNode.addBlockButton.hover();
|
|
1195
1224
|
await manualNode.updateRecordFormMenu.hover();
|
|
1225
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
1226
|
+
if (dataSourcesCount > 1) {
|
|
1227
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
1228
|
+
}
|
|
1196
1229
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
1197
1230
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
1198
1231
|
await page
|
|
@@ -1361,6 +1394,10 @@ test.describe('field data update', () => {
|
|
|
1361
1394
|
await manualNode.configureUserInterfaceButton.click();
|
|
1362
1395
|
await manualNode.addBlockButton.hover();
|
|
1363
1396
|
await manualNode.updateRecordFormMenu.hover();
|
|
1397
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
1398
|
+
if (dataSourcesCount > 1) {
|
|
1399
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
1400
|
+
}
|
|
1364
1401
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
1365
1402
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
1366
1403
|
await page
|
|
@@ -1530,6 +1567,10 @@ test.describe('field data update', () => {
|
|
|
1530
1567
|
await manualNode.configureUserInterfaceButton.click();
|
|
1531
1568
|
await manualNode.addBlockButton.hover();
|
|
1532
1569
|
await manualNode.updateRecordFormMenu.hover();
|
|
1570
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
1571
|
+
if (dataSourcesCount > 1) {
|
|
1572
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
1573
|
+
}
|
|
1533
1574
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
1534
1575
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
1535
1576
|
await page
|
|
@@ -1707,6 +1748,10 @@ test.describe('field data update', () => {
|
|
|
1707
1748
|
await manualNode.configureUserInterfaceButton.click();
|
|
1708
1749
|
await manualNode.addBlockButton.hover();
|
|
1709
1750
|
await manualNode.updateRecordFormMenu.hover();
|
|
1751
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
1752
|
+
if (dataSourcesCount > 1) {
|
|
1753
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
1754
|
+
}
|
|
1710
1755
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
1711
1756
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
1712
1757
|
await page
|
|
@@ -1875,6 +1920,10 @@ test.describe('field data update', () => {
|
|
|
1875
1920
|
await manualNode.configureUserInterfaceButton.click();
|
|
1876
1921
|
await manualNode.addBlockButton.hover();
|
|
1877
1922
|
await manualNode.updateRecordFormMenu.hover();
|
|
1923
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
1924
|
+
if (dataSourcesCount > 1) {
|
|
1925
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
1926
|
+
}
|
|
1878
1927
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
1879
1928
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
1880
1929
|
await page
|
|
@@ -2049,6 +2098,10 @@ test.describe('field data update', () => {
|
|
|
2049
2098
|
await manualNode.configureUserInterfaceButton.click();
|
|
2050
2099
|
await manualNode.addBlockButton.hover();
|
|
2051
2100
|
await manualNode.updateRecordFormMenu.hover();
|
|
2101
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
2102
|
+
if (dataSourcesCount > 1) {
|
|
2103
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
2104
|
+
}
|
|
2052
2105
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
2053
2106
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
2054
2107
|
await page
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
apiUpdateWorkflowTrigger,
|
|
9
9
|
appendJsonCollectionName,
|
|
10
10
|
generalWithNoRelationalFields,
|
|
11
|
+
apiGetDataSourceCount,
|
|
11
12
|
} from '@nocobase/plugin-workflow-test/e2e';
|
|
12
13
|
import { expect, test } from '@nocobase/test/e2e';
|
|
13
14
|
import { dayjs } from '@nocobase/utils';
|
|
@@ -69,6 +70,10 @@ test('filter task node', async ({ page, mockPage, mockCollections, mockRecords }
|
|
|
69
70
|
await manualNode.configureUserInterfaceButton.click();
|
|
70
71
|
await manualNode.addBlockButton.hover();
|
|
71
72
|
await manualNode.createRecordFormMenu.hover();
|
|
73
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
74
|
+
if (dataSourcesCount > 1) {
|
|
75
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
76
|
+
}
|
|
72
77
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
73
78
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
74
79
|
await page
|
|
@@ -179,6 +184,10 @@ test('filter workflow name', async ({ page, mockPage, mockCollections, mockRecor
|
|
|
179
184
|
await manualNode.configureUserInterfaceButton.click();
|
|
180
185
|
await manualNode.addBlockButton.hover();
|
|
181
186
|
await manualNode.createRecordFormMenu.hover();
|
|
187
|
+
const dataSourcesCount = await apiGetDataSourceCount();
|
|
188
|
+
if (dataSourcesCount > 1) {
|
|
189
|
+
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
190
|
+
}
|
|
182
191
|
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
|
|
183
192
|
await page.mouse.move(300, 0, { steps: 100 });
|
|
184
193
|
await page
|
|
@@ -35,6 +35,8 @@ import {
|
|
|
35
35
|
} from '@nocobase/client';
|
|
36
36
|
import WorkflowPlugin, {
|
|
37
37
|
JOB_STATUS,
|
|
38
|
+
DetailsBlockProvider,
|
|
39
|
+
SimpleDesigner,
|
|
38
40
|
useAvailableUpstreams,
|
|
39
41
|
useFlowContext,
|
|
40
42
|
useNodeContext,
|
|
@@ -44,7 +46,6 @@ import WorkflowPlugin, {
|
|
|
44
46
|
import { Registry, lodash } from '@nocobase/utils/client';
|
|
45
47
|
|
|
46
48
|
import { NAMESPACE, useLang } from '../../locale';
|
|
47
|
-
import { DetailsBlockProvider } from './DetailsBlockProvider';
|
|
48
49
|
import { FormBlockProvider } from './FormBlockProvider';
|
|
49
50
|
import createRecordForm from './forms/create';
|
|
50
51
|
import customRecordForm from './forms/custom';
|
|
@@ -104,24 +105,6 @@ const blockTypeNames = {
|
|
|
104
105
|
record: `{{t("Data record", { ns: "${NAMESPACE}" })}}`,
|
|
105
106
|
};
|
|
106
107
|
|
|
107
|
-
function SimpleDesigner() {
|
|
108
|
-
const schema = useFieldSchema();
|
|
109
|
-
const title = blockTypeNames[schema['x-designer-props']?.type] ?? '{{t("Block")}}';
|
|
110
|
-
const compile = useCompile();
|
|
111
|
-
return (
|
|
112
|
-
<GeneralSchemaDesigner title={compile(title)}>
|
|
113
|
-
<SchemaSettingsBlockTitleItem />
|
|
114
|
-
<SchemaSettingsDivider />
|
|
115
|
-
<SchemaSettingsRemove
|
|
116
|
-
removeParentsIfNoChildren
|
|
117
|
-
breakRemoveOn={{
|
|
118
|
-
'x-component': 'Grid',
|
|
119
|
-
}}
|
|
120
|
-
/>
|
|
121
|
-
</GeneralSchemaDesigner>
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
108
|
/**
|
|
126
109
|
* @deprecated
|
|
127
110
|
*/
|
|
@@ -153,7 +136,7 @@ export const addBlockButton_deprecated = new CompatibleSchemaInitializer({
|
|
|
153
136
|
{
|
|
154
137
|
name: 'nodes',
|
|
155
138
|
type: 'subMenu',
|
|
156
|
-
title: `{{t("Node result", { ns: "
|
|
139
|
+
title: `{{t("Node result", { ns: "workflow" })}}`,
|
|
157
140
|
children: nodeBlockInitializers,
|
|
158
141
|
},
|
|
159
142
|
]
|
|
@@ -3,7 +3,7 @@ import React, { useContext, useMemo, useState } from 'react';
|
|
|
3
3
|
import { ArrayTable } from '@formily/antd-v5';
|
|
4
4
|
import { Field, createForm } from '@formily/core';
|
|
5
5
|
import { useField, useFieldSchema, useForm } from '@formily/react';
|
|
6
|
-
import
|
|
6
|
+
import { cloneDeep, pick, set } from 'lodash';
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
9
|
ActionContextProvider,
|
|
@@ -161,7 +161,7 @@ function getOptions(interfaces) {
|
|
|
161
161
|
const schema = interfaces[type];
|
|
162
162
|
const { group = 'others' } = schema;
|
|
163
163
|
fields[group] = fields[group] || {};
|
|
164
|
-
|
|
164
|
+
set(fields, [group, type], schema);
|
|
165
165
|
});
|
|
166
166
|
|
|
167
167
|
return Object.keys(GroupLabels)
|
|
@@ -208,33 +208,51 @@ const CustomItemsComponent = (props) => {
|
|
|
208
208
|
const items = useCommonInterfaceInitializers();
|
|
209
209
|
const collection = useCollection_deprecated();
|
|
210
210
|
const { setCollectionFields } = useContext(FormBlockContext);
|
|
211
|
+
const form = useMemo(() => createForm(), [interfaceOptions]);
|
|
211
212
|
|
|
212
213
|
return (
|
|
213
214
|
<AddCustomFormFieldButtonContext.Provider
|
|
214
215
|
value={{
|
|
215
216
|
onAddField(item) {
|
|
217
|
+
const fieldInterface: Record<string, any> = pick(item, [
|
|
218
|
+
'name',
|
|
219
|
+
'group',
|
|
220
|
+
'title',
|
|
221
|
+
'default',
|
|
222
|
+
'validateSchema',
|
|
223
|
+
]);
|
|
216
224
|
const {
|
|
217
|
-
properties: { unique, type, ...properties },
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
properties,
|
|
224
|
-
});
|
|
225
|
+
properties: { unique, type, layout, autoIncrement, ...properties },
|
|
226
|
+
} = item;
|
|
227
|
+
fieldInterface.properties = properties;
|
|
228
|
+
const result = cloneDeep(fieldInterface);
|
|
229
|
+
delete result.properties.name['x-disabled'];
|
|
230
|
+
setInterface(result);
|
|
225
231
|
},
|
|
226
232
|
setCallback,
|
|
227
233
|
}}
|
|
228
234
|
>
|
|
229
235
|
<SchemaInitializerItems {...props} items={items} />
|
|
230
|
-
<ActionContextProvider
|
|
236
|
+
<ActionContextProvider
|
|
237
|
+
value={{
|
|
238
|
+
visible: Boolean(interfaceOptions),
|
|
239
|
+
setVisible(v) {
|
|
240
|
+
if (!v) {
|
|
241
|
+
setInterface(null);
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
}}
|
|
245
|
+
>
|
|
231
246
|
{interfaceOptions ? (
|
|
232
247
|
<SchemaComponent
|
|
233
248
|
schema={{
|
|
234
249
|
type: 'void',
|
|
235
250
|
name: 'drawer',
|
|
236
251
|
title: '{{t("Configure field")}}',
|
|
237
|
-
'x-decorator': '
|
|
252
|
+
'x-decorator': 'FormV2',
|
|
253
|
+
'x-decorator-props': {
|
|
254
|
+
form,
|
|
255
|
+
},
|
|
238
256
|
'x-component': 'Action.Drawer',
|
|
239
257
|
properties: {
|
|
240
258
|
...interfaceOptions.properties,
|
|
@@ -266,7 +284,7 @@ const CustomItemsComponent = (props) => {
|
|
|
266
284
|
'x-component-props': {
|
|
267
285
|
type: 'primary',
|
|
268
286
|
useAction() {
|
|
269
|
-
const { values, query } = useForm();
|
|
287
|
+
const { values, query, reset } = useForm();
|
|
270
288
|
const messages = [useLang('Field name existed in form')];
|
|
271
289
|
return {
|
|
272
290
|
async run() {
|
|
@@ -301,6 +319,7 @@ const CustomItemsComponent = (props) => {
|
|
|
301
319
|
'x-toolbar': 'FormItemSchemaToolbar',
|
|
302
320
|
'x-settings': 'fieldSettings:FormItem',
|
|
303
321
|
});
|
|
322
|
+
reset();
|
|
304
323
|
setCallback(null);
|
|
305
324
|
setInterface(null);
|
|
306
325
|
},
|
|
@@ -138,7 +138,7 @@ export default class extends Instruction {
|
|
|
138
138
|
title: form.title ?? formKey,
|
|
139
139
|
Component: CollectionBlockInitializer,
|
|
140
140
|
collection: form.collection,
|
|
141
|
-
|
|
141
|
+
dataPath: `$jobsMapByNodeKey.${node.key}.${formKey}`,
|
|
142
142
|
} as SchemaInitializerItemType)
|
|
143
143
|
: null;
|
|
144
144
|
})
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import Database from '@nocobase/database';
|
|
2
|
+
import { EXECUTION_STATUS, JOB_STATUS } from '@nocobase/plugin-workflow';
|
|
3
|
+
import { getApp, sleep } from '@nocobase/plugin-workflow-test';
|
|
4
|
+
import { MockServer } from '@nocobase/test';
|
|
5
|
+
|
|
6
|
+
// NOTE: skipped because time is not stable on github ci, but should work in local
|
|
7
|
+
describe('workflow > instructions > manual', () => {
|
|
8
|
+
let app: MockServer;
|
|
9
|
+
let agent;
|
|
10
|
+
let userAgents;
|
|
11
|
+
let db: Database;
|
|
12
|
+
let PostRepo;
|
|
13
|
+
let AnotherPostRepo;
|
|
14
|
+
let WorkflowModel;
|
|
15
|
+
let workflow;
|
|
16
|
+
let UserModel;
|
|
17
|
+
let users;
|
|
18
|
+
let UserJobModel;
|
|
19
|
+
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
app = await getApp({
|
|
22
|
+
plugins: ['users', 'auth', 'workflow-manual'],
|
|
23
|
+
});
|
|
24
|
+
// await app.getPlugin('auth').install();
|
|
25
|
+
agent = app.agent();
|
|
26
|
+
db = app.db;
|
|
27
|
+
WorkflowModel = db.getCollection('workflows').model;
|
|
28
|
+
PostRepo = db.getCollection('posts').repository;
|
|
29
|
+
AnotherPostRepo = app.dataSourceManager.dataSources.get('another').collectionManager.getRepository('posts');
|
|
30
|
+
UserModel = db.getCollection('users').model;
|
|
31
|
+
UserJobModel = db.getModel('users_jobs');
|
|
32
|
+
|
|
33
|
+
users = await UserModel.bulkCreate([
|
|
34
|
+
{ id: 2, nickname: 'a' },
|
|
35
|
+
{ id: 3, nickname: 'b' },
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
userAgents = users.map((user) => app.agent().login(user));
|
|
39
|
+
|
|
40
|
+
workflow = await WorkflowModel.create({
|
|
41
|
+
enabled: true,
|
|
42
|
+
type: 'collection',
|
|
43
|
+
config: {
|
|
44
|
+
mode: 1,
|
|
45
|
+
collection: 'posts',
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
afterEach(() => app.destroy());
|
|
51
|
+
|
|
52
|
+
describe('multiple data source', () => {
|
|
53
|
+
describe('create', () => {
|
|
54
|
+
it('create as configured', async () => {
|
|
55
|
+
const n1 = await workflow.createNode({
|
|
56
|
+
type: 'manual',
|
|
57
|
+
config: {
|
|
58
|
+
assignees: [users[0].id],
|
|
59
|
+
forms: {
|
|
60
|
+
f1: {
|
|
61
|
+
type: 'create',
|
|
62
|
+
actions: [{ status: JOB_STATUS.RESOLVED, key: 'resolve' }],
|
|
63
|
+
collection: 'posts',
|
|
64
|
+
dataSource: 'another',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const post = await PostRepo.create({ values: { title: 't1' } });
|
|
71
|
+
|
|
72
|
+
await sleep(500);
|
|
73
|
+
|
|
74
|
+
const UserJobModel = db.getModel('users_jobs');
|
|
75
|
+
const pendingJobs = await UserJobModel.findAll({
|
|
76
|
+
order: [['userId', 'ASC']],
|
|
77
|
+
});
|
|
78
|
+
expect(pendingJobs.length).toBe(1);
|
|
79
|
+
|
|
80
|
+
const res1 = await userAgents[0].resource('users_jobs').submit({
|
|
81
|
+
filterByTk: pendingJobs[0].get('id'),
|
|
82
|
+
values: {
|
|
83
|
+
result: { f1: { title: 't1' }, _: 'resolve' },
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
expect(res1.status).toBe(202);
|
|
87
|
+
|
|
88
|
+
await sleep(500);
|
|
89
|
+
|
|
90
|
+
const [e1] = await workflow.getExecutions();
|
|
91
|
+
expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
92
|
+
const [j1] = await e1.getJobs();
|
|
93
|
+
expect(j1.status).toBe(JOB_STATUS.RESOLVED);
|
|
94
|
+
expect(j1.result).toMatchObject({ f1: { title: 't1' } });
|
|
95
|
+
|
|
96
|
+
const posts = await AnotherPostRepo.find();
|
|
97
|
+
expect(posts.length).toBe(1);
|
|
98
|
+
expect(posts[0]).toMatchObject({ title: 't1' });
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('save first and then commit', async () => {
|
|
102
|
+
const n1 = await workflow.createNode({
|
|
103
|
+
type: 'manual',
|
|
104
|
+
config: {
|
|
105
|
+
assignees: [users[0].id],
|
|
106
|
+
forms: {
|
|
107
|
+
f1: {
|
|
108
|
+
type: 'create',
|
|
109
|
+
actions: [
|
|
110
|
+
{ status: JOB_STATUS.RESOLVED, key: 'resolve' },
|
|
111
|
+
{ status: JOB_STATUS.PENDING, key: 'pending' },
|
|
112
|
+
],
|
|
113
|
+
collection: 'posts',
|
|
114
|
+
dataSource: 'another',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const post = await PostRepo.create({ values: { title: 't1' } });
|
|
121
|
+
|
|
122
|
+
await sleep(500);
|
|
123
|
+
|
|
124
|
+
const UserJobModel = db.getModel('users_jobs');
|
|
125
|
+
const pendingJobs = await UserJobModel.findAll({
|
|
126
|
+
order: [['userId', 'ASC']],
|
|
127
|
+
});
|
|
128
|
+
expect(pendingJobs.length).toBe(1);
|
|
129
|
+
|
|
130
|
+
const res1 = await userAgents[0].resource('users_jobs').submit({
|
|
131
|
+
filterByTk: pendingJobs[0].get('id'),
|
|
132
|
+
values: {
|
|
133
|
+
result: { f1: { title: 't1' }, _: 'pending' },
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
expect(res1.status).toBe(202);
|
|
137
|
+
|
|
138
|
+
await sleep(500);
|
|
139
|
+
|
|
140
|
+
const [e1] = await workflow.getExecutions();
|
|
141
|
+
expect(e1.status).toBe(EXECUTION_STATUS.STARTED);
|
|
142
|
+
const [j1] = await e1.getJobs();
|
|
143
|
+
expect(j1.status).toBe(JOB_STATUS.PENDING);
|
|
144
|
+
expect(j1.result).toMatchObject({ f1: { title: 't1' } });
|
|
145
|
+
|
|
146
|
+
const c1 = await AnotherPostRepo.find();
|
|
147
|
+
expect(c1.length).toBe(0);
|
|
148
|
+
|
|
149
|
+
const res2 = await userAgents[0].resource('users_jobs').submit({
|
|
150
|
+
filterByTk: pendingJobs[0].get('id'),
|
|
151
|
+
values: {
|
|
152
|
+
result: { f1: { title: 't2' }, _: 'resolve' },
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
await sleep(500);
|
|
157
|
+
|
|
158
|
+
const [e2] = await workflow.getExecutions();
|
|
159
|
+
expect(e2.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
160
|
+
const [j2] = await e2.getJobs();
|
|
161
|
+
expect(j2.status).toBe(JOB_STATUS.RESOLVED);
|
|
162
|
+
expect(j2.result).toMatchObject({ f1: { title: 't2' } });
|
|
163
|
+
|
|
164
|
+
const c2 = await AnotherPostRepo.find();
|
|
165
|
+
expect(c2.length).toBe(1);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('update', () => {
|
|
170
|
+
it('update as configured', async () => {
|
|
171
|
+
const post = await AnotherPostRepo.create({ values: { title: 't1' } });
|
|
172
|
+
|
|
173
|
+
const n1 = await workflow.createNode({
|
|
174
|
+
type: 'manual',
|
|
175
|
+
config: {
|
|
176
|
+
assignees: [users[0].id],
|
|
177
|
+
forms: {
|
|
178
|
+
f1: {
|
|
179
|
+
type: 'update',
|
|
180
|
+
actions: [{ status: JOB_STATUS.RESOLVED, key: 'resolve' }],
|
|
181
|
+
collection: 'posts',
|
|
182
|
+
dataSource: 'another',
|
|
183
|
+
filter: {
|
|
184
|
+
id: post.id,
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
await PostRepo.create({ values: { title: 't1' } });
|
|
192
|
+
|
|
193
|
+
await sleep(500);
|
|
194
|
+
|
|
195
|
+
const UserJobModel = db.getModel('users_jobs');
|
|
196
|
+
const pendingJobs = await UserJobModel.findAll({
|
|
197
|
+
order: [['userId', 'ASC']],
|
|
198
|
+
});
|
|
199
|
+
expect(pendingJobs.length).toBe(1);
|
|
200
|
+
|
|
201
|
+
const res1 = await userAgents[0].resource('users_jobs').submit({
|
|
202
|
+
filterByTk: pendingJobs[0].get('id'),
|
|
203
|
+
values: {
|
|
204
|
+
result: { f1: { title: 't2' }, _: 'resolve' },
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
expect(res1.status).toBe(202);
|
|
208
|
+
|
|
209
|
+
await sleep(500);
|
|
210
|
+
|
|
211
|
+
const [e2] = await workflow.getExecutions();
|
|
212
|
+
expect(e2.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
213
|
+
const [j1] = await e2.getJobs();
|
|
214
|
+
expect(j1.status).toBe(JOB_STATUS.RESOLVED);
|
|
215
|
+
expect(j1.result).toMatchObject({ f1: { title: 't2' } });
|
|
216
|
+
|
|
217
|
+
const postsAfter = await AnotherPostRepo.find();
|
|
218
|
+
expect(postsAfter.length).toBe(1);
|
|
219
|
+
expect(postsAfter[0]).toMatchObject({ title: 't2' });
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
});
|