@nocobase/client-v2 2.2.0-beta.8 → 2.3.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/APIClient.d.ts +1 -3
- package/es/BaseApplication.d.ts +3 -0
- package/es/RouteRepository.d.ts +8 -0
- package/es/RouterManager.d.ts +15 -0
- package/es/authRedirect.d.ts +1 -0
- package/es/collection-field-interface/CollectionFieldInterface.d.ts +1 -0
- package/es/collection-field-interface/CollectionFieldInterfaceManager.d.ts +1 -0
- package/es/components/category-tabs/SortableCategoryTabs.d.ts +55 -0
- package/es/components/category-tabs/index.d.ts +9 -0
- package/es/components/form/ScanInput/useCodeScanner.d.ts +2 -1
- package/es/components/form/TypedVariableInput.d.ts +31 -5
- package/es/components/form/filter/CollectionFilter.d.ts +2 -0
- package/es/components/form/filter/CollectionFilterItem.d.ts +11 -1
- package/es/components/form/filter/CollectionFilterPanel.d.ts +2 -0
- package/es/components/form/filter/index.d.ts +2 -0
- package/es/components/form/filter/useFilterActionProps.d.ts +2 -0
- package/es/components/index.d.ts +1 -0
- package/es/entry-actions/EntryActionManager.d.ts +24 -0
- package/es/entry-actions/index.d.ts +9 -0
- package/es/flow/actions/index.d.ts +1 -1
- package/es/flow/actions/linkageRules.d.ts +2 -0
- package/es/flow/admin-shell/BaseLayoutModel.d.ts +6 -0
- package/es/flow/admin-shell/BaseLayoutRouteCoordinator.d.ts +7 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +1 -0
- package/es/flow/admin-shell/admin-layout/AppListRender.d.ts +2 -1
- package/es/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.d.ts +24 -0
- package/es/flow/admin-shell/admin-layout/index.d.ts +1 -0
- package/es/flow/admin-shell/admin-layout/useApplications.d.ts +7 -2
- package/es/flow/components/FieldAssignExactDatePicker.d.ts +1 -0
- package/es/flow/components/FieldAssignValueInput.d.ts +9 -0
- package/es/flow/components/RunJSValueEditor.d.ts +1 -0
- package/es/flow/components/filter/FilterGroup.d.ts +1 -0
- package/es/flow/components/filter/VariableFilterItem.d.ts +6 -1
- package/es/flow/index.d.ts +1 -0
- package/es/flow/models/base/ActionModelCore.d.ts +2 -0
- package/es/flow/models/base/PageModel/PageModel.d.ts +12 -0
- package/es/flow/models/base/PageModel/PageModelTabBar.d.ts +22 -0
- package/es/flow/models/base/PageModel/PageTabModel.d.ts +12 -0
- package/es/flow/models/blocks/form/QuickEditFormModel.d.ts +17 -2
- package/es/flow/routeTransientInputArgs.d.ts +14 -0
- package/es/flow-compat/fieldValidationConstants.d.ts +1 -1
- package/es/flow-compat/routeTypes.d.ts +1 -0
- package/es/index.d.ts +6 -0
- package/es/index.mjs +279 -158
- package/es/utils/getRouteRuntimeVersion.d.ts +23 -0
- package/es/utils/index.d.ts +1 -0
- package/es/utils/markdownSanitize.d.ts +11 -0
- package/lib/index.js +280 -159
- package/lib/locale/languageCodes.js +2 -1
- package/package.json +8 -7
- package/src/APIClient.ts +1 -10
- package/src/Application.tsx +4 -0
- package/src/BaseApplication.tsx +13 -6
- package/src/RouteRepository.ts +25 -0
- package/src/RouterManager.tsx +142 -1
- package/src/__tests__/RouteRepository.test.ts +23 -0
- package/src/__tests__/RouterManager.test.ts +125 -0
- package/src/__tests__/app.test.tsx +73 -0
- package/src/__tests__/authRedirect.test.ts +17 -0
- package/src/__tests__/browserChecker.test.ts +61 -0
- package/src/__tests__/getRouteRuntimeVersion.test.ts +68 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +28 -0
- package/src/authRedirect.ts +38 -0
- package/src/collection-field-interface/CollectionFieldInterface.ts +1 -0
- package/src/collection-field-interface/CollectionFieldInterfaceManager.ts +1 -0
- package/src/collection-manager/field-validation.ts +1 -1
- package/src/components/README.md +7 -1
- package/src/components/README.zh-CN.md +6 -1
- package/src/components/category-tabs/SortableCategoryTabs.tsx +210 -0
- package/src/components/category-tabs/index.ts +10 -0
- package/src/components/form/JsonTextArea.tsx +4 -0
- package/src/components/form/ScanInput/CodeScanner.tsx +23 -6
- package/src/components/form/ScanInput/__tests__/useCodeScanner.test.tsx +180 -3
- package/src/components/form/ScanInput/useCodeScanner.ts +170 -5
- package/src/components/form/TypedVariableInput.tsx +452 -101
- package/src/components/form/__tests__/TypedVariableInput.test.tsx +364 -12
- package/src/components/form/filter/CollectionFilter.tsx +4 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +32 -7
- package/src/components/form/filter/CollectionFilterPanel.tsx +4 -0
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +38 -0
- package/src/components/form/filter/__tests__/useFilterActionProps.test.tsx +95 -0
- package/src/components/form/filter/index.ts +2 -0
- package/src/components/form/filter/useFilterActionProps.ts +37 -6
- package/src/components/index.ts +1 -0
- package/src/entry-actions/EntryActionManager.ts +76 -0
- package/src/entry-actions/index.ts +10 -0
- package/src/flow/FlowPage.tsx +38 -3
- package/src/flow/__tests__/FlowPage.test.tsx +201 -27
- package/src/flow/__tests__/FlowRoute.test.tsx +549 -4
- package/src/flow/actions/__tests__/dataScopeFilter.test.ts +62 -0
- package/src/flow/actions/__tests__/linkageRules.tab.test.ts +171 -0
- package/src/flow/actions/__tests__/linkageRulesRefresh.test.ts +7 -3
- package/src/flow/actions/__tests__/openView.defineProps.route.test.tsx +80 -20
- package/src/flow/actions/dataScopeFilter.ts +10 -1
- package/src/flow/actions/dateTimeFormat.tsx +2 -2
- package/src/flow/actions/index.ts +2 -0
- package/src/flow/actions/linkageRules.tsx +86 -11
- package/src/flow/actions/linkageRulesRefresh.tsx +2 -6
- package/src/flow/actions/openView.tsx +21 -1
- package/src/flow/admin-shell/BaseLayoutModel.tsx +124 -0
- package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +184 -42
- package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +1016 -119
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +41 -5
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +177 -1
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +20 -0
- package/src/flow/admin-shell/admin-layout/AppListRender.tsx +13 -2
- package/src/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.tsx +289 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +253 -6
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +436 -2
- package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +48 -0
- package/src/flow/admin-shell/admin-layout/index.ts +1 -0
- package/src/flow/admin-shell/admin-layout/useApplications.tsx +81 -12
- package/src/flow/common/Markdown/Display.tsx +14 -3
- package/src/flow/common/Markdown/Edit.tsx +19 -7
- package/src/flow/components/FieldAssignExactDatePicker.tsx +25 -11
- package/src/flow/components/FieldAssignValueInput.tsx +91 -20
- package/src/flow/components/FlowRoute.tsx +134 -18
- package/src/flow/components/RunJSValueEditor.tsx +9 -1
- package/src/flow/components/__tests__/FieldAssignValueInput.context.test.tsx +216 -0
- package/src/flow/components/filter/FilterGroup.tsx +33 -5
- package/src/flow/components/filter/VariableFilterItem.tsx +158 -10
- package/src/flow/components/filter/__tests__/FilterGroup.test.tsx +45 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.leftMetaTree.test.tsx +9 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.test.tsx +70 -1
- package/src/flow/index.ts +1 -0
- package/src/flow/internal/components/Markdown/util.ts +2 -1
- package/src/flow/models/base/ActionModel.tsx +10 -8
- package/src/flow/models/base/ActionModelCore.tsx +5 -0
- package/src/flow/models/base/PageModel/PageModel.tsx +387 -53
- package/src/flow/models/base/PageModel/PageModelTabBar.tsx +114 -0
- package/src/flow/models/base/PageModel/PageTabModel.tsx +184 -3
- package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +790 -10
- package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.module-isolation.test.tsx +130 -0
- package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.test.tsx +118 -0
- package/src/flow/models/base/PageModel/__tests__/PageTabModel.test.ts +572 -1
- package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +1 -0
- package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +27 -12
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts +36 -0
- package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +34 -0
- package/src/flow/models/blocks/form/QuickEditFormModel.tsx +189 -36
- package/src/flow/models/blocks/form/__tests__/QuickEditFormModel.quickEdit.test.ts +350 -2
- package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +2 -1
- package/src/flow/models/blocks/table/TableBlockModel.tsx +1 -1
- package/src/flow/models/blocks/table/TableColumnModel.tsx +6 -2
- package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +51 -0
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +2 -1
- package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +45 -13
- package/src/flow/models/fields/TextareaFieldModel.tsx +42 -19
- package/src/flow/models/fields/VariableFieldFormModel.tsx +3 -3
- package/src/flow/models/fields/__tests__/TextareaFieldModel.test.tsx +32 -1
- package/src/flow/models/fields/__tests__/VariableFieldFormModel.test.tsx +51 -0
- package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +20 -10
- package/src/flow/models/fields/mobile-components/MobileSelect.tsx +24 -12
- package/src/flow/models/topbar/TopbarActionModel.tsx +78 -3
- package/src/flow/routeTransientInputArgs.ts +27 -0
- package/src/flow/utils/__tests__/dateTimeFormat.test.ts +42 -0
- package/src/flow-compat/fieldValidationConstants.ts +1 -1
- package/src/flow-compat/routeTypes.ts +1 -0
- package/src/index.ts +6 -0
- package/src/locale/languageCodes.ts +2 -1
- package/src/nocobase-buildin-plugin/index.tsx +19 -1
- package/src/utils/getRouteRuntimeVersion.ts +185 -0
- package/src/utils/index.tsx +1 -0
- package/src/utils/markdownSanitize.ts +88 -0
|
@@ -18,24 +18,53 @@ vi.mock('@nocobase/flow-engine', async (importOriginal) => {
|
|
|
18
18
|
return {
|
|
19
19
|
...actual,
|
|
20
20
|
FlowModel: class {
|
|
21
|
+
uid: string;
|
|
22
|
+
parentId?: string;
|
|
21
23
|
props: any;
|
|
22
24
|
context: any;
|
|
23
25
|
stepParams: any;
|
|
26
|
+
flowEngine?: {
|
|
27
|
+
modelRepository?: {
|
|
28
|
+
findOne?: (query: Record<string, unknown>) => Promise<unknown>;
|
|
29
|
+
};
|
|
30
|
+
flowSettings?: {
|
|
31
|
+
open?: (options: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
flowRegistryData: Record<string, unknown>;
|
|
35
|
+
invalidateFlowCache = vi.fn();
|
|
36
|
+
rerender = vi.fn(async () => undefined);
|
|
24
37
|
|
|
25
38
|
constructor(options: any = {}) {
|
|
39
|
+
this.uid = options.uid || 'mock-model';
|
|
40
|
+
this.parentId = options.parentId;
|
|
26
41
|
this.props = options.props || {};
|
|
27
42
|
this.context = options.context || {};
|
|
28
43
|
this.stepParams = options.stepParams || {};
|
|
44
|
+
this.flowEngine = options.flowEngine;
|
|
45
|
+
this.flowRegistryData = options.flowRegistry || {};
|
|
29
46
|
}
|
|
30
47
|
|
|
31
48
|
serialize() {
|
|
32
|
-
return { flowRegistry:
|
|
49
|
+
return { flowRegistry: this.flowRegistryData };
|
|
33
50
|
}
|
|
34
51
|
|
|
35
52
|
setProps(key: string, value: any) {
|
|
36
53
|
this.props[key] = value;
|
|
37
54
|
}
|
|
38
55
|
|
|
56
|
+
setStepParams(flowKey: string, stepKey: string, params: Record<string, unknown>) {
|
|
57
|
+
this.stepParams[flowKey] = this.stepParams[flowKey] || {};
|
|
58
|
+
this.stepParams[flowKey][stepKey] = {
|
|
59
|
+
...(this.stepParams[flowKey][stepKey] || {}),
|
|
60
|
+
...params,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
openFlowSettings(options: Record<string, unknown> = {}) {
|
|
65
|
+
return this.flowEngine?.flowSettings?.open?.({ model: this, ...options });
|
|
66
|
+
}
|
|
67
|
+
|
|
39
68
|
onInit() {}
|
|
40
69
|
static registerFlow(flow: any) {
|
|
41
70
|
registerFlowMock(flow);
|
|
@@ -86,6 +115,13 @@ describe('PageTabModel', () => {
|
|
|
86
115
|
expect(keys.indexOf('documentTitle')).toBe(keys.indexOf('title') + 1);
|
|
87
116
|
});
|
|
88
117
|
|
|
118
|
+
it('should expose tab linkage rules in page tab settings', async () => {
|
|
119
|
+
await import('../PageTabModel');
|
|
120
|
+
const flow = registerFlowMock.mock.calls.find((call) => call[0]?.key === 'pageTabSettings')?.[0];
|
|
121
|
+
|
|
122
|
+
expect(flow?.steps?.linkageRules?.use).toBe('tabLinkageRules');
|
|
123
|
+
});
|
|
124
|
+
|
|
89
125
|
it('should trigger parent page title update in tab settings handler', async () => {
|
|
90
126
|
await import('../PageTabModel');
|
|
91
127
|
const flow = registerFlowMock.mock.calls.find((call) => call[0]?.key === 'pageTabSettings')?.[0];
|
|
@@ -222,4 +258,539 @@ describe('PageTabModel', () => {
|
|
|
222
258
|
documentTitle: 'Server doc title',
|
|
223
259
|
});
|
|
224
260
|
});
|
|
261
|
+
|
|
262
|
+
describe('root tab linkage hydrate', () => {
|
|
263
|
+
it('should hydrate linkage rules before opening settings in configuration mode', async () => {
|
|
264
|
+
const { RootPageTabModel } = await import('../PageTabModel');
|
|
265
|
+
const linkageRules = { value: [{ key: 'rule-1' }] };
|
|
266
|
+
const request = vi.fn().mockResolvedValue({
|
|
267
|
+
data: {
|
|
268
|
+
data: {
|
|
269
|
+
uid: 'tab-1',
|
|
270
|
+
use: 'RouteModel',
|
|
271
|
+
props: { title: 'Stale anchor title' },
|
|
272
|
+
stepParams: {
|
|
273
|
+
pageTabSettings: {
|
|
274
|
+
tab: { title: 'Stale tab title' },
|
|
275
|
+
linkageRules,
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
const open = vi.fn(({ model }: { model: { stepParams: Record<string, unknown> } }) => {
|
|
282
|
+
expect(model.stepParams).toMatchObject({ pageTabSettings: { linkageRules } });
|
|
283
|
+
return 'opened';
|
|
284
|
+
});
|
|
285
|
+
const model = new RootPageTabModel({
|
|
286
|
+
uid: 'tab-1',
|
|
287
|
+
flowEngine: {
|
|
288
|
+
flowSettings: { open },
|
|
289
|
+
},
|
|
290
|
+
props: {
|
|
291
|
+
route: {
|
|
292
|
+
schemaUid: 'tab-1',
|
|
293
|
+
title: 'Current route title',
|
|
294
|
+
options: {},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
stepParams: {
|
|
298
|
+
pageTabSettings: {
|
|
299
|
+
tab: { title: 'Current tab title' },
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
context: {
|
|
303
|
+
api: { request },
|
|
304
|
+
flowSettingsEnabled: true,
|
|
305
|
+
defineProperty: vi.fn(),
|
|
306
|
+
t: (value: string) => value,
|
|
307
|
+
},
|
|
308
|
+
} as any);
|
|
309
|
+
|
|
310
|
+
model.onInit({});
|
|
311
|
+
await model.openFlowSettings({ flowKey: 'pageTabSettings', stepKey: 'linkageRules' });
|
|
312
|
+
|
|
313
|
+
expect(request).toHaveBeenCalledWith({
|
|
314
|
+
url: 'flowModels:findOne',
|
|
315
|
+
params: { uid: 'tab-1' },
|
|
316
|
+
});
|
|
317
|
+
expect(model.props.route.title).toBe('Current route title');
|
|
318
|
+
expect(model.stepParams.pageTabSettings.tab.title).toBe('Current tab title');
|
|
319
|
+
expect(model.stepParams.pageTabSettings.linkageRules).toEqual(linkageRules);
|
|
320
|
+
expect(model.invalidateFlowCache).toHaveBeenCalledWith('beforeRender', true);
|
|
321
|
+
expect(model.rerender).toHaveBeenCalledTimes(1);
|
|
322
|
+
expect(open).toHaveBeenCalledTimes(1);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('should only hydrate marked root tabs at runtime', async () => {
|
|
326
|
+
const { RootPageTabModel } = await import('../PageTabModel');
|
|
327
|
+
const unmarkedRequest = vi.fn().mockResolvedValue({ data: { data: null } });
|
|
328
|
+
const markedRequest = vi.fn().mockResolvedValue({
|
|
329
|
+
data: {
|
|
330
|
+
data: {
|
|
331
|
+
stepParams: {
|
|
332
|
+
pageTabSettings: {
|
|
333
|
+
linkageRules: { value: [] },
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
});
|
|
339
|
+
const createModel = (request: typeof markedRequest, marked: boolean) =>
|
|
340
|
+
new RootPageTabModel({
|
|
341
|
+
uid: marked ? 'tab-marked' : 'tab-unmarked',
|
|
342
|
+
props: {
|
|
343
|
+
route: {
|
|
344
|
+
schemaUid: marked ? 'tab-marked' : 'tab-unmarked',
|
|
345
|
+
options: marked ? { hasPersistedPageTabFlowModel: true } : {},
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
context: {
|
|
349
|
+
api: { request },
|
|
350
|
+
flowSettingsEnabled: false,
|
|
351
|
+
defineProperty: vi.fn(),
|
|
352
|
+
t: (value: string) => value,
|
|
353
|
+
},
|
|
354
|
+
} as any);
|
|
355
|
+
|
|
356
|
+
const unmarkedModel = createModel(unmarkedRequest, false);
|
|
357
|
+
const markedModel = createModel(markedRequest, true);
|
|
358
|
+
unmarkedModel.onInit({});
|
|
359
|
+
markedModel.onInit({});
|
|
360
|
+
|
|
361
|
+
await vi.waitFor(() => {
|
|
362
|
+
expect(markedRequest).toHaveBeenCalledTimes(1);
|
|
363
|
+
expect(markedModel.stepParams.pageTabSettings.linkageRules).toEqual({ value: [] });
|
|
364
|
+
});
|
|
365
|
+
expect(unmarkedRequest).not.toHaveBeenCalled();
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it('should ignore the linkage-specific legacy marker at runtime', async () => {
|
|
369
|
+
const { RootPageTabModel } = await import('../PageTabModel');
|
|
370
|
+
const request = vi.fn().mockResolvedValue({ data: { data: null } });
|
|
371
|
+
const legacyMarker = ['hasPersistedPageTab', 'LinkageRules'].join('');
|
|
372
|
+
const model = new RootPageTabModel({
|
|
373
|
+
uid: 'tab-legacy-marker',
|
|
374
|
+
props: {
|
|
375
|
+
route: {
|
|
376
|
+
schemaUid: 'tab-legacy-marker',
|
|
377
|
+
options: { [legacyMarker]: true },
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
context: {
|
|
381
|
+
api: { request },
|
|
382
|
+
flowSettingsEnabled: false,
|
|
383
|
+
defineProperty: vi.fn(),
|
|
384
|
+
t: (value: string) => value,
|
|
385
|
+
},
|
|
386
|
+
} as any);
|
|
387
|
+
|
|
388
|
+
model.onInit({});
|
|
389
|
+
|
|
390
|
+
expect(request).not.toHaveBeenCalled();
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('should share one in-flight hydrate request across concurrent settings opens', async () => {
|
|
394
|
+
const { RootPageTabModel } = await import('../PageTabModel');
|
|
395
|
+
let resolveAnchor: (value: unknown) => void = () => undefined;
|
|
396
|
+
const request = vi.fn(
|
|
397
|
+
() =>
|
|
398
|
+
new Promise<unknown>((resolve) => {
|
|
399
|
+
resolveAnchor = (value) => resolve({ data: { data: value } });
|
|
400
|
+
}),
|
|
401
|
+
);
|
|
402
|
+
const open = vi.fn().mockResolvedValue(undefined);
|
|
403
|
+
const model = new RootPageTabModel({
|
|
404
|
+
uid: 'tab-1',
|
|
405
|
+
flowEngine: {
|
|
406
|
+
flowSettings: { open },
|
|
407
|
+
},
|
|
408
|
+
props: { route: { schemaUid: 'tab-1', options: {} } },
|
|
409
|
+
context: {
|
|
410
|
+
api: { request },
|
|
411
|
+
flowSettingsEnabled: false,
|
|
412
|
+
t: (value: string) => value,
|
|
413
|
+
},
|
|
414
|
+
} as any);
|
|
415
|
+
|
|
416
|
+
const firstOpen = model.openFlowSettings({ flowKey: 'pageTabSettings', stepKey: 'linkageRules' });
|
|
417
|
+
const secondOpen = model.openFlowSettings({ flowKey: 'pageTabSettings', stepKey: 'linkageRules' });
|
|
418
|
+
|
|
419
|
+
await vi.waitFor(() => expect(request).toHaveBeenCalledTimes(1));
|
|
420
|
+
resolveAnchor({
|
|
421
|
+
stepParams: {
|
|
422
|
+
pageTabSettings: {
|
|
423
|
+
linkageRules: { value: [] },
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
await Promise.all([firstOpen, secondOpen]);
|
|
428
|
+
|
|
429
|
+
expect(request).toHaveBeenCalledTimes(1);
|
|
430
|
+
expect(open).toHaveBeenCalledTimes(2);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it('should safely handle missing anchors and missing linkage steps', async () => {
|
|
434
|
+
const { RootPageTabModel } = await import('../PageTabModel');
|
|
435
|
+
const request = vi.fn().mockResolvedValue({ data: { data: null } });
|
|
436
|
+
const model = new RootPageTabModel({
|
|
437
|
+
uid: 'tab-1',
|
|
438
|
+
flowEngine: {
|
|
439
|
+
flowSettings: { open: vi.fn().mockResolvedValue(undefined) },
|
|
440
|
+
},
|
|
441
|
+
props: { route: { schemaUid: 'tab-1', options: {} } },
|
|
442
|
+
stepParams: {
|
|
443
|
+
pageTabSettings: {
|
|
444
|
+
tab: { title: 'Current tab title' },
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
context: {
|
|
448
|
+
api: { request },
|
|
449
|
+
flowSettingsEnabled: true,
|
|
450
|
+
defineProperty: vi.fn(),
|
|
451
|
+
t: (value: string) => value,
|
|
452
|
+
},
|
|
453
|
+
} as any);
|
|
454
|
+
|
|
455
|
+
model.onInit({});
|
|
456
|
+
await expect(
|
|
457
|
+
model.openFlowSettings({ flowKey: 'pageTabSettings', stepKey: 'linkageRules' }),
|
|
458
|
+
).resolves.toBeUndefined();
|
|
459
|
+
|
|
460
|
+
expect(request).toHaveBeenCalledWith({
|
|
461
|
+
url: 'flowModels:findOne',
|
|
462
|
+
params: { uid: 'tab-1' },
|
|
463
|
+
});
|
|
464
|
+
expect(model.stepParams.pageTabSettings.linkageRules).toBeUndefined();
|
|
465
|
+
expect(model.stepParams.pageTabSettings.tab.title).toBe('Current tab title');
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
describe('root tab linkage persistence', () => {
|
|
470
|
+
it('should not touch the anchor or marker when linkage rules were never loaded', async () => {
|
|
471
|
+
const { RootPageTabModel } = await import('../PageTabModel');
|
|
472
|
+
const request = vi.fn().mockResolvedValue({});
|
|
473
|
+
const updateRoute = vi.fn();
|
|
474
|
+
const model = new RootPageTabModel({
|
|
475
|
+
uid: 'tab-1',
|
|
476
|
+
props: {
|
|
477
|
+
route: {
|
|
478
|
+
id: 10,
|
|
479
|
+
schemaUid: 'tab-1',
|
|
480
|
+
options: { badge: 'new' },
|
|
481
|
+
},
|
|
482
|
+
},
|
|
483
|
+
stepParams: {
|
|
484
|
+
pageTabSettings: {
|
|
485
|
+
tab: { title: 'Tab title' },
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
context: {
|
|
489
|
+
api: { request },
|
|
490
|
+
routeRepository: { updateRoute },
|
|
491
|
+
t: (value: string) => value,
|
|
492
|
+
},
|
|
493
|
+
} as any);
|
|
494
|
+
|
|
495
|
+
await model.saveStepParams();
|
|
496
|
+
|
|
497
|
+
expect(request).toHaveBeenCalledTimes(1);
|
|
498
|
+
expect(request.mock.calls[0][0].url).toBe('desktopRoutes:updateOrCreate');
|
|
499
|
+
expect(updateRoute).not.toHaveBeenCalled();
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
it('should merge the latest anchor without sending subModels and then set the marker', async () => {
|
|
503
|
+
const { RootPageTabModel } = await import('../PageTabModel');
|
|
504
|
+
const latestAnchor = {
|
|
505
|
+
uid: 'tab-1',
|
|
506
|
+
use: 'CustomRouteModel',
|
|
507
|
+
props: { anchorProp: true },
|
|
508
|
+
decoratorProps: { compact: true },
|
|
509
|
+
stepParams: {
|
|
510
|
+
pageTabSettings: {
|
|
511
|
+
tab: { title: 'Anchor tab title' },
|
|
512
|
+
linkageRules: { value: [{ key: 'old-rule' }] },
|
|
513
|
+
},
|
|
514
|
+
otherFlow: {
|
|
515
|
+
otherStep: { value: 1 },
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
flowRegistry: { customFlow: { steps: {} } },
|
|
519
|
+
unknownRoot: { keep: true },
|
|
520
|
+
subModels: {
|
|
521
|
+
grid: { uid: 'grid-1' },
|
|
522
|
+
},
|
|
523
|
+
};
|
|
524
|
+
const request = vi.fn(async ({ url }: { url: string }) => {
|
|
525
|
+
if (url === 'desktopRoutes:updateOrCreate') {
|
|
526
|
+
return { data: { data: { id: 10, schemaUid: 'tab-1' } } };
|
|
527
|
+
}
|
|
528
|
+
if (url === 'flowModels:findOne') {
|
|
529
|
+
return { data: { data: latestAnchor } };
|
|
530
|
+
}
|
|
531
|
+
return { data: { data: {} } };
|
|
532
|
+
});
|
|
533
|
+
const updateRoute = vi.fn().mockResolvedValue(undefined);
|
|
534
|
+
const linkageRules = { value: [{ key: 'new-rule' }] };
|
|
535
|
+
const model = new RootPageTabModel({
|
|
536
|
+
uid: 'tab-1',
|
|
537
|
+
flowRegistry: { routeFlow: { steps: {} } },
|
|
538
|
+
props: {
|
|
539
|
+
route: {
|
|
540
|
+
id: 10,
|
|
541
|
+
schemaUid: 'tab-1',
|
|
542
|
+
options: {
|
|
543
|
+
badge: 'new',
|
|
544
|
+
pluginOption: { keep: true },
|
|
545
|
+
flowRegistry: { routeFlow: { steps: {} } },
|
|
546
|
+
},
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
stepParams: {
|
|
550
|
+
pageTabSettings: {
|
|
551
|
+
tab: {
|
|
552
|
+
title: 'Tab title',
|
|
553
|
+
documentTitle: 'Tab document title',
|
|
554
|
+
},
|
|
555
|
+
linkageRules,
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
context: {
|
|
559
|
+
api: { request },
|
|
560
|
+
routeRepository: { updateRoute },
|
|
561
|
+
t: (value: string) => value,
|
|
562
|
+
},
|
|
563
|
+
} as any);
|
|
564
|
+
|
|
565
|
+
await model.saveStepParams();
|
|
566
|
+
|
|
567
|
+
const urls = request.mock.calls.map(([config]) => config.url);
|
|
568
|
+
expect(urls).toEqual(['desktopRoutes:updateOrCreate', 'flowModels:findOne', 'flowModels:save']);
|
|
569
|
+
expect(request.mock.calls[0][0].data.options).toMatchObject({
|
|
570
|
+
badge: 'new',
|
|
571
|
+
pluginOption: { keep: true },
|
|
572
|
+
flowRegistry: { routeFlow: { steps: {} } },
|
|
573
|
+
documentTitle: 'Tab document title',
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
const anchorPayload = request.mock.calls[2][0].data;
|
|
577
|
+
expect(anchorPayload).toMatchObject({
|
|
578
|
+
uid: 'tab-1',
|
|
579
|
+
use: 'CustomRouteModel',
|
|
580
|
+
props: { anchorProp: true },
|
|
581
|
+
decoratorProps: { compact: true },
|
|
582
|
+
stepParams: {
|
|
583
|
+
pageTabSettings: {
|
|
584
|
+
tab: { title: 'Anchor tab title' },
|
|
585
|
+
linkageRules,
|
|
586
|
+
},
|
|
587
|
+
otherFlow: {
|
|
588
|
+
otherStep: { value: 1 },
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
flowRegistry: { customFlow: { steps: {} } },
|
|
592
|
+
unknownRoot: { keep: true },
|
|
593
|
+
});
|
|
594
|
+
expect(anchorPayload).not.toHaveProperty('subModels');
|
|
595
|
+
expect(updateRoute).toHaveBeenCalledWith(
|
|
596
|
+
10,
|
|
597
|
+
{
|
|
598
|
+
options: expect.objectContaining({
|
|
599
|
+
badge: 'new',
|
|
600
|
+
pluginOption: { keep: true },
|
|
601
|
+
hasPersistedPageTabFlowModel: true,
|
|
602
|
+
}),
|
|
603
|
+
},
|
|
604
|
+
{ refreshAfterMutation: false },
|
|
605
|
+
);
|
|
606
|
+
expect(request.mock.invocationCallOrder[2]).toBeLessThan(updateRoute.mock.invocationCallOrder[0]);
|
|
607
|
+
expect(model.props.route.options.hasPersistedPageTabFlowModel).toBe(true);
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
it('should read the latest anchor again before every linkage save', async () => {
|
|
611
|
+
const { RootPageTabModel } = await import('../PageTabModel');
|
|
612
|
+
const request = vi.fn(async ({ url }: { url: string }) => {
|
|
613
|
+
if (url === 'flowModels:findOne') {
|
|
614
|
+
return { data: { data: { uid: 'tab-1', use: 'RouteModel' } } };
|
|
615
|
+
}
|
|
616
|
+
return {};
|
|
617
|
+
});
|
|
618
|
+
const model = new RootPageTabModel({
|
|
619
|
+
uid: 'tab-1',
|
|
620
|
+
props: { route: { id: 10, schemaUid: 'tab-1', options: {} } },
|
|
621
|
+
stepParams: {
|
|
622
|
+
pageTabSettings: {
|
|
623
|
+
tab: { title: 'Tab title' },
|
|
624
|
+
linkageRules: { value: [] },
|
|
625
|
+
},
|
|
626
|
+
},
|
|
627
|
+
context: {
|
|
628
|
+
api: { request },
|
|
629
|
+
routeRepository: { updateRoute: vi.fn().mockResolvedValue(undefined) },
|
|
630
|
+
t: (value: string) => value,
|
|
631
|
+
},
|
|
632
|
+
} as any);
|
|
633
|
+
|
|
634
|
+
await model.saveStepParams();
|
|
635
|
+
await model.saveStepParams();
|
|
636
|
+
|
|
637
|
+
expect(request.mock.calls.filter(([config]) => config.url === 'flowModels:findOne')).toHaveLength(2);
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
it('should persist empty rules without destroying the anchor and clear the marker', async () => {
|
|
641
|
+
const { RootPageTabModel } = await import('../PageTabModel');
|
|
642
|
+
const request = vi.fn(async ({ url }: { url: string }) => {
|
|
643
|
+
if (url === 'flowModels:findOne') {
|
|
644
|
+
return {
|
|
645
|
+
data: {
|
|
646
|
+
data: {
|
|
647
|
+
uid: 'tab-1',
|
|
648
|
+
use: 'RouteModel',
|
|
649
|
+
subModels: { grid: { uid: 'grid-1' } },
|
|
650
|
+
},
|
|
651
|
+
},
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
return {};
|
|
655
|
+
});
|
|
656
|
+
const updateRoute = vi.fn().mockResolvedValue(undefined);
|
|
657
|
+
const model = new RootPageTabModel({
|
|
658
|
+
uid: 'tab-1',
|
|
659
|
+
props: {
|
|
660
|
+
route: {
|
|
661
|
+
id: 10,
|
|
662
|
+
schemaUid: 'tab-1',
|
|
663
|
+
options: {
|
|
664
|
+
badge: 'new',
|
|
665
|
+
hasPersistedPageTabFlowModel: true,
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
},
|
|
669
|
+
stepParams: {
|
|
670
|
+
pageTabSettings: {
|
|
671
|
+
tab: { title: 'Tab title' },
|
|
672
|
+
linkageRules: { value: [] },
|
|
673
|
+
},
|
|
674
|
+
},
|
|
675
|
+
context: {
|
|
676
|
+
api: { request },
|
|
677
|
+
routeRepository: { updateRoute },
|
|
678
|
+
t: (value: string) => value,
|
|
679
|
+
},
|
|
680
|
+
} as any);
|
|
681
|
+
|
|
682
|
+
await model.saveStepParams();
|
|
683
|
+
|
|
684
|
+
const urls = request.mock.calls.map(([config]) => config.url);
|
|
685
|
+
expect(urls).toContain('flowModels:save');
|
|
686
|
+
expect(urls).not.toContain('flowModels:destroy');
|
|
687
|
+
const anchorPayload = request.mock.calls.find(([config]) => config.url === 'flowModels:save')?.[0].data;
|
|
688
|
+
expect(anchorPayload.stepParams.pageTabSettings.linkageRules).toEqual({ value: [] });
|
|
689
|
+
expect(anchorPayload).not.toHaveProperty('subModels');
|
|
690
|
+
expect(updateRoute.mock.calls[0][1].options).toMatchObject({ badge: 'new' });
|
|
691
|
+
expect(updateRoute.mock.calls[0][1].options).not.toHaveProperty('hasPersistedPageTabFlowModel');
|
|
692
|
+
expect(model.props.route.options).not.toHaveProperty('hasPersistedPageTabFlowModel');
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
it('should create a minimal RouteModel anchor when the anchor is missing', async () => {
|
|
696
|
+
const { RootPageTabModel } = await import('../PageTabModel');
|
|
697
|
+
const request = vi.fn(async ({ url }: { url: string }) => {
|
|
698
|
+
if (url === 'flowModels:findOne') {
|
|
699
|
+
return { data: { data: null } };
|
|
700
|
+
}
|
|
701
|
+
return {};
|
|
702
|
+
});
|
|
703
|
+
const model = new RootPageTabModel({
|
|
704
|
+
uid: 'tab-1',
|
|
705
|
+
props: { route: { id: 10, schemaUid: 'tab-1', options: {} } },
|
|
706
|
+
stepParams: {
|
|
707
|
+
pageTabSettings: {
|
|
708
|
+
tab: { title: 'Tab title' },
|
|
709
|
+
linkageRules: { value: [{ key: 'rule-1' }] },
|
|
710
|
+
},
|
|
711
|
+
},
|
|
712
|
+
context: {
|
|
713
|
+
api: { request },
|
|
714
|
+
routeRepository: { updateRoute: vi.fn().mockResolvedValue(undefined) },
|
|
715
|
+
t: (value: string) => value,
|
|
716
|
+
},
|
|
717
|
+
} as any);
|
|
718
|
+
|
|
719
|
+
await model.saveStepParams();
|
|
720
|
+
|
|
721
|
+
const anchorPayload = request.mock.calls.find(([config]) => config.url === 'flowModels:save')?.[0].data;
|
|
722
|
+
expect(anchorPayload).toMatchObject({
|
|
723
|
+
uid: 'tab-1',
|
|
724
|
+
use: 'RouteModel',
|
|
725
|
+
stepParams: {
|
|
726
|
+
pageTabSettings: {
|
|
727
|
+
linkageRules: { value: [{ key: 'rule-1' }] },
|
|
728
|
+
},
|
|
729
|
+
},
|
|
730
|
+
});
|
|
731
|
+
expect(anchorPayload).not.toHaveProperty('props.route');
|
|
732
|
+
expect(anchorPayload).not.toHaveProperty('subModels');
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
it('should not update the marker when saving the anchor fails', async () => {
|
|
736
|
+
const { RootPageTabModel } = await import('../PageTabModel');
|
|
737
|
+
const error = new Error('anchor save failed');
|
|
738
|
+
const request = vi.fn(async ({ url }: { url: string }) => {
|
|
739
|
+
if (url === 'flowModels:findOne') {
|
|
740
|
+
return { data: { data: { uid: 'tab-1', use: 'RouteModel' } } };
|
|
741
|
+
}
|
|
742
|
+
if (url === 'flowModels:save') {
|
|
743
|
+
throw error;
|
|
744
|
+
}
|
|
745
|
+
return {};
|
|
746
|
+
});
|
|
747
|
+
const updateRoute = vi.fn();
|
|
748
|
+
const model = new RootPageTabModel({
|
|
749
|
+
uid: 'tab-1',
|
|
750
|
+
props: { route: { id: 10, schemaUid: 'tab-1', options: {} } },
|
|
751
|
+
stepParams: {
|
|
752
|
+
pageTabSettings: {
|
|
753
|
+
linkageRules: { value: [{ key: 'rule-1' }] },
|
|
754
|
+
},
|
|
755
|
+
},
|
|
756
|
+
context: {
|
|
757
|
+
api: { request },
|
|
758
|
+
routeRepository: { updateRoute },
|
|
759
|
+
t: (value: string) => value,
|
|
760
|
+
},
|
|
761
|
+
} as any);
|
|
762
|
+
|
|
763
|
+
await expect(model.saveStepParams()).rejects.toBe(error);
|
|
764
|
+
expect(updateRoute).not.toHaveBeenCalled();
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
it('should reject when updating the route marker fails', async () => {
|
|
768
|
+
const { RootPageTabModel } = await import('../PageTabModel');
|
|
769
|
+
const error = new Error('marker update failed');
|
|
770
|
+
const request = vi.fn(async ({ url }: { url: string }) => {
|
|
771
|
+
if (url === 'flowModels:findOne') {
|
|
772
|
+
return { data: { data: { uid: 'tab-1', use: 'RouteModel' } } };
|
|
773
|
+
}
|
|
774
|
+
return {};
|
|
775
|
+
});
|
|
776
|
+
const updateRoute = vi.fn().mockRejectedValue(error);
|
|
777
|
+
const model = new RootPageTabModel({
|
|
778
|
+
uid: 'tab-1',
|
|
779
|
+
props: { route: { id: 10, schemaUid: 'tab-1', options: {} } },
|
|
780
|
+
stepParams: {
|
|
781
|
+
pageTabSettings: {
|
|
782
|
+
linkageRules: { value: [{ key: 'rule-1' }] },
|
|
783
|
+
},
|
|
784
|
+
},
|
|
785
|
+
context: {
|
|
786
|
+
api: { request },
|
|
787
|
+
routeRepository: { updateRoute },
|
|
788
|
+
t: (value: string) => value,
|
|
789
|
+
},
|
|
790
|
+
} as any);
|
|
791
|
+
|
|
792
|
+
await expect(model.saveStepParams()).rejects.toBe(error);
|
|
793
|
+
expect(request.mock.calls.some(([config]) => config.url === 'flowModels:save')).toBe(true);
|
|
794
|
+
});
|
|
795
|
+
});
|
|
225
796
|
});
|
|
@@ -431,6 +431,7 @@ export class FilterFormBlockModel extends FilterBlockModel<{
|
|
|
431
431
|
|
|
432
432
|
private canApplyFormDefaultValue(name: string, current: any, force?: boolean) {
|
|
433
433
|
if (force) return true;
|
|
434
|
+
if (this.userEditedFieldNames.has(name)) return false;
|
|
434
435
|
if (isEmptyValue(current)) return true;
|
|
435
436
|
if (!this.lastDefaultValueByFieldName.has(name)) return false;
|
|
436
437
|
return isEqual(current, this.lastDefaultValueByFieldName.get(name));
|
|
@@ -62,9 +62,25 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
62
62
|
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
interface CollectionFieldWithAssociationMarker {
|
|
66
|
+
isAssociationField?: () => boolean;
|
|
67
|
+
target?: unknown;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function hasAssociationMarker(value: unknown): value is CollectionFieldWithAssociationMarker {
|
|
71
|
+
return isRecord(value) && (typeof value.isAssociationField === 'function' || 'target' in value);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const isAssociationCollectionField = (collectionField: unknown) => {
|
|
75
|
+
if (!hasAssociationMarker(collectionField)) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
return collectionField.isAssociationField ? collectionField.isAssociationField() : Boolean(collectionField.target);
|
|
79
|
+
};
|
|
80
|
+
|
|
65
81
|
const normalizeAssociationDefaultFilterValue = (value: any, fieldModel: any) => {
|
|
66
82
|
const collectionField = fieldModel?.context?.collectionField;
|
|
67
|
-
if (!collectionField
|
|
83
|
+
if (!isAssociationCollectionField(collectionField)) {
|
|
68
84
|
return value;
|
|
69
85
|
}
|
|
70
86
|
|
|
@@ -171,8 +187,7 @@ const buildFilterFormFieldItem = ({
|
|
|
171
187
|
if (!binding) {
|
|
172
188
|
return;
|
|
173
189
|
}
|
|
174
|
-
const isAssociation =
|
|
175
|
-
typeof field?.isAssociationField === 'function' ? field.isAssociationField() : Boolean(field?.target);
|
|
190
|
+
const isAssociation = isAssociationCollectionField(field);
|
|
176
191
|
const fieldModel =
|
|
177
192
|
isAssociation && ctxWithFlags.engine?.getModelClass?.('FilterFormRecordSelectFieldModel')
|
|
178
193
|
? 'FilterFormRecordSelectFieldModel'
|
|
@@ -507,10 +522,7 @@ export class FilterFormItemModel extends FilterableItemModel<{
|
|
|
507
522
|
const formValue = this.context.form?.getFieldValue(this.props.name);
|
|
508
523
|
const modelValue = fieldModel.getFilterValue ? fieldModel.getFilterValue() : formValue;
|
|
509
524
|
const collectionField = (fieldModel as any)?.context?.collectionField;
|
|
510
|
-
const isAssociationField =
|
|
511
|
-
typeof collectionField?.isAssociationField === 'function'
|
|
512
|
-
? collectionField.isAssociationField()
|
|
513
|
-
: !!collectionField?.target;
|
|
525
|
+
const isAssociationField = isAssociationCollectionField(collectionField);
|
|
514
526
|
const shouldUseFormValue =
|
|
515
527
|
isAssociationField &&
|
|
516
528
|
!this.mounted &&
|
|
@@ -547,11 +559,7 @@ export class FilterFormItemModel extends FilterableItemModel<{
|
|
|
547
559
|
return value;
|
|
548
560
|
}
|
|
549
561
|
const collectionField = (fieldModel as any)?.context?.collectionField;
|
|
550
|
-
|
|
551
|
-
typeof collectionField?.isAssociationField === 'function'
|
|
552
|
-
? collectionField.isAssociationField()
|
|
553
|
-
: !!collectionField?.target;
|
|
554
|
-
if (!isAssociation) {
|
|
562
|
+
if (!isAssociationCollectionField(collectionField)) {
|
|
555
563
|
return value;
|
|
556
564
|
}
|
|
557
565
|
const normalizedFieldNames = normalizeAssociationFieldNames(
|
|
@@ -798,6 +806,13 @@ FilterFormItemModel.registerFlow({
|
|
|
798
806
|
},
|
|
799
807
|
defaultOperator: {
|
|
800
808
|
use: 'defaultOperator',
|
|
809
|
+
hideInSettings(ctx) {
|
|
810
|
+
const collectionField =
|
|
811
|
+
ctx.collectionField ||
|
|
812
|
+
ctx.model?.context?.collectionField ||
|
|
813
|
+
ctx.model?.subModels?.field?.context?.collectionField;
|
|
814
|
+
return isAssociationCollectionField(collectionField);
|
|
815
|
+
},
|
|
801
816
|
},
|
|
802
817
|
operatorComponentProps: {
|
|
803
818
|
use: 'operatorComponentProps',
|