@nocobase/plugin-ui-templates 2.1.0-beta.1 → 2.1.0-beta.10

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 (55) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +99 -0
  3. package/dist/client/index.js +1 -1
  4. package/dist/client/models/ReferenceBlockModel.d.ts +14 -0
  5. package/dist/externalVersion.js +7 -7
  6. package/package.json +3 -3
  7. package/LICENSE.txt +0 -172
  8. package/src/client/__tests__/openViewActionExtensions.test.ts +0 -1208
  9. package/src/client/collections/flowModelTemplates.ts +0 -131
  10. package/src/client/components/FlowModelTemplatesPage.tsx +0 -78
  11. package/src/client/components/TemplateSelectOption.tsx +0 -106
  12. package/src/client/constants.ts +0 -10
  13. package/src/client/hooks/useFlowModelTemplateActions.tsx +0 -137
  14. package/src/client/index.ts +0 -52
  15. package/src/client/locale.ts +0 -40
  16. package/src/client/menuExtensions.tsx +0 -1091
  17. package/src/client/models/ReferenceBlockModel.tsx +0 -841
  18. package/src/client/models/ReferenceFormGridModel.tsx +0 -448
  19. package/src/client/models/SubModelTemplateImporterModel.tsx +0 -725
  20. package/src/client/models/__tests__/ReferenceBlockModel.test.tsx +0 -547
  21. package/src/client/models/__tests__/ReferenceFormGridModel.test.tsx +0 -965
  22. package/src/client/models/__tests__/SubModelTemplateImporterModel.test.ts +0 -529
  23. package/src/client/models/referenceShared.tsx +0 -107
  24. package/src/client/openViewActionExtensions.tsx +0 -986
  25. package/src/client/schemas/flowModelTemplates.ts +0 -264
  26. package/src/client/utils/__tests__/templateCopy.test.ts +0 -67
  27. package/src/client/utils/infiniteSelect.ts +0 -150
  28. package/src/client/utils/templateCompatibility.ts +0 -374
  29. package/src/client/utils/templateCopy.ts +0 -59
  30. package/src/client.ts +0 -10
  31. package/src/index.ts +0 -11
  32. package/src/locale/de-DE.json +0 -14
  33. package/src/locale/en-US.json +0 -72
  34. package/src/locale/es-ES.json +0 -14
  35. package/src/locale/fr-FR.json +0 -14
  36. package/src/locale/hu-HU.json +0 -14
  37. package/src/locale/id-ID.json +0 -14
  38. package/src/locale/it-IT.json +0 -14
  39. package/src/locale/ja-JP.json +0 -14
  40. package/src/locale/ko-KR.json +0 -14
  41. package/src/locale/nl-NL.json +0 -14
  42. package/src/locale/pt-BR.json +0 -14
  43. package/src/locale/ru-RU.json +0 -14
  44. package/src/locale/tr-TR.json +0 -14
  45. package/src/locale/uk-UA.json +0 -14
  46. package/src/locale/vi-VN.json +0 -14
  47. package/src/locale/zh-CN.json +0 -71
  48. package/src/locale/zh-TW.json +0 -14
  49. package/src/server/__tests__/template-usage.test.ts +0 -351
  50. package/src/server/collections/flowModelTemplateUsages.ts +0 -51
  51. package/src/server/collections/flowModelTemplates.ts +0 -76
  52. package/src/server/index.ts +0 -10
  53. package/src/server/plugin.ts +0 -236
  54. package/src/server/resources/flowModelTemplateUsages.ts +0 -61
  55. package/src/server/resources/flowModelTemplates.ts +0 -251
