@nocobase/plugin-workflow 0.11.0-alpha.1 → 0.11.1-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.
Files changed (133) hide show
  1. package/lib/client/AddButton.js +13 -4
  2. package/lib/client/Branch.js +4 -2
  3. package/lib/client/CanvasContent.js +6 -4
  4. package/lib/client/ExecutionCanvas.js +18 -7
  5. package/lib/client/ExecutionPage.js +4 -2
  6. package/lib/client/WorkflowCanvas.js +16 -6
  7. package/lib/client/WorkflowPage.js +4 -2
  8. package/lib/client/WorkflowProvider.js +2 -2
  9. package/lib/client/components/CollectionBlockInitializer.js +3 -3
  10. package/lib/client/components/CollectionFieldset.js +7 -1
  11. package/lib/client/components/FieldsSelect.js +4 -1
  12. package/lib/client/components/NodeDescription.js +36 -22
  13. package/lib/client/index.js +3 -3
  14. package/lib/client/locale/zh-CN.d.ts +5 -1
  15. package/lib/client/locale/zh-CN.js +6 -2
  16. package/lib/client/nodes/aggregate.d.ts +6 -1
  17. package/lib/client/nodes/aggregate.js +4 -3
  18. package/lib/client/nodes/calculation.d.ts +5 -3
  19. package/lib/client/nodes/calculation.js +6 -5
  20. package/lib/client/nodes/condition.d.ts +1 -7
  21. package/lib/client/nodes/condition.js +12 -23
  22. package/lib/client/nodes/create.d.ts +2 -4
  23. package/lib/client/nodes/create.js +1 -3
  24. package/lib/client/nodes/index.d.ts +1 -2
  25. package/lib/client/nodes/index.js +24 -24
  26. package/lib/client/nodes/loop.js +19 -28
  27. package/lib/client/nodes/manual/FormBlockInitializer.js +6 -5
  28. package/lib/client/nodes/manual/SchemaConfig.d.ts +1 -2
  29. package/lib/client/nodes/manual/SchemaConfig.js +175 -21
  30. package/lib/client/nodes/manual/WorkflowTodo.js +39 -46
  31. package/lib/client/nodes/manual/forms/create.js +8 -1
  32. package/lib/client/nodes/manual/forms/custom.js +11 -4
  33. package/lib/client/nodes/manual/forms/update.js +8 -1
  34. package/lib/client/nodes/manual/index.d.ts +6 -1
  35. package/lib/client/nodes/manual/index.js +5 -4
  36. package/lib/client/nodes/parallel.js +7 -4
  37. package/lib/client/nodes/query.d.ts +2 -5
  38. package/lib/client/nodes/query.js +1 -3
  39. package/lib/client/nodes/sql.d.ts +26 -0
  40. package/lib/client/{triggers/schedule/DateFieldsSelect.js → nodes/sql.js} +37 -46
  41. package/lib/client/schemas/collection.d.ts +2 -3
  42. package/lib/client/schemas/collection.js +8 -7
  43. package/lib/client/style.d.ts +18 -13
  44. package/lib/client/style.js +312 -289
  45. package/lib/client/triggers/collection.d.ts +9 -10
  46. package/lib/client/triggers/collection.js +4 -0
  47. package/lib/client/triggers/index.d.ts +2 -3
  48. package/lib/client/triggers/index.js +10 -5
  49. package/lib/client/triggers/schedule/OnField.js +35 -23
  50. package/lib/client/triggers/schedule/ScheduleConfig.js +7 -7
  51. package/lib/client/triggers/schedule/index.d.ts +0 -1
  52. package/lib/client/triggers/schedule/index.js +31 -19
  53. package/lib/client/variable.d.ts +29 -11
  54. package/lib/client/variable.js +39 -24
  55. package/lib/server/Plugin.d.ts +1 -3
  56. package/lib/server/Plugin.js +10 -6
  57. package/lib/server/Processor.d.ts +1 -1
  58. package/lib/server/Processor.js +2 -2
  59. package/lib/server/instructions/create.d.ts +1 -1
  60. package/lib/server/instructions/create.js +13 -13
  61. package/lib/server/instructions/index.js +1 -1
  62. package/lib/server/instructions/manual/actions.js +19 -7
  63. package/lib/server/instructions/manual/forms/create.js +7 -1
  64. package/lib/server/instructions/manual/forms/update.js +7 -1
  65. package/lib/server/instructions/query.js +8 -1
  66. package/lib/server/instructions/request.d.ts +1 -1
  67. package/lib/server/instructions/request.js +4 -2
  68. package/lib/server/instructions/sql.d.ts +12 -0
  69. package/lib/server/instructions/sql.js +34 -0
  70. package/lib/server/migrations/20230710115902-manual-action-values.d.ts +4 -0
  71. package/lib/server/migrations/20230710115902-manual-action-values.js +97 -0
  72. package/lib/server/triggers/collection.js +13 -11
  73. package/lib/server/utils.d.ts +2 -0
  74. package/lib/server/utils.js +21 -0
  75. package/package.json +12 -11
  76. package/src/client/AddButton.tsx +17 -5
  77. package/src/client/Branch.tsx +4 -2
  78. package/src/client/CanvasContent.tsx +6 -4
  79. package/src/client/ExecutionCanvas.tsx +11 -13
  80. package/src/client/ExecutionPage.tsx +3 -2
  81. package/src/client/WorkflowCanvas.tsx +14 -13
  82. package/src/client/WorkflowPage.tsx +3 -2
  83. package/src/client/WorkflowProvider.tsx +2 -2
  84. package/src/client/components/CollectionBlockInitializer.tsx +3 -3
  85. package/src/client/components/CollectionFieldset.tsx +5 -3
  86. package/src/client/components/FieldsSelect.tsx +5 -1
  87. package/src/client/components/NodeDescription.tsx +30 -23
  88. package/src/client/index.tsx +3 -3
  89. package/src/client/locale/zh-CN.ts +8 -2
  90. package/src/client/nodes/aggregate.tsx +4 -4
  91. package/src/client/nodes/calculation.tsx +4 -5
  92. package/src/client/nodes/condition.tsx +7 -34
  93. package/src/client/nodes/create.tsx +0 -1
  94. package/src/client/nodes/index.tsx +21 -25
  95. package/src/client/nodes/loop.tsx +16 -31
  96. package/src/client/nodes/manual/FormBlockInitializer.tsx +6 -5
  97. package/src/client/nodes/manual/SchemaConfig.tsx +162 -18
  98. package/src/client/nodes/manual/WorkflowTodo.tsx +43 -47
  99. package/src/client/nodes/manual/forms/create.tsx +5 -1
  100. package/src/client/nodes/manual/forms/custom.tsx +7 -3
  101. package/src/client/nodes/manual/forms/update.tsx +5 -1
  102. package/src/client/nodes/manual/index.tsx +5 -5
  103. package/src/client/nodes/parallel.tsx +6 -5
  104. package/src/client/nodes/query.tsx +0 -1
  105. package/src/client/nodes/sql.tsx +37 -0
  106. package/src/client/schemas/collection.ts +6 -6
  107. package/src/client/style.tsx +324 -289
  108. package/src/client/triggers/collection.tsx +4 -0
  109. package/src/client/triggers/index.tsx +14 -10
  110. package/src/client/triggers/schedule/OnField.tsx +29 -15
  111. package/src/client/triggers/schedule/ScheduleConfig.tsx +21 -19
  112. package/src/client/triggers/schedule/index.tsx +25 -19
  113. package/src/client/variable.tsx +48 -26
  114. package/src/server/Plugin.ts +13 -9
  115. package/src/server/Processor.ts +2 -2
  116. package/src/server/__tests__/collections/categories.ts +4 -0
  117. package/src/server/__tests__/instructions/manual.test.ts +391 -72
  118. package/src/server/__tests__/instructions/request.test.ts +30 -0
  119. package/src/server/__tests__/instructions/sql.test.ts +162 -0
  120. package/src/server/__tests__/triggers/collection.test.ts +35 -0
  121. package/src/server/instructions/create.ts +13 -11
  122. package/src/server/instructions/index.ts +1 -0
  123. package/src/server/instructions/manual/actions.ts +16 -4
  124. package/src/server/instructions/manual/forms/create.ts +2 -1
  125. package/src/server/instructions/manual/forms/update.ts +3 -2
  126. package/src/server/instructions/query.ts +12 -1
  127. package/src/server/instructions/request.ts +2 -1
  128. package/src/server/instructions/sql.ts +25 -0
  129. package/src/server/migrations/20230710115902-manual-action-values.ts +78 -0
  130. package/src/server/triggers/collection.ts +15 -11
  131. package/src/server/utils.ts +17 -0
  132. package/lib/client/triggers/schedule/DateFieldsSelect.d.ts +0 -2
  133. package/src/client/triggers/schedule/DateFieldsSelect.tsx +0 -28
