@nocobase/client 0.7.0-alpha.80 → 0.7.0-alpha.83

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 (95) hide show
  1. package/es/acl/ACLProvider.js +10 -15
  2. package/es/antd-config-provider/index.js +7 -4
  3. package/es/api-client/APIClient.d.ts +2 -30
  4. package/es/api-client/APIClient.js +30 -158
  5. package/es/api-client/hooks/useResource.d.ts +1 -1
  6. package/es/block-provider/hooks/index.d.ts +3 -0
  7. package/es/block-provider/hooks/index.js +233 -168
  8. package/es/collection-manager/Configuration/AddFieldAction.js +27 -9
  9. package/es/collection-manager/Configuration/EditFieldAction.js +25 -8
  10. package/es/collection-manager/hooks/useCollection.d.ts +1 -1
  11. package/es/i18n/i18n.js +3 -3
  12. package/es/locale/en_US.d.ts +10 -0
  13. package/es/locale/en_US.js +11 -1
  14. package/es/locale/index.d.ts +44 -0
  15. package/es/locale/zh_CN.d.ts +34 -0
  16. package/es/locale/zh_CN.js +35 -1
  17. package/es/schema-component/antd/action/Action.Designer.js +33 -13
  18. package/es/schema-component/antd/action/utils.d.ts +2 -0
  19. package/es/schema-component/antd/action/utils.js +60 -0
  20. package/es/schema-component/antd/date-picker/util.d.ts +2 -1
  21. package/es/schema-component/antd/date-picker/util.js +4 -2
  22. package/es/schema-initializer/buttons/FormActionInitializers.d.ts +84 -0
  23. package/es/schema-initializer/buttons/FormActionInitializers.js +63 -0
  24. package/es/schema-initializer/buttons/ReadPrettyFormActionInitializers.d.ts +26 -0
  25. package/es/schema-initializer/buttons/ReadPrettyFormActionInitializers.js +21 -0
  26. package/es/schema-initializer/buttons/TableActionColumnInitializers.js +21 -0
  27. package/es/schema-settings/SchemaSettings.js +48 -16
  28. package/es/user/CurrentUser.js +1 -1
  29. package/es/user/LanguageSettings.js +4 -3
  30. package/es/user/SigninPage.js +3 -14
  31. package/es/user/SwitchRole.js +2 -26
  32. package/es/workflow/triggers/collection.js +1 -0
  33. package/es/workflow/triggers/index.js +2 -0
  34. package/es/workflow/triggers/schedule.d.ts +25 -0
  35. package/es/workflow/triggers/schedule.js +531 -0
  36. package/lib/acl/ACLProvider.js +9 -15
  37. package/lib/antd-config-provider/index.js +6 -3
  38. package/lib/api-client/APIClient.d.ts +2 -30
  39. package/lib/api-client/APIClient.js +26 -160
  40. package/lib/api-client/hooks/useResource.d.ts +1 -1
  41. package/lib/block-provider/hooks/index.d.ts +3 -0
  42. package/lib/block-provider/hooks/index.js +238 -169
  43. package/lib/collection-manager/Configuration/AddFieldAction.js +27 -9
  44. package/lib/collection-manager/Configuration/EditFieldAction.js +25 -8
  45. package/lib/collection-manager/hooks/useCollection.d.ts +1 -1
  46. package/lib/i18n/i18n.js +3 -3
  47. package/lib/locale/en_US.d.ts +10 -0
  48. package/lib/locale/en_US.js +11 -1
  49. package/lib/locale/index.d.ts +44 -0
  50. package/lib/locale/zh_CN.d.ts +34 -0
  51. package/lib/locale/zh_CN.js +35 -1
  52. package/lib/schema-component/antd/action/Action.Designer.js +34 -13
  53. package/lib/schema-component/antd/action/utils.d.ts +2 -0
  54. package/lib/schema-component/antd/action/utils.js +67 -0
  55. package/lib/schema-component/antd/date-picker/util.d.ts +2 -1
  56. package/lib/schema-component/antd/date-picker/util.js +6 -1
  57. package/lib/schema-initializer/buttons/FormActionInitializers.d.ts +84 -0
  58. package/lib/schema-initializer/buttons/FormActionInitializers.js +63 -0
  59. package/lib/schema-initializer/buttons/ReadPrettyFormActionInitializers.d.ts +26 -0
  60. package/lib/schema-initializer/buttons/ReadPrettyFormActionInitializers.js +21 -0
  61. package/lib/schema-initializer/buttons/TableActionColumnInitializers.js +21 -0
  62. package/lib/schema-settings/SchemaSettings.js +49 -16
  63. package/lib/user/CurrentUser.js +1 -1
  64. package/lib/user/LanguageSettings.js +4 -3
  65. package/lib/user/SigninPage.js +3 -14
  66. package/lib/user/SwitchRole.js +2 -27
  67. package/lib/workflow/triggers/collection.js +1 -0
  68. package/lib/workflow/triggers/index.js +3 -0
  69. package/lib/workflow/triggers/schedule.d.ts +25 -0
  70. package/lib/workflow/triggers/schedule.js +554 -0
  71. package/package.json +4 -3
  72. package/src/acl/ACLProvider.tsx +4 -5
  73. package/src/antd-config-provider/index.tsx +4 -2
  74. package/src/api-client/APIClient.ts +2 -120
  75. package/src/block-provider/hooks/index.ts +106 -69
  76. package/src/collection-manager/Configuration/AddFieldAction.tsx +18 -0
  77. package/src/collection-manager/Configuration/EditFieldAction.tsx +19 -0
  78. package/src/i18n/i18n.ts +3 -3
  79. package/src/locale/en_US.ts +11 -1
  80. package/src/locale/zh_CN.ts +39 -1
  81. package/src/schema-component/antd/action/Action.Designer.tsx +33 -1
  82. package/src/schema-component/antd/action/utils.ts +68 -0
  83. package/src/schema-component/antd/date-picker/util.ts +4 -3
  84. package/src/schema-initializer/SchemaInitializer.tsx +2 -2
  85. package/src/schema-initializer/buttons/FormActionInitializers.tsx +66 -0
  86. package/src/schema-initializer/buttons/ReadPrettyFormActionInitializers.tsx +22 -0
  87. package/src/schema-initializer/buttons/TableActionColumnInitializers.tsx +22 -0
  88. package/src/schema-settings/SchemaSettings.tsx +40 -29
  89. package/src/user/CurrentUser.tsx +1 -1
  90. package/src/user/LanguageSettings.tsx +1 -0
  91. package/src/user/SigninPage.tsx +2 -7
  92. package/src/user/SwitchRole.tsx +2 -6
  93. package/src/workflow/triggers/collection.tsx +1 -1
  94. package/src/workflow/triggers/index.tsx +2 -0
  95. package/src/workflow/triggers/schedule.tsx +422 -0