@@ -1,264 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
- import { ISchema } from '@nocobase/client';
11
- import { uid } from '@nocobase/utils/client';
12
- import { flowModelTemplatesCollection } from '../collections/flowModelTemplates';
13
- import { tStr } from '../locale';
14
-
15
- export const flowModelTemplateEditActionSchema: ISchema = {
16
- type: 'void',
17
- title: tStr('Edit'),
18
- 'x-component': 'Action.Link',
19
- 'x-component-props': {
20
- openMode: 'drawer',
21
- },
22
- properties: {
23
- drawer: {
24
- type: 'void',
25
- title: tStr('Edit template'),
26
- 'x-component': 'Action.Drawer',
27
- 'x-decorator': 'FormV2',
28
- 'x-use-decorator-props': 'useFlowModelTemplateEditFormProps',
29
- properties: {
30
- name: {
31
- type: 'string',
32
- title: tStr('Template name'),
33
- 'x-decorator': 'FormItem',
34
- 'x-component': 'Input',
35
- required: true,
36
- },
37
- description: {
38
- type: 'string',
39
- title: tStr('Template description'),
40
- 'x-decorator': 'FormItem',
41
- 'x-component': 'Input.TextArea',
42
- 'x-component-props': {
43
- rows: 4,
44
- },
45
- },
46
- footer: {
47
- type: 'void',
48
- 'x-component': 'Action.Drawer.Footer',
49
- properties: {
50
- cancel: {
51
- title: '{{t("Cancel")}}',
52
- 'x-component': 'Action',
53
- 'x-component-props': {
54
- useAction: '{{ cm.useCancelAction }}',
55
- },
56
- },
57
- submit: {
58
- title: '{{t("Submit")}}',
59
- 'x-component': 'Action',
60
- 'x-use-component-props': 'useFlowModelTemplateEditActionProps',
61
- 'x-component-props': {
62
- type: 'primary',
63
- },
64
- },
65
- },
66
- },
67
- },
68
- },
69
- },
70
- };
71
-
72
- export const createFlowModelTemplatesSchema = (filter?: Record<string, any>): ISchema => ({
73
- type: 'void',
74
- name: uid(),
75
- 'x-component': 'CardItem',
76
- 'x-decorator': 'TableBlockProvider',
77
- 'x-decorator-props': {
78
- collection: flowModelTemplatesCollection.name,
79
- action: 'list',
80
- params: {
81
- sort: '-createdAt',
82
- pageSize: 50,
83
- ...(filter ? { filter } : {}),
84
- },
85
- showIndex: true,
86
- rowKey: flowModelTemplatesCollection.filterTargetKey,
87
- },
88
- properties: {
89
- actions: {
90
- type: 'void',
91
- 'x-component': 'ActionBar',
92
- 'x-component-props': {
93
- style: {
94
- marginBottom: 16,
95
- },
96
- },
97
- properties: {
98
- filter: {
99
- type: 'void',
100
- title: '{{ t("Filter") }}',
101
- default: {
102
- $and: [{ name: { $includes: '' } }],
103
- },
104
- 'x-action': 'filter',
105
- 'x-component': 'Filter.Action',
106
- 'x-use-component-props': 'useFilterActionProps',
107
- 'x-component-props': {
108
- icon: 'FilterOutlined',
109
- },
110
- 'x-align': 'left',
111
- },
112
- search: {
113
- type: 'void',
114
- 'x-component': 'Input.Search',
115
- 'x-component-props': {
116
- allowClear: true,
117
- },
118
- 'x-use-component-props': 'useFlowModelTemplateSearchProps',
119
- 'x-align': 'left',
120
- },
121
- refresh: {
122
- type: 'void',
123
- title: '{{ t("Refresh") }}',
124
- 'x-component': 'Action',
125
- 'x-use-component-props': 'useRefreshActionProps',
126
- 'x-component-props': {
127
- icon: 'ReloadOutlined',
128
- },
129
- 'x-align': 'right',
130
- },
131
- },
132
- },
133
- table: {
134
- type: 'array',
135
- 'x-component': 'TableV2',
136
- 'x-use-component-props': 'useTableBlockProps',
137
- 'x-component-props': {
138
- rowKey: flowModelTemplatesCollection.filterTargetKey,
139
- pagination: {
140
- pageSize: 50,
141
- },
142
- },
143
- properties: {
144
- name: {
145
- type: 'void',
146
- title: tStr('Template name'),
147
- 'x-component': 'TableV2.Column',
148
- 'x-component-props': {
149
- width: 200,
150
- },
151
- properties: {
152
- name: {
153
- type: 'string',
154
- 'x-component': 'CollectionField',
155
- 'x-pattern': 'readPretty',
156
- 'x-component-props': {
157
- ellipsis: true,
158
- },
159
- },
160
- },
161
- },
162
- description: {
163
- type: 'void',
164
- title: tStr('Template description'),
165
- 'x-component': 'TableV2.Column',
166
- 'x-component-props': {
167
- width: 240,
168
- },
169
- properties: {
170
- description: {
171
- type: 'string',
172
- 'x-component': 'CollectionField',
173
- 'x-pattern': 'readPretty',
174
- 'x-component-props': {
175
- ellipsis: true,
176
- },
177
- },
178
- },
179
- },
180
- dataSourceKey: {
181
- type: 'void',
182
- title: 'Data source',
183
- 'x-component': 'TableV2.Column',
184
- 'x-component-props': {
185
- width: 140,
186
- },
187
- properties: {
188
- dataSourceKey: {
189
- type: 'string',
190
- 'x-component': 'CollectionField',
191
- 'x-pattern': 'readPretty',
192
- 'x-component-props': {
193
- ellipsis: true,
194
- },
195
- },
196
- },
197
- },
198
- collectionName: {
199
- type: 'void',
200
- title: 'Collection',
201
- 'x-component': 'TableV2.Column',
202
- 'x-component-props': {
203
- width: 160,
204
- },
205
- properties: {
206
- collectionName: {
207
- type: 'string',
208
- 'x-component': 'CollectionField',
209
- 'x-pattern': 'readPretty',
210
- 'x-component-props': {
211
- ellipsis: true,
212
- },
213
- },
214
- },
215
- },
216
- usageCount: {
217
- type: 'void',
218
- title: tStr('Usage count'),
219
- 'x-component': 'TableV2.Column',
220
- 'x-component-props': {
221
- width: 120,
222
- },
223
- properties: {
224
- usageCount: {
225
- type: 'number',
226
- 'x-component': 'CollectionField',
227
- 'x-pattern': 'readPretty',
228
- },
229
- },
230
- },
231
- actions: {
232
- type: 'void',
233
- title: tStr('Actions'),
234
- 'x-component': 'TableV2.Column',
235
- 'x-component-props': {
236
- width: 160,
237
- align: 'left',
238
- },
239
- properties: {
240
- actions: {
241
- type: 'void',
242
- 'x-component': 'Space',
243
- 'x-component-props': {
244
- split: '|',
245
- },
246
- properties: {
247
- edit: flowModelTemplateEditActionSchema,
248
- delete: {
249
- type: 'void',
250
- title: tStr('Delete'),
251
- 'x-component': 'Action.Link',
252
- 'x-use-component-props': 'useFlowModelTemplateDeleteActionProps',
253
- 'x-component-props': {
254
- danger: true,
255
- },
256
- },
257
- },
258
- },
259
- },
260
- },
261
- },
262
- },
263
- },
264
- });
@@ -1,67 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
- import { describe, expect, it } from 'vitest';
11
- import { FlowEngine, FlowModel } from '@nocobase/flow-engine';
12
- import { patchGridOptionsFromTemplateRoot } from '../templateCopy';
13
-
14
- describe('patchGridOptionsFromTemplateRoot', () => {
15
- it('fills missing layout/linkageRules from template root', () => {
16
- const engine = new FlowEngine();
17
- class RootModel extends FlowModel {}
18
- engine.registerModels({ RootModel });
19
-
20
- const root = engine.createModel<RootModel>({
21
- uid: 'tpl-root',
22
- use: 'RootModel',
23
- stepParams: {
24
- formModelSettings: { layout: { layout: 'horizontal', labelWidth: 160 } },
25
- eventSettings: { linkageRules: { value: [{ key: 'r1' }] } },
26
- },
27
- });
28
-
29
- const gridOptions: any = { uid: 'dup-grid', use: 'GridModel', stepParams: {} };
30
- const merged = patchGridOptionsFromTemplateRoot(root, gridOptions);
31
- expect(merged.patched).toBe(true);
32
- expect(merged.options.stepParams.formModelSettings.layout).toEqual({ layout: 'horizontal', labelWidth: 160 });
33
- expect(merged.options.stepParams.eventSettings.linkageRules).toEqual({ value: [{ key: 'r1' }] });
34
-
35
- // should be deep-cloned (mutating merged options must not affect template root)
36
- merged.options.stepParams.formModelSettings.layout.layout = 'vertical';
37
- expect(root.getStepParams('formModelSettings', 'layout')).toEqual({ layout: 'horizontal', labelWidth: 160 });
38
- });
39
-
40
- it('does not override existing grid values', () => {
41
- const engine = new FlowEngine();
42
- class RootModel extends FlowModel {}
43
- engine.registerModels({ RootModel });
44
-
45
- const root = engine.createModel<RootModel>({
46
- uid: 'tpl-root',
47
- use: 'RootModel',
48
- stepParams: {
49
- formModelSettings: { layout: { layout: 'horizontal', labelWidth: 160 } },
50
- eventSettings: { linkageRules: { value: [{ key: 'r1' }] } },
51
- },
52
- });
53
-
54
- const gridOptions: any = {
55
- uid: 'dup-grid',
56
- use: 'GridModel',
57
- stepParams: {
58
- formModelSettings: { layout: { layout: 'vertical', labelWidth: 120 } },
59
- eventSettings: { linkageRules: { value: [] } },
60
- },
61
- };
62
- const merged = patchGridOptionsFromTemplateRoot(root, gridOptions);
63
- expect(merged.patched).toBe(false);
64
- expect(merged.options.stepParams.formModelSettings.layout).toEqual({ layout: 'vertical', labelWidth: 120 });
65
- expect(merged.options.stepParams.eventSettings.linkageRules).toEqual({ value: [] });
66
- });
67
- });
@@ -1,150 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
- import debounce from 'lodash/debounce';
11
- import { TEMPLATE_LIST_PAGE_SIZE } from './templateCompatibility';
12
-
13
- export type PaginatedOptionsResult<T = any> = { options: T[]; hasMore: boolean };
14
-
15
- export const defaultSelectOptionComparator = (a: any, b: any) => {
16
- const da = a?.disabled ? 1 : 0;
17
- const db = b?.disabled ? 1 : 0;
18
- if (da !== db) return da - db;
19
- return (a?.__idx ?? 0) - (b?.__idx ?? 0);
20
- };
21
-
22
- export function mergeSelectOptions(
23
- prev: any[],
24
- next: any[],
25
- options?: { getKey?: (item: any) => string; comparator?: (a: any, b: any) => number },
26
- ) {
27
- const getKey = options?.getKey || ((item: any) => String(item?.value || ''));
28
- const comparator = options?.comparator || defaultSelectOptionComparator;
29
-
30
- const map = new Map<string, any>();
31
- for (const item of Array.isArray(prev) ? prev : []) {
32
- const key = getKey(item);
33
- if (!key) continue;
34
- map.set(key, item);
35
- }
36
- for (const item of Array.isArray(next) ? next : []) {
37
- const key = getKey(item);
38
- if (!key) continue;
39
- const existing = map.get(key);
40
- map.set(key, existing ? { ...existing, ...item } : item);
41
- }
42
-
43
- const merged = Array.from(map.values());
44
- merged.sort(comparator);
45
- return merged;
46
- }
47
-
48
- export function bindInfiniteScrollToFormilySelect(
49
- field: any,
50
- fetchPage: (keyword: string, page: number, pageSize: number) => Promise<PaginatedOptionsResult<any>>,
51
- options?: {
52
- pageSize?: number;
53
- debounceMs?: number;
54
- scrollThreshold?: number;
55
- composingKey?: string;
56
- comparator?: (a: any, b: any) => number;
57
- },
58
- ) {
59
- const pageSize = Math.max(1, Number(options?.pageSize || TEMPLATE_LIST_PAGE_SIZE));
60
- const debounceMs = Math.max(0, Number(options?.debounceMs ?? 300));
61
- const scrollThreshold = Math.max(0, Number(options?.scrollThreshold ?? 24));
62
- const composingKey = String(options?.composingKey || '__templateComposing');
63
- const comparator = options?.comparator || defaultSelectOptionComparator;
64
-
65
- let requestVersion = 0;
66
- let currentKeyword = '';
67
- let currentPage = 0;
68
- let currentHasMore = true;
69
- let loadingMore = false;
70
-
71
- const setComposing = (v: boolean) => {
72
- try {
73
- field.data = { ...(field.data || {}), [composingKey]: v };
74
- } catch {
75
- // ignore
76
- }
77
- };
78
-
79
- const isComposing = () => !!field.data?.[composingKey];
80
-
81
- const resetAndLoad = async (keyword: string) => {
82
- const nextVersion = (requestVersion || 0) + 1;
83
- requestVersion = nextVersion;
84
- currentKeyword = keyword;
85
- currentPage = 0;
86
- currentHasMore = true;
87
- loadingMore = false;
88
- field.loading = true;
89
- try {
90
- const { options: optionList, hasMore } = await fetchPage(keyword, 1, pageSize);
91
- if (requestVersion !== nextVersion) return;
92
- field.dataSource = mergeSelectOptions([], optionList, { comparator });
93
- currentPage = 1;
94
- currentHasMore = !!hasMore;
95
- } finally {
96
- if (requestVersion === nextVersion) {
97
- field.loading = false;
98
- }
99
- }
100
- };
101
-
102
- const loadMore = async () => {
103
- if (!currentHasMore || loadingMore) return;
104
- const version = requestVersion;
105
- const nextPage = Math.max(1, currentPage || 1) + 1;
106
- loadingMore = true;
107
- field.loading = true;
108
- try {
109
- const { options: optionList, hasMore } = await fetchPage(currentKeyword, nextPage, pageSize);
110
- if (requestVersion !== version) return;
111
- field.dataSource = mergeSelectOptions(field.dataSource || [], optionList, { comparator });
112
- currentPage = nextPage;
113
- currentHasMore = !!hasMore;
114
- } finally {
115
- loadingMore = false;
116
- if (requestVersion === version) {
117
- field.loading = false;
118
- }
119
- }
120
- };
121
-
122
- field.componentProps.onDropdownVisibleChange = async (open: boolean) => {
123
- if (!open) return;
124
- await resetAndLoad('');
125
- };
126
-
127
- const debouncedSearch = debounce(async (kw: string) => resetAndLoad(kw), debounceMs);
128
-
129
- field.componentProps.onSearch = (value: string) => {
130
- if (isComposing()) return;
131
- const keyword = typeof value === 'string' ? value.trim() : '';
132
- debouncedSearch(keyword);
133
- };
134
-
135
- field.componentProps.onCompositionStart = () => setComposing(true);
136
- field.componentProps.onCompositionEnd = (e: any) => {
137
- setComposing(false);
138
- const keyword = typeof e?.target?.value === 'string' ? e.target.value.trim() : '';
139
- debouncedSearch(keyword);
140
- };
141
-
142
- field.componentProps.onPopupScroll = (e: any) => {
143
- const target = e?.target as HTMLElement | undefined;
144
- if (!target) return;
145
- if (target.scrollTop + target.clientHeight < target.scrollHeight - scrollThreshold) return;
146
- loadMore();
147
- };
148
-
149
- return { resetAndLoad, loadMore, cancelSearch: () => debouncedSearch.cancel() };
150
- }