@@ -5,8 +5,8 @@ import { NodeDefaultView } from '.';
5
5
  import { Branch } from '../Branch';
6
6
  import { useFlowContext } from '../FlowContext';
7
7
  import { NAMESPACE, lang } from '../locale';
8
- import { addButtonClass, branchBlockClass, branchClass, nodeSubtreeClass } from '../style';
9
- import { VariableOption, nodesOptions, triggerOptions, useWorkflowVariableOptions } from '../variable';
8
+ import useStyles from '../style';
9
+ import { VariableOption, defaultFieldNames, nodesOptions, triggerOptions, useWorkflowVariableOptions } from '../variable';
10
10
 
11
11
  function findOption(options: VariableOption[], paths: string[]) {
12
12
  let opts = options;
@@ -59,14 +59,15 @@ export default {
59
59
  view: {},
60
60
  component: function Component({ data }) {
61
61
  const { nodes } = useFlowContext();
62
+ const { styles } = useStyles();
62
63
  const entry = nodes.find((node) => node.upstreamId === data.id && node.branchIndex != null);
63
64
 
64
65
  return (
65
66
  <NodeDefaultView data={data}>
66
- <div className={cx(nodeSubtreeClass)}>
67
+ <div className={styles.nodeSubtreeClass}>
67
68
  <div
68
69
  className={cx(
69
- branchBlockClass,
70
+ styles.branchBlockClass,
70
71
  css`
71
72
  padding-left: 20em;
72
73
  `,
@@ -74,28 +75,10 @@ export default {
74
75
  >
75
76
  <Branch from={data} entry={entry} branchIndex={entry?.branchIndex ?? 0} />
76
77
 
77
- <div className={cx(branchClass)}>
78
+ <div className={styles.branchClass}>
78
79
  <div className="workflow-branch-lines" />
79
- <div
80
- className={cx(
81
- addButtonClass,
82
- css`
83
- display: flex;
84
- justify-content: center;
85
- align-items: center;
86
- position: absolute;
87
- top: 50%;
88
- transform: translateY(-50%);
89
- width: 2em;
90
- height: 6em;
91
- `,
92
- )}
93
- >
94
- <ArrowUpOutlined
95
- className={css`
96
- background-color: var(--nb-box-bg);
97
- `}
98
- />
80
+ <div className={cx(styles.addButtonClass, styles.loopLineClass)}>
81
+ <ArrowUpOutlined />
99
82
  </div>
100
83
  </div>
101
84
  </div>
@@ -120,13 +103,15 @@ export default {
120
103
  return null;
121
104
  }
122
105
 
106
+ const { fieldNames = defaultFieldNames } = options;
107
+
123
108
  // const { workflow } = useFlowContext();
124
109
  // const current = useNodeContext();
125
110
  // const upstreams = useAvailableUpstreams(current);
126
111
  // find target data model by path described in `config.target`
127
112
  // 1. get options from $context/$jobsMapByNodeId
128
113
  // 2. route to sub-options and use as loop target options
129
- let targetOption: VariableOption = { key: 'item', value: 'item', label: lang('Loop target') };
114
+ let targetOption: VariableOption = { key: 'item', [fieldNames.value]: 'item', [fieldNames.label]: lang('Loop target') };
130
115
 
131
116
  if (typeof target === 'string' && target.startsWith('{{') && target.endsWith('}}')) {
132
117
  const paths = target
@@ -137,10 +122,10 @@ export default {
137
122
  const targetOptions = [nodesOptions, triggerOptions].map((item: any) => {
138
123
  const opts = item.useOptions(options).filter(Boolean);
139
124
  return {
140
- label: compile(item.title),
141
- value: item.value,
125
+ [fieldNames.label]: compile(item.title),
126
+ [fieldNames.value]: item.value,
142
127
  key: item.value,
143
- children: opts,
128
+ [fieldNames.children]: opts,
144
129
  disabled: opts && !opts.length,
145
130
  };
146
131
  });
@@ -152,8 +137,8 @@ export default {
152
137
 
153
138
  return [
154
139
  targetOption,
155
- { key: 'index', value: 'index', label: lang('Loop index') },
156
- { key: 'length', value: 'length', label: lang('Loop length') },
140
+ { key: 'index', [fieldNames.value]: 'index', [fieldNames.label]: lang('Loop index') },
141
+ { key: 'length', [fieldNames.value]: 'length', [fieldNames.label]: lang('Loop length') },
157
142
  ];
158
143
  },
159
144
  };
@@ -34,11 +34,8 @@ function InternalFormBlockInitializer({ insert, schema, ...others }) {
34
34
  type: 'primary',
35
35
  useAction: '{{ useSubmit }}',
36
36
  },
37
- 'x-designer': 'Action.Designer',
38
- 'x-designer-props': {
39
- type: 'record',
40
- },
41
- 'x-action': `${JOB_STATUS.RESOLVED}`,
37
+ 'x-designer': 'ManualActionDesigner',
38
+ 'x-designer-props': {},
42
39
  },
43
40
  },
44
41
  ...schema,
@@ -48,6 +45,10 @@ function InternalFormBlockInitializer({ insert, schema, ...others }) {
48
45
  delete result['x-acl-action'];
49
46
  const [formKey] = Object.keys(result.properties);
50
47
  result.properties[formKey].properties.actions['x-decorator'] = 'ActionBarProvider';
48
+ result.properties[formKey].properties.actions['x-component-props'].style = {
49
+ marginTop: '1.5em',
50
+ flexWrap: 'wrap',
51
+ };
51
52
  traverseSchema(result, (node) => {
52
53
  if (node['x-uid']) {
53
54
  delete node['x-uid'];
@@ -1,8 +1,12 @@
1
- import React, { useContext, useMemo, useState } from 'react';
2
-
3
- import { ISchema, Schema, useFieldSchema, useForm } from '@formily/react';
1
+ import React, { useContext, useEffect, useMemo, useState } from 'react';
2
+ import { createForm } from '@formily/core';
3
+ import { FormProvider, ISchema, Schema, useFieldSchema, useForm } from '@formily/react';
4
+ import { FormLayout } from '@formily/antd-v5';
5
+ import { Alert, Button, Modal, Space } from 'antd';
6
+ import { useTranslation } from 'react-i18next';
4
7
 
5
8
  import {
9
+ Action,
6
10
  ActionContextProvider,
7
11
  GeneralSchemaDesigner,
8
12
  InitializerWithSwitch,
@@ -12,22 +16,24 @@ import {
12
16
  SchemaInitializerItemOptions,
13
17
  SchemaInitializerProvider,
14
18
  SchemaSettings,
19
+ VariableScopeProvider,
15
20
  gridRowColWrap,
16
21
  useCompile,
17
22
  useFormBlockContext,
23
+ useSchemaOptionsContext,
18
24
  } from '@nocobase/client';
19
25
  import { Registry, lodash } from '@nocobase/utils/client';
20
- import { Button } from 'antd';
21
26
  import { instructions, useAvailableUpstreams, useNodeContext } from '..';
22
- import { useFlowContext } from '../../FlowContext';
23
27
  import { JOB_STATUS } from '../../constants';
28
+ import { useFlowContext } from '../../FlowContext';
24
29
  import { NAMESPACE, lang } from '../../locale';
25
30
  import { useTrigger } from '../../triggers';
26
31
  import { DetailsBlockProvider } from './DetailsBlockProvider';
27
32
  import { FormBlockProvider } from './FormBlockProvider';
28
- import createForm from './forms/create';
29
- import customForm from './forms/custom';
30
- import updateForm from './forms/update';
33
+ import createRecordForm from './forms/create';
34
+ import customRecordForm from './forms/custom';
35
+ import updateRecordForm from './forms/update';
36
+ import { useWorkflowVariableOptions } from '../../variable';
31
37
 
32
38
  type ValueOf<T> = T[keyof T];
33
39
 
@@ -68,9 +74,9 @@ export type ManualFormType = {
68
74
 
69
75
  export const manualFormTypes = new Registry<ManualFormType>();
70
76
 
71
- manualFormTypes.register('customForm', customForm);
72
- manualFormTypes.register('createForm', createForm);
73
- manualFormTypes.register('updateForm', updateForm);
77
+ manualFormTypes.register('customForm', customRecordForm);
78
+ manualFormTypes.register('createForm', createRecordForm);
79
+ manualFormTypes.register('updateForm', updateRecordForm);
74
80
 
75
81
  function useTriggerInitializers(): SchemaInitializerItemOptions | null {
76
82
  const { workflow } = useFlowContext();
@@ -79,7 +85,7 @@ function useTriggerInitializers(): SchemaInitializerItemOptions | null {
79
85
  }
80
86
 
81
87
  const blockTypeNames = {
82
- customForm: customForm.title,
88
+ customForm: customRecordForm.title,
83
89
  record: `{{t("Data record", { ns: "${NAMESPACE}" })}}`,
84
90
  };
85
91
 
@@ -138,7 +144,7 @@ function AddBlockButton(props: any) {
138
144
  {
139
145
  type: 'itemGroup',
140
146
  title: '{{t("Form")}}',
141
- children: Array.from(manualFormTypes.getValues()).map((item) => {
147
+ children: Array.from(manualFormTypes.getValues()).map((item: ManualFormType) => {
142
148
  const { useInitializer: getInitializer } = item.config;
143
149
  return getInitializer();
144
150
  }),
@@ -159,6 +165,142 @@ function AddBlockButton(props: any) {
159
165
  return <SchemaInitializer.Button {...props} wrap={gridRowColWrap} items={items} title="{{t('Add block')}}" />;
160
166
  }
161
167
 
168
+ function AssignedFieldValues() {
169
+ const ctx = useContext(SchemaComponentContext);
170
+ const { t } = useTranslation();
171
+ const fieldSchema = useFieldSchema();
172
+ const scope = useWorkflowVariableOptions({ fieldNames: { label: 'title', value: 'name' } });
173
+ const [open, setOpen] = useState(false);
174
+ const [initialSchema, setInitialSchema] = useState(fieldSchema?.['x-action-settings']?.assignedValues?.schema ?? {
175
+ type: 'void',
176
+ 'x-component': 'Grid',
177
+ 'x-initializer': 'CustomFormItemInitializers',
178
+ properties: {},
179
+ });
180
+ const [schema, setSchema] = useState<Schema>(null);
181
+ const { components } = useSchemaOptionsContext();
182
+ useEffect(() => {
183
+ setSchema(new Schema({
184
+ properties: {
185
+ grid: initialSchema
186
+ },
187
+ }));
188
+ }, [initialSchema]);
189
+ const form = useMemo(
190
+ () => {
191
+ const initialValues = fieldSchema?.['x-action-settings']?.assignedValues?.values;
192
+ return createForm({
193
+ initialValues: lodash.cloneDeep(initialValues),
194
+ values: lodash.cloneDeep(initialValues),
195
+ });
196
+ },
197
+ [],
198
+ );
199
+
200
+ const title = t('Assign field values');
201
+
202
+ function onCancel() {
203
+ setOpen(false);
204
+ }
205
+
206
+ function onSubmit() {
207
+ if (!fieldSchema['x-action-settings']) {
208
+ fieldSchema['x-action-settings'] = {};
209
+ }
210
+ if (!fieldSchema['x-action-settings'].assignedValues) {
211
+ fieldSchema['x-action-settings'].assignedValues = {};
212
+ }
213
+ fieldSchema['x-action-settings'].assignedValues.schema = initialSchema;
214
+ fieldSchema['x-action-settings'].assignedValues.values = form.values;
215
+ setOpen(false);
216
+ setTimeout(() => {
217
+ ctx.refresh?.();
218
+ }, 300);
219
+ }
220
+
221
+ return (
222
+ <>
223
+ <SchemaSettings.Item onClick={() => setOpen(true)}>
224
+ {title}
225
+ </SchemaSettings.Item>
226
+ <Modal
227
+ width={'50%'}
228
+ title={title}
229
+ open={open}
230
+ onCancel={onCancel}
231
+ footer={
232
+ <Space>
233
+ <Button onClick={onCancel}>{t('Cancel')}</Button>
234
+ <Button type="primary" onClick={onSubmit}>{t('Submit')}</Button>
235
+ </Space>
236
+ }
237
+ >
238
+ <VariableScopeProvider scope={scope}>
239
+ <FormProvider form={form}>
240
+ <FormLayout layout={'vertical'}>
241
+ <Alert message={lang('Values preset in this form will override user submitted ones when continue or reject.')} />
242
+ <br />
243
+ {open && schema && (
244
+ <SchemaComponentContext.Provider
245
+ value={{
246
+ ...ctx,
247
+ refresh() {
248
+ setInitialSchema(lodash.get(schema.toJSON(), 'properties.grid'));
249
+ }
250
+ }}
251
+ >
252
+ <SchemaComponent schema={schema} components={components} />
253
+ </SchemaComponentContext.Provider>
254
+ )}
255
+ </FormLayout>
256
+ </FormProvider>
257
+ </VariableScopeProvider>
258
+ </Modal>
259
+ </>
260
+ );
261
+ }
262
+
263
+ function ManualActionDesigner(props) {
264
+ return (
265
+ <GeneralSchemaDesigner {...props} disableInitializer>
266
+ <Action.Designer.ButtonEditor />
267
+ <AssignedFieldValues />
268
+ <SchemaSettings.Divider />
269
+ <SchemaSettings.Remove
270
+ removeParentsIfNoChildren
271
+ breakRemoveOn={{
272
+ 'x-component': 'ActionBar',
273
+ }}
274
+ />
275
+ </GeneralSchemaDesigner>
276
+ );
277
+ }
278
+
279
+ function ContinueInitializer({ action, actionProps, insert, ...props }) {
280
+ return (
281
+ <SchemaInitializer.Item
282
+ {...props}
283
+ onClick={() => {
284
+ insert({
285
+ type: 'void',
286
+ title: props.title,
287
+ 'x-decorator': 'ManualActionStatusProvider',
288
+ 'x-decorator-props': {
289
+ value: action,
290
+ },
291
+ 'x-component': 'Action',
292
+ 'x-component-props': {
293
+ ...actionProps,
294
+ useAction: '{{ useSubmit }}',
295
+ },
296
+ 'x-designer': 'ManualActionDesigner',
297
+ 'x-action-settings': {},
298
+ });
299
+ }}
300
+ />
301
+ );
302
+ }
303
+
162
304
  function ActionInitializer({ action, actionProps, ...props }) {
163
305
  return (
164
306
  <InitializerWithSwitch
@@ -192,7 +334,7 @@ function AddActionButton(props) {
192
334
  key: JOB_STATUS.RESOLVED,
193
335
  type: 'item',
194
336
  title: `{{t("Continue the process", { ns: "${NAMESPACE}" })}}`,
195
- component: ActionInitializer,
337
+ component: ContinueInitializer,
196
338
  action: JOB_STATUS.RESOLVED,
197
339
  actionProps: {
198
340
  type: 'primary',
@@ -205,7 +347,6 @@ function AddActionButton(props) {
205
347
  component: ActionInitializer,
206
348
  action: JOB_STATUS.REJECTED,
207
349
  actionProps: {
208
- type: 'primary',
209
350
  danger: true,
210
351
  },
211
352
  },
@@ -301,7 +442,7 @@ export function SchemaConfig({ value, onChange }) {
301
442
  ctx.refresh?.();
302
443
  const { tabs } = lodash.get(schema.toJSON(), 'properties.drawer.properties') as { tabs: ISchema };
303
444
  const forms = Array.from(manualFormTypes.getValues()).reduce(
304
- (result, item) => Object.assign(result, item.config.parseFormOptions(tabs)),
445
+ (result, item: ManualFormType) => Object.assign(result, item.config.parseFormOptions(tabs)),
305
446
  {},
306
447
  );
307
448
  form.setValuesIn('forms', forms);
@@ -316,8 +457,9 @@ export function SchemaConfig({ value, onChange }) {
316
457
  AddActionButton,
317
458
  ...trigger.initializers,
318
459
  ...nodeInitializers,
460
+ // @ts-ignore
319
461
  ...Array.from(manualFormTypes.getValues()).reduce(
320
- (result, item) => Object.assign(result, item.config.initializers),
462
+ (result, item: ManualFormType) => Object.assign(result, item.config.initializers),
321
463
  {},
322
464
  ),
323
465
  }}
@@ -326,8 +468,9 @@ export function SchemaConfig({ value, onChange }) {
326
468
  schema={schema}
327
469
  components={{
328
470
  ...nodeComponents,
471
+ // @ts-ignore
329
472
  ...Array.from(manualFormTypes.getValues()).reduce(
330
- (result, item) => Object.assign(result, item.config.components),
473
+ (result, item: ManualFormType) => Object.assign(result, item.config.components),
331
474
  {},
332
475
  ),
333
476
  FormBlockProvider,
@@ -340,6 +483,7 @@ export function SchemaConfig({ value, onChange }) {
340
483
  return props.children;
341
484
  },
342
485
  SimpleDesigner,
486
+ ManualActionDesigner,
343
487
  }}
344
488
  scope={{
345
489
  useSubmit,
@@ -1,24 +1,23 @@
1
1
  import { css } from '@emotion/css';
2
2
  import { observer, useField, useFieldSchema, useForm } from '@formily/react';
3
3
  import { dayjs } from '@nocobase/utils/client';
4
- import { Spin, Tag } from 'antd';
4
+ import { Space, Spin, Tag } from 'antd';
5
5
  import React, { createContext, useContext, useEffect, useState } from 'react';
6
6
 
7
7
  import {
8
8
  CollectionManagerProvider,
9
- FormBlockContext,
10
9
  SchemaComponent,
11
10
  SchemaComponentContext,
12
11
  TableBlockProvider,
13
12
  useAPIClient,
14
13
  useActionContext,
15
14
  useCollectionManager,
15
+ useCompile,
16
16
  useCurrentUserContext,
17
17
  useFormBlockContext,
18
18
  useRecord,
19
19
  useTableBlockContext,
20
20
  } from '@nocobase/client';
21
- import { uid } from '@nocobase/utils/client';
22
21
  import { instructions, useAvailableUpstreams } from '..';
23
22
  import { FlowContext, useFlowContext } from '../../FlowContext';
24
23
  import { JobStatusOptions, JobStatusOptionsMap } from '../../constants';
@@ -26,7 +25,7 @@ import { NAMESPACE } from '../../locale';
26
25
  import { linkNodes } from '../../utils';
27
26
  import { DetailsBlockProvider } from './DetailsBlockProvider';
28
27
  import { FormBlockProvider } from './FormBlockProvider';
29
- import { manualFormTypes } from './SchemaConfig';
28
+ import { ManualFormType, manualFormTypes } from './SchemaConfig';
30
29
 
31
30
  const nodeCollection = {
32
31
  title: `{{t("Task", { ns: "${NAMESPACE}" })}}`,
@@ -177,7 +176,6 @@ const todoCollection = {
177
176
  'x-component-props': {
178
177
  showTime: true,
179
178
  },
180
- 'x-read-pretty': true,
181
179
  },
182
180
  },
183
181
  ],
@@ -217,8 +215,6 @@ export const WorkflowTodo: React.FC & { Drawer: React.FC; Decorator: React.FC }
217
215
  }}
218
216
  schema={{
219
217
  type: 'void',
220
- name: uid(),
221
- 'x-component': 'div',
222
218
  properties: {
223
219
  actions: {
224
220
  type: 'void',
@@ -293,7 +289,7 @@ export const WorkflowTodo: React.FC & { Drawer: React.FC; Decorator: React.FC }
293
289
  'x-component': 'TableV2.Column',
294
290
  properties: {
295
291
  createdAt: {
296
- type: 'number',
292
+ type: 'string',
297
293
  'x-component': 'CollectionField',
298
294
  'x-read-pretty': true,
299
295
  },
@@ -317,7 +313,6 @@ export const WorkflowTodo: React.FC & { Drawer: React.FC; Decorator: React.FC }
317
313
  'x-component': 'TableV2.Column',
318
314
  properties: {
319
315
  status: {
320
- type: 'number',
321
316
  'x-component': 'CollectionField',
322
317
  'x-read-pretty': true,
323
318
  },
@@ -382,13 +377,14 @@ const ManualActionStatusContext = createContext<number | null>(null);
382
377
  function ManualActionStatusProvider({ value, children }) {
383
378
  const { userJob } = useFlowContext();
384
379
  const button = useField();
380
+ const buttonSchema = useFieldSchema();
385
381
 
386
382
  useEffect(() => {
387
383
  if (userJob.status) {
388
384
  button.disabled = true;
389
- button.visible = userJob.status === value;
385
+ button.visible = userJob.status === value && userJob.result._ === buttonSchema.name;
390
386
  }
391
- }, [userJob.status, value, button]);
387
+ }, [userJob, value, button]);
392
388
 
393
389
  return <ManualActionStatusContext.Provider value={value}>{children}</ManualActionStatusContext.Provider>;
394
390
  }
@@ -398,21 +394,21 @@ function useSubmit() {
398
394
  const { setVisible } = useActionContext();
399
395
  const { values, submit } = useForm();
400
396
  const buttonSchema = useFieldSchema();
401
- const nextStatus = useContext(ManualActionStatusContext);
402
397
  const { service } = useTableBlockContext();
403
398
  const { userJob } = useFlowContext();
404
- const { updateAssociationValues } = useContext(FormBlockContext);
399
+ const { name: actionKey } = buttonSchema;
400
+ const { name: formKey } = buttonSchema.parent.parent;
405
401
  return {
406
402
  async run() {
403
+ if (userJob.status) {
404
+ return;
405
+ }
407
406
  await submit();
408
- const { name } = buttonSchema.parent.parent.toJSON();
409
407
  await api.resource('users_jobs').submit({
410
408
  filterByTk: userJob.id,
411
409
  values: {
412
- status: nextStatus,
413
- result: { [name]: values },
410
+ result: { [formKey]: values, _: actionKey },
414
411
  },
415
- updateAssociationValues,
416
412
  });
417
413
  setVisible(false);
418
414
  service.refresh();
@@ -464,8 +460,9 @@ function FlowContextProvider(props) {
464
460
  DetailsBlockProvider,
465
461
  ActionBarProvider,
466
462
  ManualActionStatusProvider,
463
+ // @ts-ignore
467
464
  ...Array.from(manualFormTypes.getValues()).reduce(
468
- (result, item) => Object.assign(result, item.block.components),
465
+ (result, item: ManualFormType) => Object.assign(result, item.block.components),
469
466
  {},
470
467
  ),
471
468
  ...nodeComponents,
@@ -474,8 +471,9 @@ function FlowContextProvider(props) {
474
471
  useSubmit,
475
472
  useFormBlockProps,
476
473
  useDetailsBlockProps,
474
+ // @ts-ignore
477
475
  ...Array.from(manualFormTypes.getValues()).reduce(
478
- (result, item) => Object.assign(result, item.block.scope),
476
+ (result, item: ManualFormType) => Object.assign(result, item.block.scope),
479
477
  {},
480
478
  ),
481
479
  }}
@@ -518,40 +516,33 @@ function useDetailsBlockProps() {
518
516
  return { form };
519
517
  }
520
518
 
519
+ function FooterStatus() {
520
+ const compile = useCompile();
521
+ const { status, updatedAt } = useRecord();
522
+ const statusOption = JobStatusOptionsMap[status];
523
+ return status ? (
524
+ <Space>
525
+ <time
526
+ className={css`
527
+ margin-right: 0.5em;
528
+ `}
529
+ >
530
+ {dayjs(updatedAt).format('YYYY-MM-DD HH:mm:ss')}
531
+ </time>
532
+ <Tag icon={statusOption.icon} color={statusOption.color}>{compile(statusOption.label)}</Tag>
533
+ </Space>
534
+ ) : null;
535
+ }
536
+
521
537
  function Drawer() {
522
538
  const ctx = useContext(SchemaComponentContext);
523
- const { id, node, workflow, status, updatedAt } = useRecord();
524
-
525
- const statusOption = JobStatusOptionsMap[status];
526
- const footerSchema = status
527
- ? {
528
- date: {
529
- type: 'void',
530
- 'x-component': 'time',
531
- 'x-component-props': {
532
- className: css`
533
- margin-right: 0.5em;
534
- `,
535
- },
536
- 'x-content': dayjs(updatedAt).format('YYYY-MM-DD HH:mm:ss'),
537
- },
538
- status: {
539
- type: 'void',
540
- 'x-component': 'Tag',
541
- 'x-component-props': {
542
- icon: statusOption.icon,
543
- color: statusOption.color,
544
- },
545
- 'x-content': statusOption.label,
546
- },
547
- }
548
- : null;
539
+ const { id, node, workflow, status } = useRecord();
549
540
 
550
541
  return (
551
542
  <SchemaComponentContext.Provider value={{ ...ctx, reset() {}, designable: false }}>
552
543
  <SchemaComponent
553
544
  components={{
554
- Tag,
545
+ FooterStatus,
555
546
  FlowContextProvider,
556
547
  }}
557
548
  schema={{
@@ -570,7 +561,12 @@ function Drawer() {
570
561
  footer: {
571
562
  type: 'void',
572
563
  'x-component': 'Action.Drawer.Footer',
573
- properties: footerSchema,
564
+ properties: {
565
+ content: {
566
+ type: 'void',
567
+ 'x-component': 'FooterStatus',
568
+ }
569
+ },
574
570
  },
575
571
  },
576
572
  }}
@@ -71,7 +71,11 @@ export default {
71
71
  type: 'create',
72
72
  title: formBlock['x-component-props']?.title || formKey,
73
73
  actions: findSchema(formSchema.properties.actions, (item) => item['x-component'] === 'Action').map(
74
- (item) => item['x-decorator-props'].value,
74
+ (item) => ({
75
+ status: item['x-decorator-props'].value,
76
+ values: item['x-action-settings']?.assignedValues?.values,
77
+ key: item.name,
78
+ }),
75
79
  ),
76
80
  collection: formBlock['x-decorator-props'].collection,
77
81
  };
@@ -105,6 +105,7 @@ function CustomFormBlockInitializer({ insert, ...props }) {
105
105
  layout: 'one-column',
106
106
  style: {
107
107
  marginTop: '1.5em',
108
+ flexWrap: 'wrap',
108
109
  },
109
110
  },
110
111
  'x-initializer': 'AddActionButton',
@@ -121,8 +122,7 @@ function CustomFormBlockInitializer({ insert, ...props }) {
121
122
  type: 'primary',
122
123
  useAction: '{{ useSubmit }}',
123
124
  },
124
- 'x-designer': 'Action.Designer',
125
- 'x-action': `${JOB_STATUS.RESOLVED}`,
125
+ 'x-designer': 'ManualActionDesigner',
126
126
  },
127
127
  },
128
128
  },
@@ -371,7 +371,11 @@ export default {
371
371
  type: 'custom',
372
372
  title: formBlock['x-component-props']?.title || formKey,
373
373
  actions: findSchema(formSchema.properties.actions, (item) => item['x-component'] === 'Action').map(
374
- (item) => item['x-decorator-props'].value,
374
+ (item) => ({
375
+ status: item['x-decorator-props'].value,
376
+ values: item['x-action-settings']?.assignedValues?.values,
377
+ key: item.name,
378
+ }),
375
379
  ),
376
380
  collection: formBlock['x-decorator-props'].collection,
377
381
  };
@@ -114,7 +114,11 @@ export default {
114
114
  type: 'update',
115
115
  title: formBlock['x-component-props']?.title || formKey,
116
116
  actions: findSchema(formSchema.properties.actions, (item) => item['x-component'] === 'Action').map(
117
- (item) => item['x-decorator-props'].value,
117
+ (item) => ({
118
+ status: item['x-decorator-props'].value,
119
+ values: item['x-action-settings']?.assignedValues?.values,
120
+ key: item.name,
121
+ }),
118
122
  ),
119
123
  };
120
124
  });