@@ -1,124 +1,6 @@
1
- import { observable } from '@formily/reactive';
1
+ import { APIClient as APIClientSDK } from '@nocobase/sdk';
2
2
  import { Result } from 'ahooks/lib/useRequest/src/types';
3
- import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
4
- import Cookies from 'js-cookie';
5
- import qs from 'qs';
6
-
7
- export interface ActionParams {
8
- filterByTk?: any;
9
- [key: string]: any;
10
- }
11
-
12
- type ResourceActionOptions<P = any> = {
13
- resource?: string;
14
- resourceOf?: any;
15
- action?: string;
16
- params?: P;
17
- };
18
-
19
- export interface IResource {
20
- list?: (params?: ActionParams) => Promise<any>;
21
- get?: (params?: ActionParams) => Promise<any>;
22
- create?: (params?: ActionParams) => Promise<any>;
23
- update?: (params?: ActionParams) => Promise<any>;
24
- destroy?: (params?: ActionParams) => Promise<any>;
25
- [key: string]: (params?: ActionParams) => Promise<any>;
26
- }
27
-
28
- export class APIClient {
29
- axios: AxiosInstance;
30
3
 
4
+ export class APIClient extends APIClientSDK {
31
5
  services: Record<string, Result<any, any>>;
32
-
33
- tokenKey = 'NOCOBASE_TOKEN';
34
-
35
- constructor(instance?: AxiosInstance | AxiosRequestConfig) {
36
- this.services = observable({});
37
- if (typeof instance === 'function') {
38
- this.axios = instance;
39
- } else {
40
- this.axios = axios.create(instance);
41
- }
42
- this.qsMiddleware();
43
- this.authMiddleware();
44
- }
45
-
46
- qsMiddleware() {
47
- this.axios.interceptors.request.use((config) => {
48
- config.paramsSerializer = (params) => {
49
- return qs.stringify(params, {
50
- strictNullHandling: true,
51
- arrayFormat: 'brackets',
52
- });
53
- };
54
- return config;
55
- });
56
- }
57
-
58
- // TODO
59
- authMiddleware() {
60
- this.axios.interceptors.request.use((config) => {
61
- const token = localStorage.getItem(this.tokenKey);
62
- config.headers['X-Locale'] = localStorage.getItem('NOCOBASE_LANG');
63
- config.headers['X-Hostname'] = window.location.hostname;
64
- if (token) {
65
- config.headers['Authorization'] = `Bearer ${token}`;
66
- }
67
- const currentRoleName = Cookies.get('currentRoleName');
68
- if (currentRoleName) {
69
- config.headers['X-Role'] = currentRoleName;
70
- }
71
- return config;
72
- });
73
- }
74
-
75
- // TODO
76
- setBearerToken(token: any) {
77
- localStorage.setItem(this.tokenKey, token || '');
78
- Cookies.remove('currentRoleName');
79
- }
80
-
81
- service(uid: string): Result<any, any> {
82
- return this.services[uid];
83
- }
84
-
85
- request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D> | ResourceActionOptions): Promise<R> {
86
- const { resource, resourceOf, action, params } = config as any;
87
- if (resource) {
88
- return this.resource(resource, resourceOf)[action](params);
89
- }
90
- return this.axios.request<T, R, D>(config);
91
- }
92
-
93
- resource(name: string, of?: any): IResource {
94
- const target = {};
95
- const handler = {
96
- get: (_: any, actionName: string) => {
97
- let url = name.split('.').join(`/${of || '_'}/`);
98
- url += `:${actionName}`;
99
- const config: AxiosRequestConfig = { url };
100
- if (['get', 'list'].includes(actionName)) {
101
- config['method'] = 'get';
102
- } else {
103
- config['method'] = 'post';
104
- }
105
- return async (params?: ActionParams) => {
106
- const { values, filter, ...others } = params || {};
107
- config['params'] = others;
108
- if (filter) {
109
- if (typeof filter === 'string') {
110
- config['params']['filter'] = filter;
111
- } else {
112
- config['params']['filter'] = JSON.stringify(filter);
113
- }
114
- }
115
- if (config.method !== 'get') {
116
- config['data'] = values || {};
117
- }
118
- return await this.request(config);
119
- };
120
- },
121
- };
122
- return new Proxy(target, handler);
123
- }
124
6
  }
