@nocobase/client-v2 2.1.0-alpha.45 → 2.1.0-alpha.47
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/authRedirect.d.ts +12 -0
- package/es/collection-manager/filter-operators/index.d.ts +1 -0
- package/es/components/form/TypedVariableInput.d.ts +75 -0
- package/es/components/form/filter/CollectionFilterItem.d.ts +5 -1
- package/es/components/form/filter/FilterValueInput.d.ts +5 -0
- package/es/components/form/index.d.ts +1 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +1 -0
- package/es/flow/components/ConditionBuilder.d.ts +1 -0
- package/es/flow/components/FieldAssignRulesEditor.d.ts +3 -1
- package/es/flow/components/FieldAssignValueInput.d.ts +1 -0
- package/es/flow/components/fieldAssignOptions.d.ts +10 -0
- package/es/flow/components/filter/LinkageFilterItem.d.ts +1 -0
- package/es/flow/components/filter/VariableFilterItem.d.ts +1 -0
- package/es/flow/components/filter/metaTreeAssociationDepth.d.ts +13 -0
- package/es/flow/internal/utils/operatorSchemaHelper.d.ts +26 -3
- package/es/flow/models/base/AssociationFieldGroupModel.d.ts +2 -33
- package/es/flow/models/blocks/assign-form/assignFieldValuesFlow.d.ts +8 -0
- package/es/flow/models/blocks/filter-manager/utils.d.ts +23 -1
- package/es/flow/models/blocks/table/TableColumnModel.d.ts +2 -0
- package/es/index.mjs +106 -106
- package/lib/index.js +106 -106
- package/package.json +7 -7
- package/src/__tests__/browserChecker.test.ts +103 -0
- package/src/__tests__/dataSourceRuntime.test.tsx +22 -1
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +5 -0
- package/src/authRedirect.ts +43 -0
- package/src/collection-field-interface/CollectionFieldInterface.ts +14 -7
- package/src/collection-manager/filter-operators/index.ts +29 -2
- package/src/components/README.md +48 -0
- package/src/components/README.zh-CN.md +48 -0
- package/src/components/form/TypedVariableInput.tsx +441 -0
- package/src/components/form/__tests__/TypedVariableInput.test.tsx +152 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +10 -2
- package/src/components/form/filter/FilterValueInput.tsx +27 -2
- package/src/components/form/filter/__tests__/FilterValueInput.test.tsx +39 -0
- package/src/components/form/index.tsx +1 -0
- package/src/flow/__tests__/FlowRoute.test.tsx +8 -1
- package/src/flow/actions/__tests__/linkageRules.hiddenSync.restore.test.ts +100 -0
- package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +369 -2
- package/src/flow/actions/__tests__/linkageRulesRefresh.test.ts +23 -1
- package/src/flow/actions/dataScope.tsx +8 -1
- package/src/flow/actions/linkageRules.tsx +61 -5
- package/src/flow/actions/linkageRulesRefresh.tsx +2 -3
- package/src/flow/actions/setTargetDataScope.tsx +1 -1
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +15 -1
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +75 -1
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +11 -0
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +2 -4
- package/src/flow/common/Markdown/Edit.tsx +32 -4
- package/src/flow/components/ConditionBuilder.tsx +12 -2
- package/src/flow/components/DefaultValue.tsx +14 -8
- package/src/flow/components/FieldAssignRulesEditor.tsx +37 -46
- package/src/flow/components/FieldAssignValueInput.tsx +14 -14
- package/src/flow/components/__tests__/FieldAssignRulesEditor.test.tsx +112 -1
- package/src/flow/components/__tests__/fieldAssignOptions.test.ts +71 -1
- package/src/flow/components/code-editor/__tests__/runjsCompletions.test.ts +272 -27
- package/src/flow/components/code-editor/runjsCompletions.ts +490 -9
- package/src/flow/components/fieldAssignOptions.ts +23 -6
- package/src/flow/components/filter/LinkageFilterItem.tsx +26 -12
- package/src/flow/components/filter/VariableFilterItem.tsx +32 -13
- package/src/flow/components/filter/__tests__/fieldsToOptions.test.ts +48 -0
- package/src/flow/components/filter/__tests__/metaTreeAssociationDepth.test.ts +60 -0
- package/src/flow/components/filter/fieldsToOptions.ts +9 -4
- package/src/flow/components/filter/metaTreeAssociationDepth.ts +69 -0
- package/src/flow/internal/utils/operatorSchemaHelper.ts +112 -5
- package/src/flow/models/actions/FilterActionModel.tsx +15 -3
- package/src/flow/models/actions/__tests__/AssignFormRefill.test.ts +90 -0
- package/src/flow/models/base/AssociationFieldGroupModel.tsx +20 -3
- package/src/flow/models/base/GridModel.tsx +1 -1
- package/src/flow/models/base/PageModel/ChildPageModel.tsx +5 -1
- package/src/flow/models/base/PageModel/__tests__/ChildPageModel.test.ts +12 -0
- package/src/flow/models/base/__tests__/AssociationFieldGroupModel.test.ts +86 -0
- package/src/flow/models/base/__tests__/GridModel.render.test.tsx +53 -0
- package/src/flow/models/blocks/assign-form/AssignFormGridModel.tsx +12 -3
- package/src/flow/models/blocks/assign-form/AssignFormItemModel.tsx +14 -4
- package/src/flow/models/blocks/assign-form/__tests__/assignFieldValuesFlow.editor.test.tsx +216 -0
- package/src/flow/models/blocks/assign-form/assignFieldValuesFlow.tsx +142 -40
- package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +14 -12
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts +6 -1
- package/src/flow/models/blocks/filter-manager/__tests__/getDefaultOperator.test.ts +35 -1
- package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/customizeFilterRender.test.tsx +148 -0
- package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/defaultOperator.test.tsx +85 -0
- package/src/flow/models/blocks/filter-manager/flow-actions/connectFields.tsx +48 -6
- package/src/flow/models/blocks/filter-manager/flow-actions/customizeFilterRender.tsx +14 -44
- package/src/flow/models/blocks/filter-manager/flow-actions/defaultOperator.tsx +3 -5
- package/src/flow/models/blocks/filter-manager/flow-actions/operatorComponentProps.tsx +2 -12
- package/src/flow/models/blocks/filter-manager/utils.ts +143 -4
- package/src/flow/models/blocks/form/FormAssociationItemModel.tsx +9 -0
- package/src/flow/models/blocks/form/FormItemModel.tsx +9 -0
- package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +17 -0
- package/src/flow/models/blocks/form/__tests__/FormItemModel.defineChildren.test.ts +27 -2
- package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +29 -0
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +5 -1
- package/src/flow/models/blocks/table/TableColumnModel.tsx +15 -5
- package/src/flow/models/blocks/table/TableCustomColumnModel.tsx +2 -2
- package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +18 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +6 -7
- package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +5 -3
- package/src/flow/models/fields/mobile-components/__tests__/MobileSelect.test.tsx +70 -0
|
@@ -12,6 +12,24 @@ import { describe, expect, it, vi } from 'vitest';
|
|
|
12
12
|
import { TableColumnModel } from '../TableColumnModel';
|
|
13
13
|
|
|
14
14
|
describe('TableColumnModel sorter settings', () => {
|
|
15
|
+
it('clamps custom column width to the minimum value', () => {
|
|
16
|
+
const engine = new FlowEngine();
|
|
17
|
+
const model = new TableColumnModel({ uid: 'table-column-min-width', flowEngine: engine } as any);
|
|
18
|
+
const widthStep = model.getFlow('tableColumnSettings')?.steps?.width as any;
|
|
19
|
+
const setProps = vi.fn();
|
|
20
|
+
|
|
21
|
+
widthStep.handler(
|
|
22
|
+
{
|
|
23
|
+
model: {
|
|
24
|
+
setProps,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{ width: 0 },
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
expect(setProps).toHaveBeenCalledWith('width', 10);
|
|
31
|
+
});
|
|
32
|
+
|
|
15
33
|
it('hides quick edit setting for relation path columns added from association groups', async () => {
|
|
16
34
|
const engine = new FlowEngine();
|
|
17
35
|
const model = new TableColumnModel({ uid: 'table-column-relation-path-quick-edit', flowEngine: engine } as any);
|
package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx
CHANGED
|
@@ -33,7 +33,7 @@ import React, { useRef, useMemo, useEffect } from 'react';
|
|
|
33
33
|
import { SubTableFieldModel } from '.';
|
|
34
34
|
import { FieldModel } from '../../../base/FieldModel';
|
|
35
35
|
import { DetailsItemModel } from '../../../blocks/details/DetailsItemModel';
|
|
36
|
-
import { FieldDeletePlaceholder, CustomWidth } from '../../../blocks/table/TableColumnModel';
|
|
36
|
+
import { FieldDeletePlaceholder, CustomWidth, normalizeTableColumnWidth } from '../../../blocks/table/TableColumnModel';
|
|
37
37
|
import { buildDynamicNamePath } from '../../../blocks/form/dynamicNamePath';
|
|
38
38
|
import { getSubTableRowIdentity } from './rowIdentity';
|
|
39
39
|
import { getFieldBindingUse, rebuildFieldSubModel } from '../../../../internal/utils/rebuildFieldSubModel';
|
|
@@ -67,7 +67,7 @@ export function FieldWithoutPermissionPlaceholder({ targetModel }) {
|
|
|
67
67
|
const dataSourcePrefix = `${t(dataSource.displayName || dataSource.key)} > `;
|
|
68
68
|
const collectionPrefix = collection ? `${t(collection.title) || collection.name || collection.tableName} > ` : '';
|
|
69
69
|
return `${dataSourcePrefix}${collectionPrefix}${name}`;
|
|
70
|
-
}, []);
|
|
70
|
+
}, [collection, dataSource.displayName, dataSource.key, name, t]);
|
|
71
71
|
const { actionName } = fieldModel.forbidden || {};
|
|
72
72
|
const messageValue = useMemo(() => {
|
|
73
73
|
return t(
|
|
@@ -77,7 +77,7 @@ export function FieldWithoutPermissionPlaceholder({ targetModel }) {
|
|
|
77
77
|
actionName: t(capitalize(actionName)),
|
|
78
78
|
},
|
|
79
79
|
).replaceAll('>', '>');
|
|
80
|
-
}, [nameValue, t]);
|
|
80
|
+
}, [actionName, nameValue, t]);
|
|
81
81
|
return (
|
|
82
82
|
<Tooltip title={messageValue}>
|
|
83
83
|
<LockOutlined style={{ opacity: '0.3' }} />
|
|
@@ -100,10 +100,9 @@ const LargeFieldEdit = observer(({ model, params: { fieldPath, index }, defaultV
|
|
|
100
100
|
const handleChange = useMemo(
|
|
101
101
|
() =>
|
|
102
102
|
debounce((val) => {
|
|
103
|
-
if (props.onChange) props.onChange(val);
|
|
104
103
|
if (onChange) onChange(val);
|
|
105
104
|
}, 200),
|
|
106
|
-
[
|
|
105
|
+
[onChange],
|
|
107
106
|
);
|
|
108
107
|
|
|
109
108
|
return <FieldModelRenderer model={model} {...rest} onChange={handleChange} />;
|
|
@@ -149,7 +148,7 @@ const LargeFieldEdit = observer(({ model, params: { fieldPath, index }, defaultV
|
|
|
149
148
|
</Space>
|
|
150
149
|
);
|
|
151
150
|
}
|
|
152
|
-
}, [collectionField.interface, defaultValue, fieldModel]);
|
|
151
|
+
}, [collectionField.interface, defaultValue, disabled, fieldModel]);
|
|
153
152
|
return (
|
|
154
153
|
<div
|
|
155
154
|
ref={ref}
|
|
@@ -830,7 +829,7 @@ SubTableColumnModel.registerFlow({
|
|
|
830
829
|
width: 200,
|
|
831
830
|
},
|
|
832
831
|
handler(ctx, params) {
|
|
833
|
-
ctx.model.setProps('width', params.width);
|
|
832
|
+
ctx.model.setProps('width', normalizeTableColumnWidth(params.width));
|
|
834
833
|
},
|
|
835
834
|
},
|
|
836
835
|
aclCheck: {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { useFlowModelContext } from '@nocobase/flow-engine';
|
|
11
11
|
import { Select } from 'antd';
|
|
12
12
|
import type { CSSProperties } from 'react';
|
|
13
|
-
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
13
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
14
14
|
import { Button, CheckList, Popup, SearchBar, SpinLoading } from 'antd-mobile';
|
|
15
15
|
import { css } from '@emotion/css';
|
|
16
16
|
import {
|
|
@@ -51,7 +51,7 @@ function deriveRecordsFromValue(
|
|
|
51
51
|
) {
|
|
52
52
|
if (isMultiple) {
|
|
53
53
|
if (Array.isArray(value)) {
|
|
54
|
-
return (value.filter(
|
|
54
|
+
return (value.filter((item) => item !== null && item !== undefined) as any[]).map((item) => {
|
|
55
55
|
if (valueMode === 'value') {
|
|
56
56
|
return optionMap.get(item) ?? { [valueKey]: item };
|
|
57
57
|
}
|
|
@@ -113,11 +113,13 @@ export function MobileLazySelect(props: Readonly<LazySelectProps>) {
|
|
|
113
113
|
);
|
|
114
114
|
|
|
115
115
|
const [selectedRecords, setSelectedRecords] = useState<AssociationOption[]>(() => derivedRecords);
|
|
116
|
+
const wasVisibleRef = useRef(visible);
|
|
116
117
|
|
|
117
118
|
useEffect(() => {
|
|
118
|
-
if (visible) {
|
|
119
|
+
if (visible && !wasVisibleRef.current) {
|
|
119
120
|
setSelectedRecords(derivedRecords);
|
|
120
121
|
}
|
|
122
|
+
wasVisibleRef.current = visible;
|
|
121
123
|
}, [derivedRecords, visible]);
|
|
122
124
|
|
|
123
125
|
useEffect(() => {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import React from 'react';
|
|
11
11
|
import { beforeEach, describe, it, expect, vi } from 'vitest';
|
|
12
12
|
import { act, fireEvent, render, screen } from '@nocobase/test/client';
|
|
13
|
+
import { MobileLazySelect } from '../MobileLazySelect';
|
|
13
14
|
import { MobileSelect } from '../MobileSelect';
|
|
14
15
|
|
|
15
16
|
const DEFAULT_OPTIONS = [
|
|
@@ -17,6 +18,11 @@ const DEFAULT_OPTIONS = [
|
|
|
17
18
|
{ label: 'Option B', value: 'b' },
|
|
18
19
|
];
|
|
19
20
|
|
|
21
|
+
const RELATION_OPTIONS = [
|
|
22
|
+
{ uuid: '05f6a3b4-bfb7-7943-578a-3819e2687a7e' },
|
|
23
|
+
{ uuid: 'c7d99828-a1de-9e70-4c2d-b0139abdf02e' },
|
|
24
|
+
];
|
|
25
|
+
|
|
20
26
|
const mockState = vi.hoisted(() => ({
|
|
21
27
|
selectProps: undefined as any,
|
|
22
28
|
popupProps: undefined as any,
|
|
@@ -44,6 +50,13 @@ function openPopup() {
|
|
|
44
50
|
expect(screen.getByTestId('popup')).toBeInTheDocument();
|
|
45
51
|
}
|
|
46
52
|
|
|
53
|
+
function openLazyPopup() {
|
|
54
|
+
act(() => {
|
|
55
|
+
mockState.selectProps?.onClick?.();
|
|
56
|
+
});
|
|
57
|
+
expect(screen.getByTestId('popup')).toBeInTheDocument();
|
|
58
|
+
}
|
|
59
|
+
|
|
47
60
|
function selectValues(values: string[]) {
|
|
48
61
|
act(() => {
|
|
49
62
|
mockState.checklistProps?.onChange?.(values);
|
|
@@ -73,6 +86,30 @@ function renderMobileSelect(props: Record<string, any> = {}) {
|
|
|
73
86
|
return { onChange, onChangeComplete };
|
|
74
87
|
}
|
|
75
88
|
|
|
89
|
+
function renderMobileLazySelect(props: Record<string, any> = {}) {
|
|
90
|
+
const onChange = props.onChange ?? vi.fn();
|
|
91
|
+
const renderComponent = (nextProps: Record<string, any> = {}) => (
|
|
92
|
+
<MobileLazySelect
|
|
93
|
+
fieldNames={{ label: 'uuid', value: 'uuid' }}
|
|
94
|
+
value={[]}
|
|
95
|
+
multiple
|
|
96
|
+
allowMultiple
|
|
97
|
+
options={RELATION_OPTIONS}
|
|
98
|
+
{...props}
|
|
99
|
+
{...nextProps}
|
|
100
|
+
onChange={onChange}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const result = render(renderComponent());
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
...result,
|
|
108
|
+
onChange,
|
|
109
|
+
rerender: (nextProps: Record<string, any> = {}) => result.rerender(renderComponent(nextProps)),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
76
113
|
vi.mock('@nocobase/flow-engine', async () => {
|
|
77
114
|
const actual = await vi.importActual<any>('@nocobase/flow-engine');
|
|
78
115
|
return {
|
|
@@ -80,6 +117,12 @@ vi.mock('@nocobase/flow-engine', async () => {
|
|
|
80
117
|
useFlowModelContext: () => ({
|
|
81
118
|
t: (value: string) => value,
|
|
82
119
|
}),
|
|
120
|
+
useFlowModel: () => ({
|
|
121
|
+
context: {
|
|
122
|
+
collectionField: {},
|
|
123
|
+
},
|
|
124
|
+
subModels: {},
|
|
125
|
+
}),
|
|
83
126
|
};
|
|
84
127
|
});
|
|
85
128
|
|
|
@@ -240,3 +283,30 @@ describe('MobileSelect in SubForm/SubTable containers', () => {
|
|
|
240
283
|
expect(onCommit).toHaveBeenNthCalledWith(2, ['a', 'b']);
|
|
241
284
|
});
|
|
242
285
|
});
|
|
286
|
+
|
|
287
|
+
describe('MobileLazySelect', () => {
|
|
288
|
+
beforeEach(() => {
|
|
289
|
+
resetMockState();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('keeps pending relation records selected until confirm', () => {
|
|
293
|
+
const { onChange, rerender } = renderMobileLazySelect();
|
|
294
|
+
|
|
295
|
+
openLazyPopup();
|
|
296
|
+
expect(mockState.checklistProps?.value).toEqual([]);
|
|
297
|
+
|
|
298
|
+
selectValues(['c7d99828-a1de-9e70-4c2d-b0139abdf02e']);
|
|
299
|
+
expect(mockState.checklistProps?.value).toEqual(['c7d99828-a1de-9e70-4c2d-b0139abdf02e']);
|
|
300
|
+
|
|
301
|
+
rerender({
|
|
302
|
+
options: RELATION_OPTIONS.map((item) => ({ ...item })),
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
expect(mockState.checklistProps?.value).toEqual(['c7d99828-a1de-9e70-4c2d-b0139abdf02e']);
|
|
306
|
+
|
|
307
|
+
confirmSelection();
|
|
308
|
+
|
|
309
|
+
expect(onChange).toHaveBeenCalledTimes(1);
|
|
310
|
+
expect(onChange).toHaveBeenCalledWith([RELATION_OPTIONS[1]]);
|
|
311
|
+
});
|
|
312
|
+
});
|