@nocobase/client-v2 2.1.0-beta.30 → 2.1.0-beta.33
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/es/BaseApplication.d.ts +1 -0
- package/es/PluginManager.d.ts +1 -0
- package/es/components/form/DrawerFormLayout.d.ts +49 -0
- package/es/components/form/EnvVariableInput.d.ts +42 -0
- package/es/components/form/FileSizeInput.d.ts +27 -0
- package/es/components/form/createFormRegistry.d.ts +33 -0
- package/es/components/form/index.d.ts +13 -0
- package/es/components/index.d.ts +1 -1
- package/es/flow/components/FieldAssignRulesEditor.d.ts +1 -0
- package/es/flow/components/code-editor/index.d.ts +1 -0
- package/es/flow/internal/utils/enumOptionsUtils.d.ts +5 -0
- package/es/flow/models/actions/AssociationActionUtils.d.ts +5 -0
- package/es/flow/models/blocks/filter-form/FilterFormBlockModel.d.ts +4 -0
- package/es/flow/models/blocks/filter-manager/FilterManager.d.ts +5 -1
- package/es/flow/models/blocks/shared/legacyDefaultValueMigrationBase.d.ts +1 -0
- package/es/flow/models/blocks/table/TableSelectModel.d.ts +8 -0
- package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.d.ts +4 -0
- package/es/flow/models/fields/ClickableFieldModel.d.ts +3 -0
- package/es/flow/models/fields/DisplayEnumFieldModel.d.ts +6 -0
- package/es/flow/models/fields/DisplayTitleFieldModel.d.ts +2 -2
- package/es/flow/models/utils/displayValueUtils.d.ts +12 -0
- package/es/flow-compat/passwordUtils.d.ts +1 -1
- package/es/index.mjs +119 -108
- package/es/utils/remotePlugins.d.ts +0 -4
- package/lib/index.js +122 -111
- package/package.json +9 -5
- package/src/BaseApplication.tsx +14 -8
- package/src/PluginManager.ts +1 -0
- package/src/__tests__/app.test.tsx +28 -1
- package/src/__tests__/globalDeps.test.ts +1 -0
- package/src/__tests__/remotePlugins.test.ts +29 -18
- package/src/components/form/DrawerFormLayout.tsx +103 -0
- package/src/components/form/EnvVariableInput.tsx +126 -0
- package/src/components/form/FileSizeInput.tsx +105 -0
- package/src/components/form/createFormRegistry.ts +60 -0
- package/src/components/form/index.tsx +14 -0
- package/src/components/index.ts +1 -1
- package/src/flow/actions/__tests__/dataScopeFilter.test.ts +92 -13
- package/src/flow/actions/__tests__/formAssignRules.legacyMigration.test.tsx +173 -0
- package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +476 -1
- package/src/flow/actions/__tests__/pattern.test.ts +134 -0
- package/src/flow/actions/__tests__/titleField.test.ts +45 -0
- package/src/flow/actions/filterFormDefaultValues.tsx +30 -9
- package/src/flow/actions/formAssignRules.tsx +24 -9
- package/src/flow/actions/linkageRules.tsx +240 -258
- package/src/flow/actions/pattern.tsx +41 -6
- package/src/flow/actions/setTargetDataScope.tsx +32 -3
- package/src/flow/actions/titleField.tsx +4 -2
- package/src/flow/actions/validation.tsx +1 -1
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +0 -4
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +13 -5
- package/src/flow/components/DynamicFlowsIcon.tsx +87 -13
- package/src/flow/components/FieldAssignRulesEditor.tsx +2 -0
- package/src/flow/components/__tests__/DynamicFlowsIcon.test.tsx +195 -8
- package/src/flow/components/__tests__/FieldAssignRulesEditor.test.tsx +81 -4
- package/src/flow/components/code-editor/index.tsx +12 -8
- package/src/flow/components/filter/LinkageFilterItem.tsx +9 -2
- package/src/flow/components/filter/VariableFilterItem.tsx +2 -6
- package/src/flow/components/filter/__tests__/LinkageFilterItem.test.tsx +71 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.test.tsx +48 -0
- package/src/flow/internal/utils/__tests__/enumOptionsUtils.test.ts +10 -1
- package/src/flow/internal/utils/enumOptionsUtils.ts +29 -0
- package/src/flow/models/actions/AssociateActionModel.tsx +2 -2
- package/src/flow/models/actions/AssociationActionUtils.ts +14 -0
- package/src/flow/models/actions/__tests__/AssociationActionModel.test.ts +63 -0
- package/src/flow/models/base/CollectionBlockModel.tsx +7 -0
- package/src/flow/models/base/PageModel/RootPageModel.tsx +1 -1
- package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +33 -9
- package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +53 -13
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.getFilterValue.test.ts +63 -3
- package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +33 -1
- package/src/flow/models/blocks/filter-form/__tests__/legacyDefaultValueMigration.test.ts +3 -0
- package/src/flow/models/blocks/filter-manager/FilterManager.ts +66 -2
- package/src/flow/models/blocks/filter-manager/__tests__/FilterManager.test.ts +270 -0
- package/src/flow/models/blocks/form/FormActionModel.tsx +2 -8
- package/src/flow/models/blocks/form/FormBlockModel.tsx +8 -5
- package/src/flow/models/blocks/form/FormItemModel.tsx +1 -1
- package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +30 -0
- package/src/flow/models/blocks/form/__tests__/legacyDefaultValueMigration.test.ts +3 -0
- package/src/flow/models/blocks/form/value-runtime/rules.ts +6 -1
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +6 -1
- package/src/flow/models/blocks/shared/legacyDefaultValueMigrationBase.ts +21 -5
- package/src/flow/models/blocks/table/TableBlockModel.tsx +11 -6
- package/src/flow/models/blocks/table/TableColumnModel.tsx +8 -2
- package/src/flow/models/blocks/table/TableSelectModel.tsx +36 -26
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowClick.test.ts +69 -0
- package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +132 -1
- package/src/flow/models/blocks/table/__tests__/TableSelectModel.test.ts +41 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +144 -3
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableColumnModel.rowRecord.test.ts +170 -1
- package/src/flow/models/fields/ClickableFieldModel.tsx +55 -6
- package/src/flow/models/fields/DisplayEnumFieldModel.tsx +44 -0
- package/src/flow/models/fields/DisplayTitleFieldModel.tsx +40 -7
- package/src/flow/models/fields/SelectFieldModel.tsx +31 -1
- package/src/flow/models/fields/__tests__/ClickableFieldModel.test.ts +202 -1
- package/src/flow/models/fields/__tests__/DisplayEnumFieldModel.test.tsx +39 -0
- package/src/flow/models/fields/mobile-components/MobileSelect.tsx +2 -1
- package/src/flow/models/fields/mobile-components/__tests__/MobileSelect.test.tsx +7 -0
- package/src/flow/models/utils/displayValueUtils.ts +57 -0
- package/src/utils/globalDeps.ts +11 -0
- package/src/utils/remotePlugins.ts +7 -27
|
@@ -8,8 +8,12 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { describe, expect, it, vi } from 'vitest';
|
|
11
|
-
import { FlowEngine } from '@nocobase/flow-engine';
|
|
11
|
+
import { FlowEngine, FlowModel } from '@nocobase/flow-engine';
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
12
14
|
import { ClickableFieldModel } from '../ClickableFieldModel';
|
|
15
|
+
import { DisplayTitleFieldModel } from '../DisplayTitleFieldModel';
|
|
16
|
+
import { DisplayTextFieldModel } from '../DisplayTextFieldModel';
|
|
13
17
|
|
|
14
18
|
function createRolesFieldModel(sourceRecord: Record<string, any>) {
|
|
15
19
|
const engine = new FlowEngine();
|
|
@@ -84,4 +88,201 @@ describe('ClickableFieldModel', () => {
|
|
|
84
88
|
{ debounce: true },
|
|
85
89
|
);
|
|
86
90
|
});
|
|
91
|
+
|
|
92
|
+
it('uses the parent association field when the display model is bound to the title field', () => {
|
|
93
|
+
const engine = new FlowEngine();
|
|
94
|
+
engine.registerModels({ ClickableFieldModel });
|
|
95
|
+
|
|
96
|
+
const usersCollection = {
|
|
97
|
+
name: 'users',
|
|
98
|
+
filterTargetKey: 'id',
|
|
99
|
+
};
|
|
100
|
+
const rolesCollection = {
|
|
101
|
+
name: 'roles',
|
|
102
|
+
filterTargetKey: 'name',
|
|
103
|
+
};
|
|
104
|
+
const rolesField = {
|
|
105
|
+
name: 'roles',
|
|
106
|
+
target: 'roles',
|
|
107
|
+
targetKey: 'name',
|
|
108
|
+
type: 'belongsToMany',
|
|
109
|
+
interface: 'm2m',
|
|
110
|
+
collection: usersCollection,
|
|
111
|
+
targetCollection: rolesCollection,
|
|
112
|
+
isAssociationField: () => true,
|
|
113
|
+
};
|
|
114
|
+
const titleField = {
|
|
115
|
+
name: 'title',
|
|
116
|
+
collection: rolesCollection,
|
|
117
|
+
isAssociationField: () => false,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const parent = engine.createModel<FlowModel>({
|
|
121
|
+
use: FlowModel,
|
|
122
|
+
uid: 'roles-column',
|
|
123
|
+
});
|
|
124
|
+
parent.context.defineProperty('collectionField', { value: rolesField });
|
|
125
|
+
|
|
126
|
+
const model = engine.createModel<ClickableFieldModel>({
|
|
127
|
+
use: ClickableFieldModel,
|
|
128
|
+
uid: 'roles-title-display',
|
|
129
|
+
});
|
|
130
|
+
model.setParent(parent);
|
|
131
|
+
model.context.defineProperty('collectionField', { value: titleField });
|
|
132
|
+
model.context.defineProperty('blockModel', { value: { collection: usersCollection } });
|
|
133
|
+
model.context.defineProperty('record', { value: { id: 1 } });
|
|
134
|
+
const dispatchEvent = vi.spyOn(model, 'dispatchEvent').mockResolvedValue([]);
|
|
135
|
+
const event = { type: 'click' };
|
|
136
|
+
|
|
137
|
+
model.onClick(event, { name: 'admin', title: 'Admin' });
|
|
138
|
+
|
|
139
|
+
expect(dispatchEvent).toHaveBeenCalledWith(
|
|
140
|
+
'click',
|
|
141
|
+
{
|
|
142
|
+
event,
|
|
143
|
+
filterByTk: 'admin',
|
|
144
|
+
collectionName: 'users',
|
|
145
|
+
associationName: 'users.roles',
|
|
146
|
+
sourceId: 1,
|
|
147
|
+
},
|
|
148
|
+
{ debounce: true },
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('renders title display values as links when click-to-open is enabled', () => {
|
|
153
|
+
const engine = new FlowEngine();
|
|
154
|
+
engine.registerModels({ DisplayTitleFieldModel });
|
|
155
|
+
|
|
156
|
+
const usersCollection = {
|
|
157
|
+
name: 'users',
|
|
158
|
+
filterTargetKey: 'id',
|
|
159
|
+
};
|
|
160
|
+
const rolesCollection = {
|
|
161
|
+
name: 'roles',
|
|
162
|
+
filterTargetKey: 'name',
|
|
163
|
+
};
|
|
164
|
+
const rolesField = {
|
|
165
|
+
name: 'roles',
|
|
166
|
+
target: 'roles',
|
|
167
|
+
targetKey: 'name',
|
|
168
|
+
type: 'belongsToMany',
|
|
169
|
+
interface: 'm2m',
|
|
170
|
+
collection: usersCollection,
|
|
171
|
+
targetCollection: rolesCollection,
|
|
172
|
+
isAssociationField: () => true,
|
|
173
|
+
};
|
|
174
|
+
const titleField = {
|
|
175
|
+
name: 'title',
|
|
176
|
+
collection: rolesCollection,
|
|
177
|
+
isAssociationField: () => false,
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const parent = engine.createModel<FlowModel>({
|
|
181
|
+
use: FlowModel,
|
|
182
|
+
uid: 'roles-title-column',
|
|
183
|
+
});
|
|
184
|
+
parent.context.defineProperty('collectionField', { value: rolesField });
|
|
185
|
+
|
|
186
|
+
const model = engine.createModel<DisplayTitleFieldModel>({
|
|
187
|
+
use: DisplayTitleFieldModel,
|
|
188
|
+
uid: 'roles-title-display-link',
|
|
189
|
+
props: {
|
|
190
|
+
clickToOpen: true,
|
|
191
|
+
titleField: 'name',
|
|
192
|
+
value: { name: 'admin', title: 'Admin' },
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
model.setParent(parent);
|
|
196
|
+
model.context.defineProperty('collectionField', { value: titleField });
|
|
197
|
+
model.context.defineProperty('blockModel', { value: { collection: usersCollection } });
|
|
198
|
+
model.context.defineProperty('record', { value: { id: 1 } });
|
|
199
|
+
const dispatchEvent = vi.spyOn(model, 'dispatchEvent').mockResolvedValue([]);
|
|
200
|
+
|
|
201
|
+
render(React.createElement(React.Fragment, null, model.render()));
|
|
202
|
+
const link = screen.getByText('admin').closest('a');
|
|
203
|
+
expect(link).toBeTruthy();
|
|
204
|
+
|
|
205
|
+
fireEvent.click(link);
|
|
206
|
+
|
|
207
|
+
expect(dispatchEvent).toHaveBeenCalledWith(
|
|
208
|
+
'click',
|
|
209
|
+
expect.objectContaining({
|
|
210
|
+
filterByTk: 'admin',
|
|
211
|
+
collectionName: 'users',
|
|
212
|
+
associationName: 'users.roles',
|
|
213
|
+
sourceId: 1,
|
|
214
|
+
}),
|
|
215
|
+
{ debounce: true },
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('renders object title field values by configured target title field', () => {
|
|
220
|
+
const engine = new FlowEngine();
|
|
221
|
+
engine.registerModels({ DisplayTextFieldModel });
|
|
222
|
+
|
|
223
|
+
const model = engine.createModel<DisplayTextFieldModel>({
|
|
224
|
+
use: DisplayTextFieldModel,
|
|
225
|
+
uid: 'display-text-association-title',
|
|
226
|
+
});
|
|
227
|
+
model.context.defineProperty('collectionField', {
|
|
228
|
+
value: {
|
|
229
|
+
targetCollectionTitleFieldName: 'code',
|
|
230
|
+
isAssociationField: () => true,
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
render(model.renderInDisplayStyle({ id: 2, name: 'Sales', code: 'S-001' }, { id: 1 }, false));
|
|
235
|
+
|
|
236
|
+
expect(screen.getByText('S-001')).toBeInTheDocument();
|
|
237
|
+
expect(screen.queryByText('Sales')).not.toBeInTheDocument();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('refreshes the parent column when title display click-to-open changes', async () => {
|
|
241
|
+
const engine = new FlowEngine();
|
|
242
|
+
engine.registerModels({ DisplayTitleFieldModel });
|
|
243
|
+
|
|
244
|
+
const rolesField = {
|
|
245
|
+
name: 'roles',
|
|
246
|
+
target: 'roles',
|
|
247
|
+
collection: { name: 'users' },
|
|
248
|
+
targetCollection: { name: 'roles' },
|
|
249
|
+
isAssociationField: () => true,
|
|
250
|
+
getComponentProps: () => ({ titleField: 'name' }),
|
|
251
|
+
};
|
|
252
|
+
const titleField = {
|
|
253
|
+
name: 'title',
|
|
254
|
+
collection: { name: 'roles' },
|
|
255
|
+
isAssociationField: () => false,
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const parent = engine.createModel<FlowModel>({
|
|
259
|
+
use: FlowModel,
|
|
260
|
+
uid: 'roles-title-column-refresh',
|
|
261
|
+
});
|
|
262
|
+
parent.context.defineProperty('collectionField', { value: rolesField });
|
|
263
|
+
const parentSetProps = vi.spyOn(parent, 'setProps');
|
|
264
|
+
const parentRerender = vi.spyOn(parent, 'rerender').mockResolvedValue(undefined);
|
|
265
|
+
|
|
266
|
+
const model = engine.createModel<DisplayTitleFieldModel>({
|
|
267
|
+
use: DisplayTitleFieldModel,
|
|
268
|
+
uid: 'roles-title-display-refresh',
|
|
269
|
+
});
|
|
270
|
+
model.setParent(parent);
|
|
271
|
+
model.context.defineProperty('collectionField', { value: titleField });
|
|
272
|
+
const modelRerender = vi.spyOn(model, 'rerender').mockResolvedValue(undefined);
|
|
273
|
+
|
|
274
|
+
const clickToOpenStep = model.getFlow('displayFieldSettings').steps.clickToOpen;
|
|
275
|
+
|
|
276
|
+
await clickToOpenStep.afterParamsSave(model.context as any, { clickToOpen: true }, { clickToOpen: false });
|
|
277
|
+
|
|
278
|
+
expect(model.props).toMatchObject({
|
|
279
|
+
clickToOpen: true,
|
|
280
|
+
titleField: 'name',
|
|
281
|
+
});
|
|
282
|
+
expect(modelRerender).toHaveBeenCalled();
|
|
283
|
+
expect(parentSetProps).toHaveBeenCalledWith({
|
|
284
|
+
__displayFieldRefreshKey: expect.any(String),
|
|
285
|
+
});
|
|
286
|
+
expect(parentRerender).toHaveBeenCalled();
|
|
287
|
+
});
|
|
87
288
|
});
|
|
@@ -0,0 +1,39 @@
|
|
|
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 } from '@nocobase/flow-engine';
|
|
12
|
+
import { render, screen } from '@testing-library/react';
|
|
13
|
+
import { DisplayEnumFieldModel } from '../DisplayEnumFieldModel';
|
|
14
|
+
|
|
15
|
+
describe('DisplayEnumFieldModel', () => {
|
|
16
|
+
it('renders labels for multiple values (multipleSelect/checkboxGroup)', () => {
|
|
17
|
+
const engine = new FlowEngine();
|
|
18
|
+
engine.registerModels({ DisplayEnumFieldModel });
|
|
19
|
+
|
|
20
|
+
const model = engine.createModel<DisplayEnumFieldModel>({
|
|
21
|
+
use: DisplayEnumFieldModel,
|
|
22
|
+
uid: 'display-enum-multiple-values',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
model.setProps({
|
|
26
|
+
value: ['a', 'b'],
|
|
27
|
+
options: [
|
|
28
|
+
{ label: 'Option A', value: 'a' },
|
|
29
|
+
{ label: 'Option B', value: 'b' },
|
|
30
|
+
],
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
render(model.render());
|
|
34
|
+
|
|
35
|
+
expect(screen.getByText('Option A')).toBeInTheDocument();
|
|
36
|
+
expect(screen.getByText('Option B')).toBeInTheDocument();
|
|
37
|
+
expect(screen.queryByText('a, b')).not.toBeInTheDocument();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -13,7 +13,7 @@ import { Button, CheckList, Popup, SearchBar } from 'antd-mobile';
|
|
|
13
13
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
14
14
|
|
|
15
15
|
export function MobileSelect(props) {
|
|
16
|
-
const { value, onChange, onChangeComplete, disabled, options = [], mode } = props;
|
|
16
|
+
const { value, displayValue, onChange, onChangeComplete, disabled, options = [], mode } = props;
|
|
17
17
|
const ctx = useFlowModelContext();
|
|
18
18
|
const t = ctx.t;
|
|
19
19
|
const [visible, setVisible] = useState(false);
|
|
@@ -44,6 +44,7 @@ export function MobileSelect(props) {
|
|
|
44
44
|
<div onClick={() => !disabled && setVisible(true)}>
|
|
45
45
|
<Select
|
|
46
46
|
{...props}
|
|
47
|
+
value={displayValue ?? value}
|
|
47
48
|
open={false}
|
|
48
49
|
dropdownStyle={{ display: 'none' }}
|
|
49
50
|
showSearch={false}
|
|
@@ -178,6 +178,13 @@ describe('MobileSelect', () => {
|
|
|
178
178
|
clickTrigger();
|
|
179
179
|
expect(screen.queryByTestId('popup')).not.toBeInTheDocument();
|
|
180
180
|
});
|
|
181
|
+
|
|
182
|
+
it('prefers displayValue for trigger rendering', () => {
|
|
183
|
+
const displayValue = [{ label: 'Published', value: 'published' }];
|
|
184
|
+
renderMobileSelect({ value: ['published'], displayValue, mode: 'multiple' });
|
|
185
|
+
|
|
186
|
+
expect(mockState.selectProps?.value).toEqual(displayValue);
|
|
187
|
+
});
|
|
181
188
|
});
|
|
182
189
|
|
|
183
190
|
function SubTableCellHarness({ value, onCommit, mode }: { value: any; onCommit: (value: any) => void; mode?: string }) {
|
|
@@ -0,0 +1,57 @@
|
|
|
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 { isValidElement } from 'react';
|
|
11
|
+
|
|
12
|
+
export function hasDisplayValue(value: any) {
|
|
13
|
+
return value !== undefined && value !== null && value !== '';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getTitleFieldName(collectionField: any) {
|
|
17
|
+
const targetCollection = collectionField?.targetCollection;
|
|
18
|
+
return (
|
|
19
|
+
collectionField?.targetCollectionTitleFieldName ||
|
|
20
|
+
targetCollection?.titleCollectionField?.name ||
|
|
21
|
+
targetCollection?.titleField ||
|
|
22
|
+
targetCollection?.options?.titleField
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getTitleCollectionField(collectionField: any, titleFieldName: string) {
|
|
27
|
+
return (
|
|
28
|
+
collectionField?.targetCollection?.getField?.(titleFieldName) ||
|
|
29
|
+
collectionField?.targetCollection?.titleCollectionField
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function normalizeDisplayValue(value: any, options: { collectionField?: any } = {}): any {
|
|
34
|
+
if (!hasDisplayValue(value) || isValidElement(value)) {
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
if (['string', 'number', 'boolean'].includes(typeof value)) {
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
if (Array.isArray(value)) {
|
|
41
|
+
const parts = value.map((item) => normalizeDisplayValue(item, options)).filter(hasDisplayValue);
|
|
42
|
+
return parts.length ? parts.map(String).join(', ') : undefined;
|
|
43
|
+
}
|
|
44
|
+
if (value instanceof Date) {
|
|
45
|
+
return value.toISOString();
|
|
46
|
+
}
|
|
47
|
+
if (typeof value === 'object') {
|
|
48
|
+
const titleFieldName = getTitleFieldName(options.collectionField);
|
|
49
|
+
if (titleFieldName) {
|
|
50
|
+
return normalizeDisplayValue(value[titleFieldName], {
|
|
51
|
+
collectionField: getTitleCollectionField(options.collectionField, titleFieldName),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
return value;
|
|
57
|
+
}
|
package/src/utils/globalDeps.ts
CHANGED
|
@@ -9,16 +9,21 @@
|
|
|
9
9
|
|
|
10
10
|
import * as antdCssinjs from '@ant-design/cssinjs';
|
|
11
11
|
import * as antdIcons from '@ant-design/icons';
|
|
12
|
+
import * as antdStyle from 'antd-style';
|
|
12
13
|
import * as emotionCss from '@emotion/css';
|
|
14
|
+
import * as formilyAntdV5 from '@formily/antd-v5';
|
|
13
15
|
import * as formilyCore from '@formily/core';
|
|
14
16
|
import * as formilyReact from '@formily/react';
|
|
15
17
|
import * as formilyReactive from '@formily/reactive';
|
|
16
18
|
import * as formilyShared from '@formily/shared';
|
|
19
|
+
import * as nocobaseEvaluators from '@nocobase/evaluators/client';
|
|
17
20
|
import * as nocobaseClientUtils from '@nocobase/utils/client';
|
|
18
21
|
import { dayjs } from '@nocobase/utils/client';
|
|
19
22
|
import * as nocobaseFlowEngine from '@nocobase/flow-engine';
|
|
20
23
|
import * as ahooks from 'ahooks';
|
|
21
24
|
import * as antd from 'antd';
|
|
25
|
+
import * as FileSaver from 'file-saver';
|
|
26
|
+
import axios from 'axios';
|
|
22
27
|
import * as i18next from 'i18next';
|
|
23
28
|
import lodash from 'lodash';
|
|
24
29
|
import React from 'react';
|
|
@@ -48,12 +53,14 @@ export function defineGlobalDeps(requirejs: RequireJS) {
|
|
|
48
53
|
requirejs.define('antd', () => antd);
|
|
49
54
|
requirejs.define('@ant-design/icons', () => antdIcons);
|
|
50
55
|
requirejs.define('@ant-design/cssinjs', () => antdCssinjs);
|
|
56
|
+
requirejs.define('antd-style', () => antdStyle);
|
|
51
57
|
|
|
52
58
|
// i18next
|
|
53
59
|
requirejs.define('i18next', () => i18next);
|
|
54
60
|
requirejs.define('react-i18next', () => reactI18next);
|
|
55
61
|
|
|
56
62
|
// formily
|
|
63
|
+
requirejs.define('@formily/antd-v5', () => formilyAntdV5);
|
|
57
64
|
requirejs.define('@formily/core', () => formilyCore);
|
|
58
65
|
requirejs.define('@formily/react', () => formilyReact);
|
|
59
66
|
requirejs.define('@formily/reactive', () => formilyReactive);
|
|
@@ -65,10 +72,14 @@ export function defineGlobalDeps(requirejs: RequireJS) {
|
|
|
65
72
|
requirejs.define('@nocobase/client-v2', () => nocobaseClientV2);
|
|
66
73
|
requirejs.define('@nocobase/client-v2/client-v2', () => nocobaseClientV2);
|
|
67
74
|
requirejs.define('@nocobase/flow-engine', () => nocobaseFlowEngine);
|
|
75
|
+
requirejs.define('@nocobase/evaluators', () => nocobaseEvaluators);
|
|
76
|
+
requirejs.define('@nocobase/evaluators/client', () => nocobaseEvaluators);
|
|
68
77
|
|
|
69
78
|
// utils
|
|
70
79
|
requirejs.define('ahooks', () => ahooks);
|
|
80
|
+
requirejs.define('axios', () => axios);
|
|
71
81
|
requirejs.define('dayjs', () => dayjs);
|
|
72
82
|
requirejs.define('lodash', () => lodash);
|
|
73
83
|
requirejs.define('@emotion/css', () => emotionCss);
|
|
84
|
+
requirejs.define('file-saver', () => FileSaver);
|
|
74
85
|
}
|
|
@@ -12,33 +12,16 @@ import type { PluginClass } from '../PluginManager';
|
|
|
12
12
|
import type { PluginData } from '../PluginManager';
|
|
13
13
|
import type { RequireJS } from './requirejs';
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*/
|
|
18
|
-
export function defineDevPlugins(plugins: Record<string, PluginClass>) {
|
|
19
|
-
Object.entries(plugins).forEach(([packageName, plugin]) => {
|
|
20
|
-
window.define(`${packageName}/client-v2`, () => plugin);
|
|
21
|
-
});
|
|
15
|
+
function getClientV2ModuleId(packageName: string) {
|
|
16
|
+
return `${packageName}/client-v2`;
|
|
22
17
|
}
|
|
23
18
|
|
|
24
19
|
/**
|
|
25
20
|
* @internal
|
|
26
21
|
*/
|
|
27
|
-
export function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
value: true,
|
|
31
|
-
});
|
|
32
|
-
Object.keys(_pluginExports).forEach(function (key) {
|
|
33
|
-
if (key === '__esModule') return;
|
|
34
|
-
if (key in _exports && _exports[key] === _pluginExports[key]) return;
|
|
35
|
-
Object.defineProperty(_exports, key, {
|
|
36
|
-
enumerable: true,
|
|
37
|
-
get: function () {
|
|
38
|
-
return _pluginExports[key];
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
});
|
|
22
|
+
export function defineDevPlugins(plugins: Record<string, PluginClass>) {
|
|
23
|
+
Object.entries(plugins).forEach(([packageName, plugin]) => {
|
|
24
|
+
window.define(getClientV2ModuleId(packageName), () => plugin);
|
|
42
25
|
});
|
|
43
26
|
}
|
|
44
27
|
|
|
@@ -49,7 +32,7 @@ export function configRequirejs(requirejs: any, pluginData: PluginData[]) {
|
|
|
49
32
|
requirejs.requirejs.config({
|
|
50
33
|
waitSeconds: 120,
|
|
51
34
|
paths: pluginData.reduce<Record<string, string>>((acc, cur) => {
|
|
52
|
-
acc[cur.packageName] = cur.url;
|
|
35
|
+
acc[getClientV2ModuleId(cur.packageName)] = cur.url;
|
|
53
36
|
return acc;
|
|
54
37
|
}, {}),
|
|
55
38
|
});
|
|
@@ -85,10 +68,7 @@ export function processRemotePlugins(pluginData: PluginData[], resolve: (plugins
|
|
|
85
68
|
export function getRemotePlugins(requirejs: any, pluginData: PluginData[] = []): Promise<Array<[string, PluginClass]>> {
|
|
86
69
|
configRequirejs(requirejs, pluginData);
|
|
87
70
|
|
|
88
|
-
const packageNames = pluginData.map((item) => item.packageName);
|
|
89
|
-
packageNames.forEach((packageName) => {
|
|
90
|
-
definePluginClient(packageName);
|
|
91
|
-
});
|
|
71
|
+
const packageNames = pluginData.map((item) => getClientV2ModuleId(item.packageName));
|
|
92
72
|
|
|
93
73
|
return new Promise((resolve, reject) => {
|
|
94
74
|
requirejs.requirejs(packageNames, processRemotePlugins(pluginData, resolve), reject);
|