@@ -2,6 +2,7 @@ import { useField, useFieldSchema, useForm } from '@formily/react';
2
2
  import { message, Modal } from 'antd';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import { useHistory } from 'react-router-dom';
5
+ import { useAPIClient } from '../../api-client';
5
6
  import { useCollection } from '../../collection-manager';
6
7
  import { useRecord } from '../../record-provider';
7
8
  import { useActionContext, useCompile } from '../../schema-component';
@@ -54,6 +55,50 @@ const filterValue = (value) => {
54
55
  return obj;
55
56
  };
56
57
 
58
+ function getFormValues(filterByTk, field, form, fieldNames, getField, resource) {
59
+ let values = {};
60
+ for (const key in form.values) {
61
+ if (fieldNames.includes(key)) {
62
+ const collectionField = getField(key);
63
+ if (filterByTk) {
64
+ if (collectionField.interface === 'subTable') {
65
+ values[key] = form.values[key];
66
+ continue;
67
+ }
68
+ if (field.added && !field.added.has(key)) {
69
+ continue;
70
+ }
71
+ }
72
+ const items = form.values[key];
73
+ if (collectionField.interface === 'linkTo') {
74
+ const targetKey = collectionField.targetKey || 'id';
75
+ if (resource instanceof TableFieldResource) {
76
+ if (Array.isArray(items)) {
77
+ values[key] = filterValue(items);
78
+ } else if (items && typeof items === 'object') {
79
+ values[key] = filterValue(items);
80
+ } else {
81
+ values[key] = items;
82
+ }
83
+ } else {
84
+ if (Array.isArray(items)) {
85
+ values[key] = items.map((item) => item[targetKey]);
86
+ } else if (items && typeof items === 'object') {
87
+ values[key] = items[targetKey];
88
+ } else {
89
+ values[key] = items;
90
+ }
91
+ }
92
+ } else {
93
+ values[key] = form.values[key];
94
+ }
95
+ } else {
96
+ values[key] = form.values[key];
97
+ }
98
+ }
99
+ return values;
100
+ }
101
+
57
102
  export const useCreateActionProps = () => {
58
103
  const form = useForm();
59
104
  const { field, resource, __parent } = useBlockRequestContext();
@@ -64,6 +109,7 @@ export const useCreateActionProps = () => {
64
109
  const actionField = useField();
65
110
  const { fields, getField } = useCollection();
66
111
  const compile = useCompile();
112
+ const filterByTk = useFilterByTk();
67
113
  return {
68
114
  async onClick() {
69
115
  const fieldNames = fields.map((field) => field.name);
@@ -72,37 +118,7 @@ export const useCreateActionProps = () => {
72
118
  if (!skipValidator) {
73
119
  await form.submit();
74
120
  }
75
- let values = {};
76
- for (const key in form.values) {
77
- if (fieldNames.includes(key)) {
78
- const items = form.values[key];
79
- const collectionField = getField(key);
80
- if (collectionField.interface === 'linkTo') {
81
- const targetKey = collectionField.targetKey || 'id';
82
- if (resource instanceof TableFieldResource) {
83
- if (Array.isArray(items)) {
84
- values[key] = filterValue(items);
85
- } else if (items && typeof items === 'object') {
86
- values[key] = filterValue(items);
87
- } else {
88
- values[key] = items;
89
- }
90
- } else {
91
- if (Array.isArray(items)) {
92
- values[key] = items.map((item) => item[targetKey]);
93
- } else if (items && typeof items === 'object') {
94
- values[key] = items[targetKey];
95
- } else {
96
- values[key] = items;
97
- }
98
- }
99
- } else {
100
- values[key] = form.values[key];
101
- }
102
- } else {
103
- values[key] = form.values[key];
104
- }
105
- }
121
+ const values = getFormValues(filterByTk, field, form, fieldNames, getField, resource);
106
122
  actionField.data = field.data || {};
107
123
  actionField.data.loading = true;
108
124
  await resource.create({
@@ -186,6 +202,64 @@ export const useCustomizeUpdateActionProps = () => {
186
202
  };
187
203
  };
188
204
 
205
+ export const useCustomizeRequestActionProps = () => {
206
+ const apiClient = useAPIClient();
207
+ const history = useHistory();
208
+ const filterByTk = useFilterByTk();
209
+ const actionSchema = useFieldSchema();
210
+ const compile = useCompile();
211
+ const form = useForm();
212
+ const { fields, getField } = useCollection();
213
+ const { field, resource } = useBlockRequestContext();
214
+ return {
215
+ async onClick() {
216
+ const { skipValidator, onSuccess, requestSettings } = actionSchema?.['x-action-settings'] ?? {};
217
+ if (!requestSettings['url']) {
218
+ return;
219
+ }
220
+ if (skipValidator === false) {
221
+ await form.submit();
222
+ }
223
+
224
+ const headers = requestSettings['headers'] ? JSON.parse(requestSettings['headers']) : {};
225
+ const params = requestSettings['params'] ? JSON.parse(requestSettings['params']) : {};
226
+ const data = requestSettings['data'] ? JSON.parse(requestSettings['data']) : {};
227
+ const methods = ['POST', 'PUT', 'PATCH'];
228
+ if (actionSchema['x-action'] === 'customize:form:request' && methods.includes(requestSettings['method'])) {
229
+ const fieldNames = fields.map((field) => field.name);
230
+ const values = getFormValues(filterByTk, field, form, fieldNames, getField, resource);
231
+ Object.assign(data, values);
232
+ }
233
+ await apiClient.request({
234
+ ...requestSettings,
235
+ headers,
236
+ params,
237
+ data,
238
+ });
239
+
240
+ if (!onSuccess?.successMessage) {
241
+ return;
242
+ }
243
+ if (onSuccess?.manualClose) {
244
+ Modal.success({
245
+ title: compile(onSuccess?.successMessage),
246
+ onOk: async () => {
247
+ if (onSuccess?.redirecting && onSuccess?.redirectTo) {
248
+ if (isURL(onSuccess.redirectTo)) {
249
+ window.location.href = onSuccess.redirectTo;
250
+ } else {
251
+ history.push(onSuccess.redirectTo);
252
+ }
253
+ }
254
+ },
255
+ });
256
+ } else {
257
+ message.success(compile(onSuccess?.successMessage));
258
+ }
259
+ },
260
+ };
261
+ };
262
+
189
263
  export const useUpdateActionProps = () => {
190
264
  const form = useForm();
191
265
  const filterByTk = useFilterByTk();
@@ -204,44 +278,7 @@ export const useUpdateActionProps = () => {
204
278
  await form.submit();
205
279
  }
206
280
  const fieldNames = fields.map((field) => field.name);
207
- let values = {};
208
- for (const key in form.values) {
209
- if (fieldNames.includes(key)) {
210
- const collectionField = getField(key);
211
- if (collectionField.interface === 'subTable') {
212
- values[key] = form.values[key];
213
- continue;
214
- }
215
- if (field.added && !field.added.has(key)) {
216
- continue;
217
- }
218
- const items = form.values[key];
219
- if (collectionField.interface === 'linkTo') {
220
- const targetKey = collectionField.targetKey || 'id';
221
- if (resource instanceof TableFieldResource) {
222
- if (Array.isArray(items)) {
223
- values[key] = filterValue(items);
224
- } else if (items && typeof items === 'object') {
225
- values[key] = filterValue(items);
226
- } else {
227
- values[key] = items;
228
- }
229
- } else {
230
- if (Array.isArray(items)) {
231
- values[key] = items.map((item) => item[targetKey]);
232
- } else if (items && typeof items === 'object') {
233
- values[key] = items[targetKey];
234
- } else {
235
- values[key] = items;
236
- }
237
- }
238
- } else {
239
- values[key] = form.values[key];
240
- }
241
- } else {
242
- values[key] = form.values[key];
243
- }
244
- }
281
+ const values = getFormValues(filterByTk, field, form, fieldNames, getField, resource);
245
282
  actionField.data = field.data || {};
246
283
  actionField.data.loading = true;
247
284
  await resource.update({
@@ -94,6 +94,24 @@ const useCreateCollectionField = () => {
94
94
  }),
95
95
  );
96
96
  }
97
+ function recursiveChildren(children = [], prefix = 'children') {
98
+ children.forEach((item, index) => {
99
+ const itemOptions = item.uiSchema?.enum?.slice() || [];
100
+ form.setValuesIn(
101
+ `${prefix}[${index}].uiSchema.enum`,
102
+ itemOptions.map((option) => {
103
+ return {
104
+ value: uid(),
105
+ ...option,
106
+ };
107
+ }),
108
+ );
109
+ recursiveChildren(item.children, `${prefix}[${index}].children`);
110
+ });
111
+ }
112
+
113
+ recursiveChildren(form?.values?.children);
114
+
97
115
  if (form?.values?.interface === 'linkTo' && title) {
98
116
  form.setValuesIn('reverseField.uiSchema.title', title);
99
117
  }
@@ -83,6 +83,25 @@ const useUpdateCollectionField = () => {
83
83
  };
84
84
  }),
85
85
  );
86
+
87
+ function recursiveChildren(children = [], prefix = 'children') {
88
+ children.forEach((item, index) => {
89
+ const itemOptions = item.uiSchema?.enum?.slice() || [];
90
+ form.setValuesIn(
91
+ `${prefix}[${index}].uiSchema.enum`,
92
+ itemOptions.map((option) => {
93
+ return {
94
+ value: uid(),
95
+ ...option,
96
+ };
97
+ }),
98
+ );
99
+ recursiveChildren(item.children, `${prefix}[${index}].children`);
100
+ });
101
+ }
102
+
103
+ recursiveChildren(form?.values?.children);
104
+
86
105
  await run();
87
106
  await refreshCM();
88
107
  },
package/src/i18n/i18n.ts CHANGED
@@ -7,7 +7,7 @@ const log = require('debug')('i18next');
7
7
  export const i18n = i18next.createInstance();
8
8
 
9
9
  i18n.use(initReactI18next).init({
10
- lng: localStorage.getItem('NOCOBASE_LANG') || 'en-US',
10
+ lng: localStorage.getItem('NOCOBASE_LOCALE') || 'en-US',
11
11
  // debug: true,
12
12
  defaultNS: 'client',
13
13
  // parseMissingKeyHandler: (key) => {
@@ -29,9 +29,9 @@ function setMomentLng(language) {
29
29
  moment.locale(lng);
30
30
  }
31
31
 
32
- setMomentLng(localStorage.getItem('NOCOBASE_LANG'));
32
+ setMomentLng(localStorage.getItem('NOCOBASE_LOCALE'));
33
33
 
34
34
  i18n.on('languageChanged', (lng) => {
35
- localStorage.setItem('NOCOBASE_LANG', lng);
35
+ localStorage.setItem('NOCOBASE_LOCALE', lng);
36
36
  setMomentLng(lng);
37
37
  });
@@ -301,5 +301,15 @@ export default {
301
301
  'After successful save': 'After successful save',
302
302
  'Button background color': 'Button background color',
303
303
  'Highlight': 'Highlight',
304
- 'Danger red': 'Danger red'
304
+ 'Danger red': 'Danger red',
305
+ 'Custom request': 'Custom request',
306
+ 'Request settings': 'Request settings',
307
+ 'Request URL': 'Request URL',
308
+ 'Request method': 'Request method',
309
+ 'Request query parameters': 'Request query parameters(JSON)',
310
+ 'Request headers': 'Request headers(JSON)',
311
+ 'Request body': 'Request body(JSON)',
312
+ 'Request success': 'Request success',
313
+ 'Invalid JSON format': 'Invalid JSON format',
314
+ 'After successful request': 'After successful request'
305
315
  }
@@ -432,6 +432,34 @@ export default {
432
432
  'Triggered only if one of the selected fields changes. If unselected, it means that it will be triggered when any field changes. When record is added or deleted, any field is considered to have been changed.': '只有被选中的某个字段发生变动时才会触发。如果不选择,则表示任何字段变动时都会触发。新增或删除数据时,任意字段都被认为发生变动。',
433
433
  'Only triggers when match conditions': '满足以下条件才触发',
434
434
 
435
+ 'Schedule event': '定时任务',
436
+ 'Trigger mode': '触发模式',
437
+ 'Based on certain date': '自定义时间',
438
+ 'Based on date field of collection': '根据数据表时间字段',
439
+ 'Starts on': '开始于',
440
+ 'Ends on': '结束于',
441
+ 'Exactly at': '当时',
442
+ 'Repeat mode': '重复模式',
443
+ 'Repeat limit': '重复次数',
444
+ 'No limit': '不限',
445
+ 'Seconds': '秒',
446
+ 'Minutes': '分钟',
447
+ 'Hours': '小时',
448
+ 'Days': '天',
449
+ 'Months': '月',
450
+
451
+ 'No repeat': '不重复',
452
+ 'Every': '每',
453
+
454
+ 'By minute': '按分钟',
455
+ 'By hour': '按小时',
456
+ 'By date': '按日(月)',
457
+ 'By month': '按月',
458
+ 'By day of week': '按天(周)',
459
+
460
+ 'By field': '数据表字段',
461
+ 'By custom date': '自定义时间',
462
+
435
463
  'End': '结束',
436
464
 
437
465
  'Trigger context': '触发数据',
@@ -508,5 +536,15 @@ export default {
508
536
  'After clicking the custom button, the following fields of the current record will be saved according to the following form.': '点击当前自定义按钮时,当前数据以下字段将按照以下表单保存。',
509
537
  'Button background color': '按钮颜色',
510
538
  'Highlight': '高亮',
511
- 'Danger red': '红色'
539
+ 'Danger red': '红色',
540
+ 'Custom request': '自定义请求',
541
+ 'Request settings': '请求设置',
542
+ 'Request URL': '请求地址',
543
+ 'Request method': '请求方法',
544
+ 'Request query parameters': '请求查询参数(JSON格式)',
545
+ 'Request headers': '请求头参数(JSON格式)',
546
+ 'Request body': '请求体(JSON格式)',
547
+ 'Request success': '请求成功',
548
+ 'Invalid JSON format': '非法JSON格式',
549
+ 'After successful request': '请求成功之后'
512
550
  }
@@ -6,6 +6,7 @@ import React, { useEffect, useState } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { useActionContext, useCompile, useDesignable } from '../..';
8
8
  import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
9
+ import { requestSettingsSchema } from './utils';
9
10
 
10
11
  const MenuGroup = (props) => {
11
12
  const fieldSchema = useFieldSchema();
@@ -15,8 +16,18 @@ const MenuGroup = (props) => {
15
16
  'customize:popup': t('Popup'),
16
17
  'customize:update': t('Update record'),
17
18
  'customize:save': t('Save record'),
19
+ 'customize:table:request': t('Custom request'),
20
+ 'customize:form:request': t('Custom request'),
18
21
  };
19
- if (!['customize:popup', 'customize:update', 'customize:save'].includes(actionType)) {
22
+ if (
23
+ ![
24
+ 'customize:popup',
25
+ 'customize:update',
26
+ 'customize:save',
27
+ 'customize:table:request',
28
+ 'customize:form:request',
29
+ ].includes(actionType)
30
+ ) {
20
31
  return <>{props.children}</>;
21
32
  }
22
33
  return <Menu.ItemGroup title={`${t('Customize')} > ${actionTitles[actionType]}`}>{props.children}</Menu.ItemGroup>;
@@ -162,6 +173,23 @@ export const ActionDesigner = (props) => {
162
173
  }}
163
174
  />
164
175
  )}
176
+ {isValid(fieldSchema?.['x-action-settings']?.requestSettings) && (
177
+ <SchemaSettings.ActionModalItem
178
+ title={t('Request settings')}
179
+ schema={requestSettingsSchema}
180
+ initialValues={fieldSchema?.['x-action-settings']?.requestSettings}
181
+ onSubmit={(requestSettings) => {
182
+ fieldSchema['x-action-settings']['requestSettings'] = requestSettings;
183
+ dn.emit('patch', {
184
+ schema: {
185
+ ['x-uid']: fieldSchema['x-uid'],
186
+ 'x-action-settings': fieldSchema['x-action-settings'],
187
+ },
188
+ });
189
+ dn.refresh();
190
+ }}
191
+ />
192
+ )}
165
193
  {isValid(fieldSchema?.['x-action-settings']?.skipValidator) && (
166
194
  <SchemaSettings.SwitchItem
167
195
  title={t('Skip required validation')}
@@ -218,6 +246,8 @@ export const ActionDesigner = (props) => {
218
246
  {
219
247
  'customize:save': t('After successful save'),
220
248
  'customize:update': t('After successful update'),
249
+ 'customize:table:request': t('After successful request'),
250
+ 'customize:form:request': t('After successful request'),
221
251
  }[actionType]
222
252
  }
223
253
  initialValues={fieldSchema?.['x-action-settings']?.['onSuccess']}
@@ -227,6 +257,8 @@ export const ActionDesigner = (props) => {
227
257
  title: {
228
258
  'customize:save': t('After successful save'),
229
259
  'customize:update': t('After successful update'),
260
+ 'customize:table:request': t('After successful request'),
261
+ 'customize:form:request': t('After successful request'),
230
262
  }[actionType],
231
263
  properties: {
232
264
  successMessage: {
@@ -0,0 +1,68 @@
1
+ import type { ISchema } from '@formily/react';
2
+
3
+ const validateJSON = {
4
+ validator: `{{(value, rule)=> {
5
+ if (!value) {
6
+ return '';
7
+ }
8
+ try {
9
+ const val = JSON.parse(value);
10
+ if(!isNaN(val)) {
11
+ return false;
12
+ }
13
+ return true;
14
+ } catch(error) {
15
+ console.error(error);
16
+ return false;
17
+ }
18
+ }}}`,
19
+ message: '{{t("Invalid JSON format")}}',
20
+ };
21
+
22
+ export const requestSettingsSchema: ISchema = {
23
+ type: 'object',
24
+ properties: {
25
+ url: {
26
+ type: 'string',
27
+ title: '{{t("Request URL")}}',
28
+ required: true,
29
+ 'x-decorator': 'FormItem',
30
+ 'x-component': 'Input',
31
+ },
32
+ method: {
33
+ type: 'string',
34
+ title: '{{t("Request method")}}',
35
+ 'x-decorator': 'FormItem',
36
+ 'x-component': 'Select',
37
+ default: 'POST',
38
+ enum: [
39
+ { label: 'POST', value: 'POST' },
40
+ { label: 'GET', value: 'GET' },
41
+ { label: 'PUT', value: 'PUT' },
42
+ { label: 'PATCH', value: 'PATCH' },
43
+ { label: 'DELETE', value: 'DELETE' },
44
+ ],
45
+ },
46
+ headers: {
47
+ type: 'string',
48
+ title: '{{t("Request headers")}}',
49
+ 'x-decorator': 'FormItem',
50
+ 'x-component': 'Input.TextArea',
51
+ 'x-validator': validateJSON,
52
+ },
53
+ params: {
54
+ type: 'string',
55
+ title: '{{t("Request query parameters")}}',
56
+ 'x-decorator': 'FormItem',
57
+ 'x-component': 'Input.TextArea',
58
+ 'x-validator': validateJSON,
59
+ },
60
+ data: {
61
+ type: 'string',
62
+ title: '{{t("Request body")}}',
63
+ 'x-decorator': 'FormItem',
64
+ 'x-component': 'Input.TextArea',
65
+ 'x-validator': validateJSON,
66
+ },
67
+ },
68
+ };
@@ -1,5 +1,6 @@
1
- import { formatMomentValue, momentable } from '@formily/antd/lib/__builtins__';
1
+ import { formatMomentValue } from '@formily/antd/lib/__builtins__';
2
2
  import type { DatePickerProps } from 'antd/lib/date-picker';
3
+ import moment from 'moment';
3
4
 
4
5
  export const getDefaultFormat = (props: DatePickerProps & { dateFormat: string; timeFormat: string }) => {
5
6
  if (props.format) {
@@ -30,8 +31,8 @@ export const mapDateFormat = function () {
30
31
  return {
31
32
  ...props,
32
33
  format: format,
33
-
34
- value: momentable(props.value, format === 'YYYY-wo' ? 'YYYY-w' : format),
34
+ value: props.value && moment(props.value).isValid() ? moment(props.value) : undefined,
35
+ // value: momentable(props.value, format === 'YYYY-wo' ? 'YYYY-w' : format),
35
36
  onChange: (value: moment.Moment | moment.Moment[]) => {
36
37
  if (onChange) {
37
38
  onChange(formatMomentValue(value, format));
@@ -9,7 +9,7 @@ import {
9
9
  SchemaInitializerButtonProps,
10
10
  SchemaInitializerItemComponent,
11
11
  SchemaInitializerItemOptions,
12
- SchemaInitializerItemProps
12
+ SchemaInitializerItemProps,
13
13
  } from './types';
14
14
 
15
15
  const defaultWrap = (s: ISchema) => s;
@@ -129,7 +129,7 @@ SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
129
129
  ...style,
130
130
  }}
131
131
  {...others}
132
- icon={<Icon type={icon as string}/>}
132
+ icon={<Icon type={icon as string} />}
133
133
  >
134
134
  {compile(props.children || props.title)}
135
135
  </Button>