@nocobase/plugin-workflow 0.10.1-alpha.1 → 0.11.1-alpha.1
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/client.d.ts +2 -3
- package/client.js +1 -30
- package/lib/client/AddButton.js +13 -11
- package/lib/client/Branch.js +10 -8
- package/lib/client/CanvasContent.js +12 -10
- package/lib/client/ExecutionCanvas.js +37 -33
- package/lib/client/ExecutionPage.js +4 -9
- package/lib/client/WorkflowCanvas.js +18 -15
- package/lib/client/WorkflowPage.js +4 -9
- package/lib/client/WorkflowProvider.js +1 -40
- package/lib/client/components/CollectionBlockInitializer.js +3 -3
- package/lib/client/components/CollectionFieldset.d.ts +1 -1
- package/lib/client/components/CollectionFieldset.js +15 -16
- package/lib/client/components/Duration.js +5 -5
- package/lib/client/components/DynamicExpression.d.ts +3 -3
- package/lib/client/components/FieldsSelect.d.ts +1 -1
- package/lib/client/components/FieldsSelect.js +10 -7
- package/lib/client/components/NodeDescription.js +45 -31
- package/lib/client/components/RadioWithTooltip.js +13 -20
- package/lib/client/components/ValueBlock.js +14 -21
- package/lib/client/components/renderEngineReference.js +1 -8
- package/lib/client/index.d.ts +12 -4
- package/lib/client/index.js +78 -15
- package/lib/client/locale/zh-CN.d.ts +5 -1
- package/lib/client/locale/zh-CN.js +6 -2
- package/lib/client/nodes/aggregate.d.ts +8 -3
- package/lib/client/nodes/aggregate.js +5 -4
- package/lib/client/nodes/calculation.d.ts +6 -4
- package/lib/client/nodes/calculation.js +22 -28
- package/lib/client/nodes/condition.d.ts +2 -10
- package/lib/client/nodes/condition.js +19 -37
- package/lib/client/nodes/create.d.ts +5 -6
- package/lib/client/nodes/create.js +1 -3
- package/lib/client/nodes/destroy.d.ts +1 -1
- package/lib/client/nodes/index.d.ts +2 -3
- package/lib/client/nodes/index.js +95 -102
- package/lib/client/nodes/loop.d.ts +1 -1
- package/lib/client/nodes/loop.js +46 -54
- package/lib/client/nodes/manual/FormBlockInitializer.js +6 -5
- package/lib/client/nodes/manual/ModeConfig.js +23 -30
- package/lib/client/nodes/manual/SchemaConfig.d.ts +4 -5
- package/lib/client/nodes/manual/SchemaConfig.js +180 -25
- package/lib/client/nodes/manual/WorkflowTodo.js +95 -110
- package/lib/client/nodes/manual/WorkflowTodoBlockInitializer.d.ts +2 -5
- package/lib/client/nodes/manual/WorkflowTodoBlockInitializer.js +6 -5
- package/lib/client/nodes/manual/forms/create.js +8 -1
- package/lib/client/nodes/manual/forms/custom.js +22 -22
- package/lib/client/nodes/manual/forms/update.js +8 -1
- package/lib/client/nodes/manual/index.d.ts +6 -1
- package/lib/client/nodes/manual/index.js +5 -4
- package/lib/client/nodes/parallel.js +23 -20
- package/lib/client/nodes/query.d.ts +3 -5
- package/lib/client/nodes/query.js +1 -3
- package/lib/client/nodes/request.d.ts +2 -2
- package/lib/client/nodes/request.js +7 -7
- package/lib/client/nodes/sql.d.ts +26 -0
- package/lib/client/{triggers/schedule/DateFieldsSelect.js → nodes/sql.js} +37 -46
- package/lib/client/nodes/update.d.ts +2 -2
- package/lib/client/nodes/update.js +1 -1
- package/lib/client/schemas/collection.d.ts +3 -4
- package/lib/client/schemas/collection.js +11 -17
- package/lib/client/style.d.ts +18 -13
- package/lib/client/style.js +315 -292
- package/lib/client/triggers/collection.d.ts +13 -13
- package/lib/client/triggers/collection.js +5 -1
- package/lib/client/triggers/index.d.ts +3 -4
- package/lib/client/triggers/index.js +51 -53
- package/lib/client/triggers/schedule/EndsByField.js +11 -11
- package/lib/client/triggers/schedule/OnField.js +45 -33
- package/lib/client/triggers/schedule/RepeatField.js +4 -4
- package/lib/client/triggers/schedule/ScheduleConfig.js +24 -31
- package/lib/client/triggers/schedule/index.d.ts +1 -1
- package/lib/client/triggers/schedule/index.js +32 -20
- package/lib/client/variable.d.ts +31 -13
- package/lib/client/variable.js +44 -29
- package/lib/server/Plugin.d.ts +3 -6
- package/lib/server/Plugin.js +15 -12
- package/lib/server/Processor.d.ts +3 -5
- package/lib/server/Processor.js +2 -2
- package/lib/server/actions/nodes.js +7 -7
- package/lib/server/fields/expression-field.d.ts +1 -2
- package/lib/server/fields/expression-field.js +1 -8
- package/lib/server/functions/index.d.ts +2 -3
- package/lib/server/index.d.ts +1 -0
- package/lib/server/index.js +12 -0
- package/lib/server/instructions/aggregate.d.ts +1 -1
- package/lib/server/instructions/aggregate.js +5 -5
- package/lib/server/instructions/condition.d.ts +2 -1
- package/lib/server/instructions/create.d.ts +2 -2
- package/lib/server/instructions/create.js +13 -13
- package/lib/server/instructions/delay.d.ts +3 -3
- package/lib/server/instructions/delay.js +66 -64
- package/lib/server/instructions/destroy.d.ts +1 -1
- package/lib/server/instructions/index.d.ts +5 -5
- package/lib/server/instructions/index.js +1 -1
- package/lib/server/instructions/loop.d.ts +1 -2
- package/lib/server/instructions/manual/actions.js +19 -7
- package/lib/server/instructions/manual/forms/create.js +7 -1
- package/lib/server/instructions/manual/forms/index.d.ts +1 -1
- package/lib/server/instructions/manual/forms/update.js +7 -1
- package/lib/server/instructions/manual/index.d.ts +1 -1
- package/lib/server/instructions/parallel.d.ts +1 -2
- package/lib/server/instructions/query.d.ts +1 -1
- package/lib/server/instructions/query.js +8 -1
- package/lib/server/instructions/request.d.ts +3 -3
- package/lib/server/instructions/request.js +5 -2
- package/lib/server/instructions/sql.d.ts +12 -0
- package/lib/server/instructions/sql.js +34 -0
- package/lib/server/instructions/update.d.ts +1 -1
- package/lib/server/migrations/20230221071831-calculation-expression.js +1 -1
- package/lib/server/migrations/20230221121203-condition-calculation.js +1 -1
- package/lib/server/migrations/20230221162902-jsonb-to-json.js +7 -7
- package/lib/server/migrations/20230411034722-manual-multi-form.js +1 -8
- package/lib/server/migrations/20230710115902-manual-action-values.d.ts +4 -0
- package/lib/server/migrations/20230710115902-manual-action-values.js +97 -0
- package/lib/server/triggers/collection.d.ts +1 -1
- package/lib/server/triggers/collection.js +15 -13
- package/lib/server/triggers/index.d.ts +1 -1
- package/lib/server/triggers/schedule.d.ts +1 -1
- package/lib/server/triggers/schedule.js +18 -18
- package/lib/server/{models → types}/Execution.d.ts +2 -3
- package/lib/server/{models → types}/FlowNode.d.ts +1 -2
- package/lib/server/{models → types}/Job.d.ts +1 -2
- package/lib/server/{models → types}/Workflow.d.ts +1 -2
- package/lib/server/types/index.d.ts +4 -0
- package/lib/server/types/index.js +5 -0
- package/lib/server/utils.d.ts +2 -0
- package/lib/server/utils.js +21 -0
- package/package.json +39 -18
- package/server.d.ts +2 -3
- package/server.js +1 -30
- package/src/client/AddButton.tsx +111 -0
- package/src/client/Branch.tsx +37 -0
- package/src/client/CanvasContent.tsx +25 -0
- package/src/client/ExecutionCanvas.tsx +166 -0
- package/src/client/ExecutionLink.tsx +16 -0
- package/src/client/ExecutionPage.tsx +45 -0
- package/src/client/ExecutionResourceProvider.tsx +21 -0
- package/src/client/FlowContext.ts +7 -0
- package/src/client/WorkflowCanvas.tsx +221 -0
- package/src/client/WorkflowLink.tsx +16 -0
- package/src/client/WorkflowPage.tsx +52 -0
- package/src/client/WorkflowProvider.tsx +84 -0
- package/src/client/components/CollectionBlockInitializer.tsx +71 -0
- package/src/client/components/CollectionFieldset.tsx +160 -0
- package/src/client/components/Duration.tsx +45 -0
- package/src/client/components/DynamicExpression.tsx +53 -0
- package/src/client/components/FieldsSelect.tsx +32 -0
- package/src/client/components/FilterDynamicComponent.tsx +15 -0
- package/src/client/components/NodeDescription.tsx +51 -0
- package/src/client/components/NullRender.tsx +3 -0
- package/src/client/components/OpenDrawer.tsx +24 -0
- package/src/client/components/RadioWithTooltip.tsx +38 -0
- package/src/client/components/ValueBlock.tsx +67 -0
- package/src/client/components/renderEngineReference.tsx +30 -0
- package/src/client/constants.tsx +91 -0
- package/src/client/index.tsx +51 -0
- package/src/client/interfaces/expression.tsx +25 -0
- package/src/client/locale/en-US.ts +136 -0
- package/src/client/locale/es-ES.ts +129 -0
- package/src/client/locale/index.ts +18 -0
- package/src/client/locale/ja-JP.ts +90 -0
- package/src/client/locale/pt-BR.ts +136 -0
- package/src/client/locale/ru-RU.ts +90 -0
- package/src/client/locale/tr-TR.ts +90 -0
- package/src/client/locale/zh-CN.ts +248 -0
- package/src/client/nodes/aggregate.tsx +327 -0
- package/src/client/nodes/calculation.tsx +216 -0
- package/src/client/nodes/condition.tsx +463 -0
- package/src/client/nodes/create.tsx +85 -0
- package/src/client/nodes/delay.tsx +37 -0
- package/src/client/nodes/destroy.tsx +34 -0
- package/src/client/nodes/index.tsx +485 -0
- package/src/client/nodes/loop.tsx +144 -0
- package/src/client/nodes/manual/AssigneesSelect.tsx +33 -0
- package/src/client/nodes/manual/DetailsBlockProvider.tsx +80 -0
- package/src/client/nodes/manual/FormBlockInitializer.tsx +69 -0
- package/src/client/nodes/manual/FormBlockProvider.tsx +75 -0
- package/src/client/nodes/manual/ModeConfig.tsx +84 -0
- package/src/client/nodes/manual/SchemaConfig.tsx +509 -0
- package/src/client/nodes/manual/WorkflowTodo.tsx +607 -0
- package/src/client/nodes/manual/WorkflowTodoBlockInitializer.tsx +28 -0
- package/src/client/nodes/manual/forms/create.tsx +92 -0
- package/src/client/nodes/manual/forms/custom.tsx +392 -0
- package/src/client/nodes/manual/forms/update.tsx +134 -0
- package/src/client/nodes/manual/index.tsx +162 -0
- package/src/client/nodes/manual/utils.ts +28 -0
- package/src/client/nodes/parallel.tsx +138 -0
- package/src/client/nodes/query.tsx +88 -0
- package/src/client/nodes/request.tsx +185 -0
- package/src/client/nodes/sql.tsx +37 -0
- package/src/client/nodes/update.tsx +99 -0
- package/src/client/schemas/collection.ts +75 -0
- package/src/client/schemas/executions.tsx +169 -0
- package/src/client/schemas/workflows.ts +364 -0
- package/src/client/style.tsx +347 -0
- package/src/client/triggers/collection.tsx +190 -0
- package/src/client/triggers/index.tsx +311 -0
- package/src/client/triggers/schedule/EndsByField.tsx +40 -0
- package/src/client/triggers/schedule/OnField.tsx +64 -0
- package/src/client/triggers/schedule/RepeatField.tsx +116 -0
- package/src/client/triggers/schedule/ScheduleConfig.tsx +227 -0
- package/src/client/triggers/schedule/constants.ts +4 -0
- package/src/client/triggers/schedule/index.tsx +78 -0
- package/src/client/triggers/schedule/locale/Cron.zh-CN.ts +79 -0
- package/src/client/utils.ts +36 -0
- package/src/client/variable.tsx +318 -0
- package/src/index.ts +1 -0
- package/src/server/Plugin.ts +355 -0
- package/src/server/Processor.ts +354 -0
- package/src/server/__tests__/Plugin.test.ts +398 -0
- package/src/server/__tests__/Processor.test.ts +474 -0
- package/src/server/__tests__/actions/workflows.test.ts +419 -0
- package/src/server/__tests__/collections/categories.ts +27 -0
- package/src/server/__tests__/collections/comments.ts +24 -0
- package/src/server/__tests__/collections/posts.ts +42 -0
- package/src/server/__tests__/collections/replies.ts +9 -0
- package/src/server/__tests__/collections/tags.ts +15 -0
- package/src/server/__tests__/index.ts +89 -0
- package/src/server/__tests__/instructions/aggregate.test.ts +294 -0
- package/src/server/__tests__/instructions/calculation.test.ts +265 -0
- package/src/server/__tests__/instructions/condition.test.ts +335 -0
- package/src/server/__tests__/instructions/create.test.ts +129 -0
- package/src/server/__tests__/instructions/delay.test.ts +182 -0
- package/src/server/__tests__/instructions/destroy.test.ts +58 -0
- package/src/server/__tests__/instructions/loop.test.ts +331 -0
- package/src/server/__tests__/instructions/manual.test.ts +1173 -0
- package/src/server/__tests__/instructions/parallel.test.ts +445 -0
- package/src/server/__tests__/instructions/query.test.ts +359 -0
- package/src/server/__tests__/instructions/request.test.ts +247 -0
- package/src/server/__tests__/instructions/sql.test.ts +162 -0
- package/src/server/__tests__/instructions/update.test.ts +189 -0
- package/src/server/__tests__/triggers/collection.test.ts +333 -0
- package/src/server/__tests__/triggers/schedule.test.ts +369 -0
- package/src/server/actions/index.ts +25 -0
- package/src/server/actions/nodes.ts +214 -0
- package/src/server/actions/workflows.ts +178 -0
- package/src/server/collections/executions.ts +35 -0
- package/src/server/collections/flow_nodes.ts +54 -0
- package/src/server/collections/jobs.ts +31 -0
- package/src/server/collections/workflows.ts +88 -0
- package/src/server/constants.ts +26 -0
- package/src/server/fields/expression-field.ts +11 -0
- package/src/server/fields/index.ts +7 -0
- package/src/server/functions/index.ts +16 -0
- package/src/server/index.ts +6 -0
- package/src/server/instructions/aggregate.ts +42 -0
- package/src/server/instructions/calculation.ts +41 -0
- package/src/server/instructions/condition.ts +172 -0
- package/src/server/instructions/create.ts +39 -0
- package/src/server/instructions/delay.ts +105 -0
- package/src/server/instructions/destroy.ts +23 -0
- package/src/server/instructions/index.ts +64 -0
- package/src/server/instructions/loop.ts +99 -0
- package/src/server/instructions/manual/actions.ts +91 -0
- package/src/server/instructions/manual/collecions/jobs.ts +17 -0
- package/src/server/instructions/manual/collecions/users.ts +15 -0
- package/src/server/instructions/manual/collecions/users_jobs.ts +50 -0
- package/src/server/instructions/manual/forms/create.ts +23 -0
- package/src/server/instructions/manual/forms/index.ts +12 -0
- package/src/server/instructions/manual/forms/update.ts +23 -0
- package/src/server/instructions/manual/index.ts +184 -0
- package/src/server/instructions/parallel.ts +121 -0
- package/src/server/instructions/query.ts +42 -0
- package/src/server/instructions/request.ts +88 -0
- package/src/server/instructions/sql.ts +25 -0
- package/src/server/instructions/update.ts +24 -0
- package/src/server/migrations/20221129153547-calculation-variables.ts +64 -0
- package/src/server/migrations/20230221032941-change-request-body-type.ts +76 -0
- package/src/server/migrations/20230221071831-calculation-expression.ts +102 -0
- package/src/server/migrations/20230221121203-condition-calculation.ts +82 -0
- package/src/server/migrations/20230221162902-jsonb-to-json.ts +51 -0
- package/src/server/migrations/20230411034722-manual-multi-form.ts +282 -0
- package/src/server/migrations/20230612021134-manual-collection-block.ts +138 -0
- package/src/server/migrations/20230710115902-manual-action-values.ts +78 -0
- package/src/server/triggers/collection.ts +146 -0
- package/src/server/triggers/index.ts +22 -0
- package/src/server/triggers/schedule.ts +567 -0
- package/src/server/types/Execution.ts +26 -0
- package/src/server/types/FlowNode.ts +21 -0
- package/src/server/types/Job.ts +18 -0
- package/src/server/types/Workflow.ts +36 -0
- package/src/server/types/index.ts +4 -0
- package/src/server/utils.ts +17 -0
- package/lib/client/triggers/schedule/DateFieldsSelect.d.ts +0 -2
- /package/lib/server/{models → types}/Execution.js +0 -0
- /package/lib/server/{models → types}/FlowNode.js +0 -0
- /package/lib/server/{models → types}/Job.js +0 -0
- /package/lib/server/{models → types}/Workflow.js +0 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Processor } from '../../..';
|
|
2
|
+
import ManualInstruction from '..';
|
|
3
|
+
|
|
4
|
+
import create from './create';
|
|
5
|
+
import update from './update';
|
|
6
|
+
|
|
7
|
+
export type FormHandler = (this: ManualInstruction, instance, formConfig, processor: Processor) => Promise<void>;
|
|
8
|
+
|
|
9
|
+
export default function ({ formTypes }) {
|
|
10
|
+
formTypes.register('create', create);
|
|
11
|
+
formTypes.register('update', update);
|
|
12
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Processor } from '../../..';
|
|
2
|
+
import ManualInstruction from '..';
|
|
3
|
+
|
|
4
|
+
export default async function (this: ManualInstruction, instance, { collection, filter = {} }, processor: Processor) {
|
|
5
|
+
const repo = this.plugin.db.getRepository(collection);
|
|
6
|
+
if (!repo) {
|
|
7
|
+
throw new Error(`collection ${collection} for update data on manual node not found`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { _, ...form } = instance.result;
|
|
11
|
+
const [values] = Object.values(form);
|
|
12
|
+
await repo.update({
|
|
13
|
+
filter: processor.getParsedValue(filter),
|
|
14
|
+
values: {
|
|
15
|
+
...((values as { [key: string]: any }) ?? {}),
|
|
16
|
+
updatedBy: instance.userId,
|
|
17
|
+
},
|
|
18
|
+
context: {
|
|
19
|
+
executionId: processor.execution.id,
|
|
20
|
+
},
|
|
21
|
+
transaction: processor.transaction,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import actions from '@nocobase/actions';
|
|
2
|
+
import { HandlerType } from '@nocobase/resourcer';
|
|
3
|
+
import { Registry } from '@nocobase/utils';
|
|
4
|
+
|
|
5
|
+
import Plugin from '../..';
|
|
6
|
+
import { JOB_STATUS } from '../../constants';
|
|
7
|
+
import { Instruction } from '..';
|
|
8
|
+
import jobsCollection from './collecions/jobs';
|
|
9
|
+
import usersCollection from './collecions/users';
|
|
10
|
+
import usersJobsCollection from './collecions/users_jobs';
|
|
11
|
+
import { submit } from './actions';
|
|
12
|
+
import initFormTypes, { FormHandler } from './forms';
|
|
13
|
+
|
|
14
|
+
type FormType = {
|
|
15
|
+
type: 'custom' | 'create' | 'update';
|
|
16
|
+
actions: number[];
|
|
17
|
+
options: {
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export interface ManualConfig {
|
|
23
|
+
schema: { [key: string]: any };
|
|
24
|
+
forms: { [key: string]: FormType };
|
|
25
|
+
assignees?: (number | string)[];
|
|
26
|
+
mode?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const MULTIPLE_ASSIGNED_MODE = {
|
|
30
|
+
SINGLE: Symbol('single'),
|
|
31
|
+
ALL: Symbol('all'),
|
|
32
|
+
ANY: Symbol('any'),
|
|
33
|
+
ALL_PERCENTAGE: Symbol('all percentage'),
|
|
34
|
+
ANY_PERCENTAGE: Symbol('any percentage'),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const Modes = {
|
|
38
|
+
[MULTIPLE_ASSIGNED_MODE.SINGLE]: {
|
|
39
|
+
getStatus(distribution, assignees) {
|
|
40
|
+
const done = distribution.find((item) => item.status !== JOB_STATUS.PENDING && item.count > 0);
|
|
41
|
+
return done ? done.status : null;
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
[MULTIPLE_ASSIGNED_MODE.ALL]: {
|
|
45
|
+
getStatus(distribution, assignees) {
|
|
46
|
+
const resolved = distribution.find((item) => item.status === JOB_STATUS.RESOLVED);
|
|
47
|
+
if (resolved && resolved.count === assignees.length) {
|
|
48
|
+
return JOB_STATUS.RESOLVED;
|
|
49
|
+
}
|
|
50
|
+
const rejected = distribution.find((item) => item.status < JOB_STATUS.PENDING);
|
|
51
|
+
if (rejected && rejected.count) {
|
|
52
|
+
return rejected.status;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return null;
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
[MULTIPLE_ASSIGNED_MODE.ANY]: {
|
|
59
|
+
getStatus(distribution, assignees) {
|
|
60
|
+
const resolved = distribution.find((item) => item.status === JOB_STATUS.RESOLVED);
|
|
61
|
+
if (resolved && resolved.count) {
|
|
62
|
+
return JOB_STATUS.RESOLVED;
|
|
63
|
+
}
|
|
64
|
+
const rejectedCount = distribution.reduce(
|
|
65
|
+
(count, item) => (item.status < JOB_STATUS.PENDING ? count + item.count : count),
|
|
66
|
+
0,
|
|
67
|
+
);
|
|
68
|
+
// NOTE: all failures are considered as rejected for now
|
|
69
|
+
if (rejectedCount === assignees.length) {
|
|
70
|
+
return JOB_STATUS.REJECTED;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return null;
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
function getMode(mode) {
|
|
79
|
+
switch (true) {
|
|
80
|
+
case mode === 1:
|
|
81
|
+
return Modes[MULTIPLE_ASSIGNED_MODE.ALL];
|
|
82
|
+
case mode === -1:
|
|
83
|
+
return Modes[MULTIPLE_ASSIGNED_MODE.ANY];
|
|
84
|
+
case mode > 0:
|
|
85
|
+
return Modes[MULTIPLE_ASSIGNED_MODE.ALL_PERCENTAGE];
|
|
86
|
+
case mode < 0:
|
|
87
|
+
return Modes[MULTIPLE_ASSIGNED_MODE.ANY_PERCENTAGE];
|
|
88
|
+
default:
|
|
89
|
+
return Modes[MULTIPLE_ASSIGNED_MODE.SINGLE];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export default class implements Instruction {
|
|
94
|
+
formTypes = new Registry<FormHandler>();
|
|
95
|
+
|
|
96
|
+
constructor(protected plugin: Plugin) {
|
|
97
|
+
plugin.db.collection(usersJobsCollection);
|
|
98
|
+
plugin.db.extendCollection(usersCollection);
|
|
99
|
+
plugin.db.extendCollection(jobsCollection);
|
|
100
|
+
|
|
101
|
+
plugin.app.resource({
|
|
102
|
+
name: 'users_jobs',
|
|
103
|
+
actions: {
|
|
104
|
+
list: {
|
|
105
|
+
filter: {
|
|
106
|
+
$or: [
|
|
107
|
+
{
|
|
108
|
+
'workflow.enabled': true,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
'workflow.enabled': false,
|
|
112
|
+
status: {
|
|
113
|
+
$ne: JOB_STATUS.PENDING,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
},
|
|
118
|
+
handler: actions.list as HandlerType,
|
|
119
|
+
},
|
|
120
|
+
submit,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
initFormTypes(this);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async run(node, prevJob, processor) {
|
|
128
|
+
const { mode, ...config } = node.config as ManualConfig;
|
|
129
|
+
const assignees = [...new Set(processor.getParsedValue(config.assignees) || [])];
|
|
130
|
+
|
|
131
|
+
const job = await processor.saveJob({
|
|
132
|
+
status: JOB_STATUS.PENDING,
|
|
133
|
+
result: mode ? [] : null,
|
|
134
|
+
nodeId: node.id,
|
|
135
|
+
upstreamId: prevJob?.id ?? null,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// NOTE: batch create users jobs
|
|
139
|
+
const UserJobModel = processor.options.plugin.db.getModel('users_jobs');
|
|
140
|
+
await UserJobModel.bulkCreate(
|
|
141
|
+
assignees.map((userId) => ({
|
|
142
|
+
userId,
|
|
143
|
+
jobId: job.id,
|
|
144
|
+
nodeId: node.id,
|
|
145
|
+
executionId: job.executionId,
|
|
146
|
+
workflowId: node.workflowId,
|
|
147
|
+
status: JOB_STATUS.PENDING,
|
|
148
|
+
})),
|
|
149
|
+
{
|
|
150
|
+
transaction: processor.transaction,
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
return job;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async resume(node, job, processor) {
|
|
158
|
+
// NOTE: check all users jobs related if all done then continue as parallel
|
|
159
|
+
const { assignees = [], mode } = node.config as ManualConfig;
|
|
160
|
+
|
|
161
|
+
const UserJobModel = processor.options.plugin.db.getModel('users_jobs');
|
|
162
|
+
const distribution = await UserJobModel.count({
|
|
163
|
+
where: {
|
|
164
|
+
jobId: job.id,
|
|
165
|
+
},
|
|
166
|
+
group: ['status'],
|
|
167
|
+
transaction: processor.transaction,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const submitted = distribution.reduce(
|
|
171
|
+
(count, item) => (item.status !== JOB_STATUS.PENDING ? count + item.count : count),
|
|
172
|
+
0,
|
|
173
|
+
);
|
|
174
|
+
const status = job.status || (getMode(mode).getStatus(distribution, assignees) ?? JOB_STATUS.PENDING);
|
|
175
|
+
const result = mode ? (submitted || 0) / assignees.length : job.latestUserJob?.result ?? job.result;
|
|
176
|
+
processor.logger.debug(`manual resume job and next status: ${status}`);
|
|
177
|
+
job.set({
|
|
178
|
+
status,
|
|
179
|
+
result,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
return job;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import Processor from '../Processor';
|
|
2
|
+
import { JOB_STATUS } from '../constants';
|
|
3
|
+
import type { FlowNodeModel, JobModel } from '../types';
|
|
4
|
+
|
|
5
|
+
export const PARALLEL_MODE = {
|
|
6
|
+
ALL: 'all',
|
|
7
|
+
ANY: 'any',
|
|
8
|
+
RACE: 'race',
|
|
9
|
+
} as const;
|
|
10
|
+
|
|
11
|
+
const Modes = {
|
|
12
|
+
[PARALLEL_MODE.ALL]: {
|
|
13
|
+
next(previous) {
|
|
14
|
+
return previous.status >= JOB_STATUS.PENDING;
|
|
15
|
+
},
|
|
16
|
+
getStatus(result) {
|
|
17
|
+
const failedStatus = result.find((status) => status != null && status < JOB_STATUS.PENDING);
|
|
18
|
+
if (typeof failedStatus !== 'undefined') {
|
|
19
|
+
return failedStatus;
|
|
20
|
+
}
|
|
21
|
+
if (result.every((status) => status != null && status === JOB_STATUS.RESOLVED)) {
|
|
22
|
+
return JOB_STATUS.RESOLVED;
|
|
23
|
+
}
|
|
24
|
+
return JOB_STATUS.PENDING;
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
[PARALLEL_MODE.ANY]: {
|
|
28
|
+
next(previous) {
|
|
29
|
+
return previous.status <= JOB_STATUS.PENDING;
|
|
30
|
+
},
|
|
31
|
+
getStatus(result) {
|
|
32
|
+
if (result.some((status) => status != null && status === JOB_STATUS.RESOLVED)) {
|
|
33
|
+
return JOB_STATUS.RESOLVED;
|
|
34
|
+
}
|
|
35
|
+
if (result.some((status) => (status != null ? status === JOB_STATUS.PENDING : true))) {
|
|
36
|
+
return JOB_STATUS.PENDING;
|
|
37
|
+
}
|
|
38
|
+
return JOB_STATUS.FAILED;
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
[PARALLEL_MODE.RACE]: {
|
|
42
|
+
next(previous) {
|
|
43
|
+
return previous.status === JOB_STATUS.PENDING;
|
|
44
|
+
},
|
|
45
|
+
getStatus(result) {
|
|
46
|
+
if (result.some((status) => status != null && status === JOB_STATUS.RESOLVED)) {
|
|
47
|
+
return JOB_STATUS.RESOLVED;
|
|
48
|
+
}
|
|
49
|
+
const failedStatus = result.find((status) => status != null && status < JOB_STATUS.PENDING);
|
|
50
|
+
if (typeof failedStatus !== 'undefined') {
|
|
51
|
+
return failedStatus;
|
|
52
|
+
}
|
|
53
|
+
return JOB_STATUS.PENDING;
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default {
|
|
59
|
+
async run(node: FlowNodeModel, prevJob: JobModel, processor: Processor) {
|
|
60
|
+
const branches = processor.getBranches(node);
|
|
61
|
+
|
|
62
|
+
const job = await processor.saveJob({
|
|
63
|
+
status: JOB_STATUS.PENDING,
|
|
64
|
+
result: Array(branches.length).fill(null),
|
|
65
|
+
nodeId: node.id,
|
|
66
|
+
upstreamId: prevJob?.id ?? null,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// NOTE:
|
|
70
|
+
// use `reduce` but not `Promise.all` here to avoid racing manupulating db.
|
|
71
|
+
// for users, this is almost equivalent to `Promise.all`,
|
|
72
|
+
// because of the delay is not significant sensible.
|
|
73
|
+
// another benifit of this is, it could handle sequenced branches in future.
|
|
74
|
+
const { mode = PARALLEL_MODE.ALL } = node.config;
|
|
75
|
+
await branches.reduce(
|
|
76
|
+
(promise: Promise<any>, branch, i) =>
|
|
77
|
+
promise.then(async (previous) => {
|
|
78
|
+
if (i && !Modes[mode].next(previous)) {
|
|
79
|
+
return previous;
|
|
80
|
+
}
|
|
81
|
+
await processor.run(branch, job);
|
|
82
|
+
|
|
83
|
+
// find last job of the branch
|
|
84
|
+
return processor.findBranchLastJob(branch);
|
|
85
|
+
}),
|
|
86
|
+
Promise.resolve(),
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
return null;
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
async resume(node: FlowNodeModel, branchJob, processor: Processor) {
|
|
93
|
+
const job = processor.findBranchParentJob(branchJob, node) as JobModel;
|
|
94
|
+
|
|
95
|
+
const { result, status } = job;
|
|
96
|
+
// if parallel has been done (resolved / rejected), do not care newly executed branch jobs.
|
|
97
|
+
if (status !== JOB_STATUS.PENDING) {
|
|
98
|
+
return processor.exit();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// find the index of the node which start the branch
|
|
102
|
+
const jobNode = processor.nodesMap.get(branchJob.nodeId) as FlowNodeModel;
|
|
103
|
+
const branchStartNode = processor.findBranchStartNode(jobNode, node) as FlowNodeModel;
|
|
104
|
+
const branches = processor.getBranches(node);
|
|
105
|
+
const branchIndex = branches.indexOf(branchStartNode);
|
|
106
|
+
const { mode = PARALLEL_MODE.ALL } = node.config || {};
|
|
107
|
+
|
|
108
|
+
const newResult = [...result.slice(0, branchIndex), branchJob.status, ...result.slice(branchIndex + 1)];
|
|
109
|
+
job.set({
|
|
110
|
+
result: newResult,
|
|
111
|
+
status: Modes[mode].getStatus(newResult),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (job.status === JOB_STATUS.PENDING) {
|
|
115
|
+
await job.save({ transaction: processor.transaction });
|
|
116
|
+
return processor.exit();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return job;
|
|
120
|
+
},
|
|
121
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Processor from '../Processor';
|
|
2
|
+
import { JOB_STATUS } from '../constants';
|
|
3
|
+
import { toJSON } from '../utils';
|
|
4
|
+
import type { FlowNodeModel } from '../types';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
async run(node: FlowNodeModel, input, processor: Processor) {
|
|
8
|
+
const { collection, multiple, params = {}, failOnEmpty = false } = node.config;
|
|
9
|
+
|
|
10
|
+
const repo = (<typeof FlowNodeModel>node.constructor).database.getRepository(collection);
|
|
11
|
+
const options = processor.getParsedValue(params, node);
|
|
12
|
+
const appends = options.appends
|
|
13
|
+
? Array.from(
|
|
14
|
+
options.appends.reduce((set, field) => {
|
|
15
|
+
set.add(field.split('.')[0]);
|
|
16
|
+
set.add(field);
|
|
17
|
+
return set;
|
|
18
|
+
}, new Set()),
|
|
19
|
+
)
|
|
20
|
+
: options.appends;
|
|
21
|
+
const result = await (multiple ? repo.find : repo.findOne).call(repo, {
|
|
22
|
+
...options,
|
|
23
|
+
appends: appends,
|
|
24
|
+
transaction: processor.transaction,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (failOnEmpty && (multiple ? !result.length : !result)) {
|
|
28
|
+
return {
|
|
29
|
+
result,
|
|
30
|
+
status: JOB_STATUS.FAILED,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// NOTE: `toJSON()` to avoid getting undefined value from Proxied model instance (#380)
|
|
35
|
+
// e.g. Object.prototype.hasOwnProperty.call(result, 'id') // false
|
|
36
|
+
// so the properties can not be get by json-templates(object-path)
|
|
37
|
+
return {
|
|
38
|
+
result: toJSON(result),
|
|
39
|
+
status: JOB_STATUS.RESOLVED,
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import axios, { AxiosRequestConfig } from 'axios';
|
|
2
|
+
|
|
3
|
+
import { Instruction } from './index';
|
|
4
|
+
import { JOB_STATUS } from '../constants';
|
|
5
|
+
import Processor from '../Processor';
|
|
6
|
+
import type { FlowNodeModel } from '../types';
|
|
7
|
+
|
|
8
|
+
export interface Header {
|
|
9
|
+
name: string;
|
|
10
|
+
value: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type RequestConfig = Pick<AxiosRequestConfig, 'url' | 'method' | 'params' | 'data' | 'timeout'> & {
|
|
14
|
+
headers: Array<Header>;
|
|
15
|
+
ignoreFail: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
async function request(config) {
|
|
19
|
+
// default headers
|
|
20
|
+
const { url, method = 'POST', data, timeout = 5000 } = config;
|
|
21
|
+
const headers = (config.headers ?? []).reduce((result, header) => {
|
|
22
|
+
if (header.name.toLowerCase() === 'content-type') {
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
return Object.assign(result, { [header.name]: header.value });
|
|
26
|
+
}, {});
|
|
27
|
+
const params = (config.params ?? []).reduce(
|
|
28
|
+
(result, param) => Object.assign(result, { [param.name]: param.value }),
|
|
29
|
+
{},
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
// TODO(feat): only support JSON type for now, should support others in future
|
|
33
|
+
headers['Content-Type'] = 'application/json';
|
|
34
|
+
|
|
35
|
+
return axios.request({
|
|
36
|
+
url,
|
|
37
|
+
method,
|
|
38
|
+
headers,
|
|
39
|
+
params,
|
|
40
|
+
data,
|
|
41
|
+
timeout,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default class implements Instruction {
|
|
46
|
+
constructor(public plugin) {}
|
|
47
|
+
|
|
48
|
+
async run(node: FlowNodeModel, prevJob, processor: Processor) {
|
|
49
|
+
const job = await processor.saveJob({
|
|
50
|
+
status: JOB_STATUS.PENDING,
|
|
51
|
+
nodeId: node.id,
|
|
52
|
+
upstreamId: prevJob?.id ?? null,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const config = processor.getParsedValue(node.config, node) as RequestConfig;
|
|
56
|
+
|
|
57
|
+
// eslint-disable-next-line promise/catch-or-return
|
|
58
|
+
request(config)
|
|
59
|
+
.then((response) => {
|
|
60
|
+
job.set({
|
|
61
|
+
status: JOB_STATUS.RESOLVED,
|
|
62
|
+
result: response.data,
|
|
63
|
+
});
|
|
64
|
+
})
|
|
65
|
+
.catch((error) => {
|
|
66
|
+
job.set({
|
|
67
|
+
status: JOB_STATUS.FAILED,
|
|
68
|
+
result: error.isAxiosError ? error.toJSON() : error.message,
|
|
69
|
+
});
|
|
70
|
+
})
|
|
71
|
+
.finally(() => {
|
|
72
|
+
processor.logger.info(`request (#${node.id}) response received, status: ${job.get('status')}`);
|
|
73
|
+
this.plugin.resume(job);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
processor.logger.info(`request (#${node.id}) sent to "${config.url}", waiting for response...`);
|
|
77
|
+
|
|
78
|
+
return processor.exit();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async resume(node: FlowNodeModel, job, processor: Processor) {
|
|
82
|
+
const { ignoreFail } = node.config as RequestConfig;
|
|
83
|
+
if (ignoreFail) {
|
|
84
|
+
job.set('status', JOB_STATUS.RESOLVED);
|
|
85
|
+
}
|
|
86
|
+
return job;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Processor, JOB_STATUS } from '..';
|
|
2
|
+
import type { FlowNodeModel } from '../types';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
async run(node: FlowNodeModel, input, processor: Processor) {
|
|
6
|
+
const { sequelize } = (<typeof FlowNodeModel>node.constructor).database;
|
|
7
|
+
const sql = processor.getParsedValue(node.config.sql ?? '', node).trim();
|
|
8
|
+
if (!sql) {
|
|
9
|
+
return {
|
|
10
|
+
status: JOB_STATUS.RESOLVED,
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const result = await sequelize.query(sql, {
|
|
15
|
+
transaction: processor.transaction,
|
|
16
|
+
// plain: true,
|
|
17
|
+
// model: db.getCollection(node.config.collection).model
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
result,
|
|
22
|
+
status: JOB_STATUS.RESOLVED,
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import Processor from '../Processor';
|
|
2
|
+
import { JOB_STATUS } from '../constants';
|
|
3
|
+
import type { FlowNodeModel } from '../types';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
async run(node: FlowNodeModel, input, processor: Processor) {
|
|
7
|
+
const { collection, params = {} } = node.config;
|
|
8
|
+
|
|
9
|
+
const repo = (<typeof FlowNodeModel>node.constructor).database.getRepository(collection);
|
|
10
|
+
const options = processor.getParsedValue(params, node);
|
|
11
|
+
const result = await repo.update({
|
|
12
|
+
...options,
|
|
13
|
+
context: {
|
|
14
|
+
executionId: processor.execution.id,
|
|
15
|
+
},
|
|
16
|
+
transaction: processor.transaction,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
result: result.length ?? result,
|
|
21
|
+
status: JOB_STATUS.RESOLVED,
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Migration } from '@nocobase/server';
|
|
2
|
+
|
|
3
|
+
const VTypes = {
|
|
4
|
+
constant(operand) {
|
|
5
|
+
return operand.value;
|
|
6
|
+
},
|
|
7
|
+
$jobsMapByNodeId({ options }) {
|
|
8
|
+
const paths = [options.nodeId, options.path].filter(Boolean);
|
|
9
|
+
return paths ? `{{$jobsMapByNodeId.${paths.join('.')}}}` : null;
|
|
10
|
+
},
|
|
11
|
+
$context({ options }) {
|
|
12
|
+
return `{{$context.${options.path}}}`;
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function migrateConfig(config) {
|
|
17
|
+
if (Array.isArray(config)) {
|
|
18
|
+
return config.map((item) => migrateConfig(item));
|
|
19
|
+
}
|
|
20
|
+
if (typeof config !== 'object') {
|
|
21
|
+
return config;
|
|
22
|
+
}
|
|
23
|
+
if (!config) {
|
|
24
|
+
return config;
|
|
25
|
+
}
|
|
26
|
+
if (config.type && VTypes[config.type] && (config.options || config.value)) {
|
|
27
|
+
return VTypes[config.type](config);
|
|
28
|
+
}
|
|
29
|
+
return Object.keys(config).reduce((memo, key) => ({ ...memo, [key]: migrateConfig(config[key]) }), {});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default class extends Migration {
|
|
33
|
+
async up() {
|
|
34
|
+
const match = await this.app.version.satisfies('<=0.8.0-alpha.13');
|
|
35
|
+
if (!match) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const NodeRepo = this.context.db.getRepository('flow_nodes');
|
|
39
|
+
await this.context.db.sequelize.transaction(async (transaction) => {
|
|
40
|
+
const nodes = await NodeRepo.find({
|
|
41
|
+
filter: {
|
|
42
|
+
type: {
|
|
43
|
+
$or: ['calculation', 'condition'],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
transaction,
|
|
47
|
+
});
|
|
48
|
+
console.log('%d nodes need to be migrated.', nodes.length);
|
|
49
|
+
|
|
50
|
+
await nodes.reduce((promise, node) => {
|
|
51
|
+
return node.update(
|
|
52
|
+
{
|
|
53
|
+
config: migrateConfig(node.config),
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
transaction,
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
}, Promise.resolve());
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async down() {}
|
|
64
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Migration } from '@nocobase/server';
|
|
2
|
+
|
|
3
|
+
const EJS_RE = /"?<%=\s*(ctx|node)([\w\.\[\]-]+)\s*.*%>"?/;
|
|
4
|
+
|
|
5
|
+
function migrateData(input) {
|
|
6
|
+
if (typeof input !== 'string') {
|
|
7
|
+
return input;
|
|
8
|
+
}
|
|
9
|
+
if (!input) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const typeMap = {
|
|
13
|
+
ctx: '$context',
|
|
14
|
+
node: '$jobsMapByNodeId',
|
|
15
|
+
};
|
|
16
|
+
return input.replace(EJS_RE, (_, type, path) => {
|
|
17
|
+
if (type === 'ctx') {
|
|
18
|
+
return `"{{$context${path}}}"`;
|
|
19
|
+
}
|
|
20
|
+
if (type === 'node') {
|
|
21
|
+
return `"{{$jobsMapByNodeId${path.replace('[', '.').replace(']', '.').replace(/\.$/, '')}}}"`;
|
|
22
|
+
}
|
|
23
|
+
return _;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default class extends Migration {
|
|
28
|
+
async up() {
|
|
29
|
+
const match = await this.app.version.satisfies('<0.9.0-alpha.3');
|
|
30
|
+
if (!match) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const NodeRepo = this.context.db.getRepository('flow_nodes');
|
|
35
|
+
|
|
36
|
+
await this.context.db.sequelize.transaction(async (transaction) => {
|
|
37
|
+
const nodes = await NodeRepo.find({
|
|
38
|
+
filter: {
|
|
39
|
+
type: 'request',
|
|
40
|
+
},
|
|
41
|
+
transaction,
|
|
42
|
+
});
|
|
43
|
+
console.log('%d nodes need to be migrated.', nodes.length);
|
|
44
|
+
|
|
45
|
+
await nodes.reduce(
|
|
46
|
+
(promise, node) =>
|
|
47
|
+
promise.then(async () => {
|
|
48
|
+
if (typeof node.config.data !== 'string') {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
let data = migrateData(node.config.data);
|
|
52
|
+
try {
|
|
53
|
+
data = JSON.parse(node.config.data);
|
|
54
|
+
return node.update(
|
|
55
|
+
{
|
|
56
|
+
config: {
|
|
57
|
+
...node.config,
|
|
58
|
+
data,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
transaction,
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(
|
|
67
|
+
`flow_node #${node.id} config migrating failed! you should migrate its format from ejs to json-templates manually in your db.`,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}),
|
|
71
|
+
Promise.resolve(),
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async down() {}
|
|
76
|
+
}
|