@nocobase/client-v2 2.1.0-alpha.30 → 2.1.0-alpha.32
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/components/form/JsonTextArea.d.ts +18 -0
- package/es/components/index.d.ts +1 -0
- package/es/flow/actions/dateRangeLimit.d.ts +9 -0
- package/es/flow/actions/index.d.ts +1 -0
- package/es/flow/actions/linkageRulesFormValueRefresh.d.ts +10 -0
- package/es/flow/index.d.ts +1 -0
- package/es/flow/models/actions/AssociateActionModel.d.ts +19 -0
- package/es/flow/models/actions/AssociationActionUtils.d.ts +17 -0
- package/es/flow/models/actions/DisassociateActionModel.d.ts +16 -0
- package/es/flow/models/actions/index.d.ts +3 -0
- package/es/flow/models/base/GridModel.d.ts +3 -1
- package/es/flow/models/base/PageModel/PageModel.d.ts +4 -0
- package/es/flow/models/base/PageModel/RootPageModel.d.ts +9 -0
- package/es/flow/models/blocks/filter-form/FilterFormGridModel.d.ts +15 -6
- package/es/flow/models/blocks/form/value-runtime/runtime.d.ts +7 -0
- package/es/flow/models/blocks/shared/filterOperators.d.ts +9 -0
- package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.d.ts +3 -0
- package/es/flow/models/fields/AssociationFieldModel/recordSelectSettingsUtils.d.ts +9 -0
- package/es/flow/models/fields/DateTimeFieldModel/dateLimit.d.ts +20 -0
- package/es/flow/models/fields/JSEditableFieldModel.d.ts +4 -0
- package/es/flow-compat/data.d.ts +9 -2
- package/es/flow-compat/index.d.ts +1 -1
- package/es/index.d.ts +1 -0
- package/es/index.mjs +100 -93
- package/lib/index.js +101 -94
- package/package.json +6 -5
- package/src/BaseApplication.tsx +1 -1
- package/src/__tests__/app.test.tsx +23 -6
- package/src/__tests__/globalDeps.test.ts +5 -0
- package/src/components/form/JsonTextArea.tsx +129 -0
- package/src/components/index.ts +1 -0
- package/src/flow/actions/__tests__/fieldLinkageRules.scopeDepth.test.ts +478 -0
- package/src/flow/actions/__tests__/linkageRules.formValueDrivenRefresh.test.ts +438 -0
- package/src/flow/actions/__tests__/linkageRulesRefresh.test.ts +42 -0
- package/src/flow/actions/__tests__/pattern.test.ts +190 -0
- package/src/flow/actions/dateRangeLimit.tsx +66 -0
- package/src/flow/actions/index.ts +1 -0
- package/src/flow/actions/linkageRules.tsx +119 -14
- package/src/flow/actions/linkageRulesFormValueRefresh.ts +492 -0
- package/src/flow/actions/linkageRulesRefresh.tsx +4 -2
- package/src/flow/actions/openView.tsx +2 -1
- package/src/flow/actions/pattern.tsx +25 -2
- package/src/flow/actions/titleField.tsx +8 -3
- package/src/flow/admin-shell/AdminLayoutRouteCoordinator.ts +7 -1
- package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +117 -0
- package/src/flow/components/FieldAssignValueInput.tsx +1 -0
- package/src/flow/components/filter/LinkageFilterItem.tsx +6 -5
- package/src/flow/components/filter/VariableFilterItem.tsx +14 -13
- package/src/flow/components/filter/__tests__/LinkageFilterItem.test.tsx +33 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.test.tsx +48 -5
- package/src/flow/index.ts +1 -0
- package/src/flow/internal/utils/__tests__/titleFieldQuickSync.test.ts +1 -0
- package/src/flow/internal/utils/titleFieldQuickSync.ts +2 -2
- package/src/flow/models/actions/AssociateActionModel.tsx +196 -0
- package/src/flow/models/actions/AssociationActionUtils.ts +90 -0
- package/src/flow/models/actions/DisassociateActionModel.tsx +57 -0
- package/src/flow/models/actions/FilterActionModel.tsx +17 -9
- package/src/flow/models/actions/__tests__/AssociationActionModel.test.ts +250 -0
- package/src/flow/models/actions/index.ts +3 -0
- package/src/flow/models/base/GridModel.tsx +21 -1
- package/src/flow/models/base/PageModel/PageModel.tsx +15 -3
- package/src/flow/models/base/PageModel/RootPageModel.tsx +37 -2
- package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +73 -0
- package/src/flow/models/base/PageModel/__tests__/RootPageModel.test.ts +116 -0
- package/src/flow/models/base/__tests__/GridModel.dragSnapshotContainer.test.ts +98 -0
- package/src/flow/models/blocks/details/DetailsItemModel.tsx +3 -0
- package/src/flow/models/blocks/filter-form/FilterFormGridModel.tsx +200 -36
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormGridModel.toggleFormFieldsCollapse.test.ts +270 -1
- package/src/flow/models/blocks/filter-form/__tests__/customFieldOperators.test.tsx +23 -0
- package/src/flow/models/blocks/filter-form/customFieldOperators.ts +12 -1
- package/src/flow/models/blocks/filter-form/fields/FieldComponentProps.tsx +22 -8
- package/src/flow/models/blocks/filter-form/fields/__tests__/FilterFormCustomFieldModel.recordSelect.test.tsx +18 -0
- package/src/flow/models/blocks/filter-manager/FilterManager.ts +51 -1
- package/src/flow/models/blocks/filter-manager/__tests__/FilterManager.test.ts +75 -0
- package/src/flow/models/blocks/form/FormItemModel.tsx +48 -28
- package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +167 -1
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +103 -11
- package/src/flow/models/blocks/shared/filterOperators.ts +14 -0
- package/src/flow/models/blocks/table/TableBlockModel.tsx +19 -3
- package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +5 -1
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +48 -8
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +47 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableColumnModel.rowRecord.test.ts +42 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableField.refresh.test.tsx +122 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +2 -0
- package/src/flow/models/fields/AssociationFieldModel/recordSelectSettingsUtils.ts +20 -0
- package/src/flow/models/fields/ClickableFieldModel.tsx +21 -9
- package/src/flow/models/fields/DateTimeFieldModel/DateOnlyFieldModel.tsx +9 -0
- package/src/flow/models/fields/DateTimeFieldModel/DateTimeFieldModel.tsx +4 -0
- package/src/flow/models/fields/DateTimeFieldModel/DateTimeNoTzFieldModel.tsx +9 -0
- package/src/flow/models/fields/DateTimeFieldModel/DateTimeTzFieldModel.tsx +9 -0
- package/src/flow/models/fields/DateTimeFieldModel/__tests__/DateTimeNoTzFieldModel.dateLimit.test.tsx +242 -0
- package/src/flow/models/fields/DateTimeFieldModel/dateLimit.ts +152 -0
- package/src/flow/models/fields/DividerItemModel.tsx +30 -15
- package/src/flow/models/fields/JSEditableFieldModel.tsx +110 -14
- package/src/flow/models/fields/__tests__/ClickableFieldModel.test.ts +87 -0
- package/src/flow/models/fields/__tests__/JSEditableFieldModel.test.tsx +210 -0
- package/src/flow/models/fields/mobile-components/MobileSelect.tsx +11 -3
- package/src/flow/models/fields/mobile-components/__tests__/MobileSelect.test.tsx +235 -0
- package/src/flow-compat/data.ts +25 -3
- package/src/flow-compat/index.ts +7 -1
- package/src/index.ts +1 -0
- package/src/utils/globalDeps.ts +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/client-v2",
|
|
3
|
-
"version": "2.1.0-alpha.
|
|
3
|
+
"version": "2.1.0-alpha.32",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "es/index.mjs",
|
|
@@ -24,17 +24,18 @@
|
|
|
24
24
|
"@formily/antd-v5": "1.2.3",
|
|
25
25
|
"@formily/react": "^2.2.27",
|
|
26
26
|
"@formily/shared": "^2.2.27",
|
|
27
|
-
"@nocobase/flow-engine": "2.1.0-alpha.
|
|
28
|
-
"@nocobase/sdk": "2.1.0-alpha.
|
|
29
|
-
"@nocobase/shared": "2.1.0-alpha.
|
|
27
|
+
"@nocobase/flow-engine": "2.1.0-alpha.32",
|
|
28
|
+
"@nocobase/sdk": "2.1.0-alpha.32",
|
|
29
|
+
"@nocobase/shared": "2.1.0-alpha.32",
|
|
30
30
|
"ahooks": "^3.7.2",
|
|
31
31
|
"antd": "5.24.2",
|
|
32
32
|
"classnames": "^2.3.1",
|
|
33
33
|
"dayjs": "^1.11.10",
|
|
34
34
|
"i18next": "^22.4.9",
|
|
35
|
+
"json5": "^2.2.3",
|
|
35
36
|
"lodash": "4.17.21",
|
|
36
37
|
"react-i18next": "^11.15.1",
|
|
37
38
|
"react-router-dom": "^6.30.1"
|
|
38
39
|
},
|
|
39
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "1ba7d717e156651db17c615f9b9c48edd669d19b"
|
|
40
41
|
}
|
package/src/BaseApplication.tsx
CHANGED
|
@@ -72,29 +72,46 @@ describe('app', () => {
|
|
|
72
72
|
});
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
it('should mount the app
|
|
75
|
+
it('should mount the base app with blank fallback route', async () => {
|
|
76
76
|
const app = createMockClient();
|
|
77
77
|
const element = document.createElement('div');
|
|
78
78
|
act(() => {
|
|
79
79
|
app.mount(element);
|
|
80
80
|
});
|
|
81
|
-
await waitFor(() => expect(element.
|
|
81
|
+
await waitFor(() => expect(element.querySelector('.ant-app')).not.toBeNull());
|
|
82
|
+
expect(element.textContent).toBe('');
|
|
82
83
|
});
|
|
83
84
|
|
|
84
|
-
it('should render
|
|
85
|
+
it('should render blank fallback route by default', async () => {
|
|
85
86
|
const app = createMockClient();
|
|
86
87
|
await renderApp(app);
|
|
87
|
-
expect(screen.
|
|
88
|
+
expect(screen.queryByText('Sorry, the page you visited does not exist.')).not.toBeInTheDocument();
|
|
88
89
|
});
|
|
89
90
|
|
|
90
|
-
it('should render custom "Not Found" component', async () => {
|
|
91
|
+
it('should not render custom "Not Found" component before builtin routes are added', async () => {
|
|
91
92
|
class PluginHelloClient extends Plugin {}
|
|
92
93
|
const app = createMockClient({
|
|
93
94
|
plugins: [PluginHelloClient],
|
|
94
95
|
components: { AppNotFound: () => <div>Not Found2</div> },
|
|
95
96
|
});
|
|
96
97
|
await renderApp(app);
|
|
97
|
-
expect(screen.
|
|
98
|
+
expect(screen.queryByText('Not Found2')).not.toBeInTheDocument();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should render builtin "Not Found" view after builtin routes are added', async () => {
|
|
102
|
+
const app = createMockClient({
|
|
103
|
+
plugins: [NocoBaseBuildInPlugin as any],
|
|
104
|
+
router: { type: 'memory', initialEntries: ['/missing'] },
|
|
105
|
+
});
|
|
106
|
+
app.apiMock.onGet('app:getLang').reply(200, {
|
|
107
|
+
data: {
|
|
108
|
+
lang: 'en-US',
|
|
109
|
+
resources: { client: {} },
|
|
110
|
+
cron: {},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
await renderApp(app);
|
|
114
|
+
expect(screen.getByText('Sorry, the page you visited does not exist.')).toBeInTheDocument();
|
|
98
115
|
});
|
|
99
116
|
|
|
100
117
|
it('should support app provider functionality', async () => {
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
import { defineGlobalDeps } from '../utils/globalDeps';
|
|
11
11
|
|
|
12
|
+
vi.mock('../index', () => ({}));
|
|
13
|
+
|
|
12
14
|
describe('client-v2 defineGlobalDeps', () => {
|
|
13
15
|
it('should register shared AMD dependencies for remote plugins', () => {
|
|
14
16
|
const define = vi.fn();
|
|
@@ -24,5 +26,8 @@ describe('client-v2 defineGlobalDeps', () => {
|
|
|
24
26
|
expect(define).toHaveBeenCalledWith('@nocobase/client-v2', expect.any(Function));
|
|
25
27
|
expect(define).toHaveBeenCalledWith('@nocobase/flow-engine', expect.any(Function));
|
|
26
28
|
expect(define).toHaveBeenCalledWith('ahooks', expect.any(Function));
|
|
29
|
+
expect(define).toHaveBeenCalledWith('dayjs', expect.any(Function));
|
|
30
|
+
expect(define).toHaveBeenCalledWith('lodash', expect.any(Function));
|
|
31
|
+
expect(define).toHaveBeenCalledWith('@emotion/css', expect.any(Function));
|
|
27
32
|
});
|
|
28
33
|
});
|
|
@@ -0,0 +1,129 @@
|
|
|
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 { css, cx } from '@emotion/css';
|
|
11
|
+
import { Input, Typography } from 'antd';
|
|
12
|
+
import type { TextAreaProps } from 'antd/es/input';
|
|
13
|
+
import JSON5 from 'json5';
|
|
14
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
15
|
+
|
|
16
|
+
export interface JsonTextAreaProps extends Omit<TextAreaProps, 'value' | 'onChange'> {
|
|
17
|
+
value?: unknown;
|
|
18
|
+
onChange?: (value: unknown) => void;
|
|
19
|
+
space?: number;
|
|
20
|
+
json5?: boolean;
|
|
21
|
+
showError?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const jsonTextAreaClassName = css`
|
|
25
|
+
font-size: 80%;
|
|
26
|
+
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
function stringifyJsonValue(value: unknown, json: typeof JSON | typeof JSON5, space: number) {
|
|
30
|
+
if (value == null) {
|
|
31
|
+
return '';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (typeof value === 'string') {
|
|
35
|
+
try {
|
|
36
|
+
json.parse(value);
|
|
37
|
+
return value;
|
|
38
|
+
} catch {
|
|
39
|
+
return json.stringify(value, undefined, space);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return json.stringify(value, undefined, space);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const JsonTextArea = React.memo((props: JsonTextAreaProps) => {
|
|
47
|
+
const {
|
|
48
|
+
value,
|
|
49
|
+
onChange,
|
|
50
|
+
space = 2,
|
|
51
|
+
json5 = false,
|
|
52
|
+
showError = true,
|
|
53
|
+
className,
|
|
54
|
+
status,
|
|
55
|
+
onBlur,
|
|
56
|
+
...textAreaProps
|
|
57
|
+
} = props;
|
|
58
|
+
const json = json5 ? JSON5 : JSON;
|
|
59
|
+
const [text, setText] = useState(() => stringifyJsonValue(value, json, space));
|
|
60
|
+
const [error, setError] = useState<string>();
|
|
61
|
+
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
setText(stringifyJsonValue(value, json, space));
|
|
64
|
+
}, [json, space, value]);
|
|
65
|
+
|
|
66
|
+
const parseText = useCallback(
|
|
67
|
+
(nextText: string) => {
|
|
68
|
+
if (nextText.trim() === '') {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return json.parse(nextText);
|
|
73
|
+
},
|
|
74
|
+
[json],
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const handleChange = useCallback(
|
|
78
|
+
(event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
79
|
+
const nextText = event.target.value;
|
|
80
|
+
setText(nextText);
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
parseText(nextText);
|
|
84
|
+
setError(undefined);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
[parseText],
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const handleBlur = useCallback(
|
|
93
|
+
(event: React.FocusEvent<HTMLTextAreaElement>) => {
|
|
94
|
+
try {
|
|
95
|
+
const parsed = parseText(event.target.value);
|
|
96
|
+
setError(undefined);
|
|
97
|
+
setText(parsed == null ? '' : json.stringify(parsed, undefined, space));
|
|
98
|
+
onChange?.(parsed);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
onBlur?.(event);
|
|
104
|
+
},
|
|
105
|
+
[json, onBlur, onChange, parseText, space],
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const mergedStatus = useMemo(() => status || (error ? 'error' : undefined), [error, status]);
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<>
|
|
112
|
+
<Input.TextArea
|
|
113
|
+
{...textAreaProps}
|
|
114
|
+
value={text}
|
|
115
|
+
onChange={handleChange}
|
|
116
|
+
onBlur={handleBlur}
|
|
117
|
+
status={mergedStatus}
|
|
118
|
+
className={cx(jsonTextAreaClassName, className)}
|
|
119
|
+
/>
|
|
120
|
+
{showError && error ? (
|
|
121
|
+
<Typography.Text type="danger" style={{ display: 'block', marginTop: 4 }}>
|
|
122
|
+
{error}
|
|
123
|
+
</Typography.Text>
|
|
124
|
+
) : null}
|
|
125
|
+
</>
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
JsonTextArea.displayName = 'JsonTextArea';
|