@nocobase/client-v2 2.4.0-alpha.11 → 2.4.0-alpha.12
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/flow/models/actions/LinkActionUtils.d.ts +1 -0
- package/es/index.mjs +3 -3
- package/lib/index.js +25 -25
- package/package.json +7 -7
- package/src/flow/models/actions/LinkActionModel.tsx +11 -9
- package/src/flow/models/actions/LinkActionUtils.ts +4 -2
- package/src/flow/models/actions/__tests__/LinkActionModel.test.ts +14 -0
- package/src/flow/models/fields/InputFieldModel.tsx +1 -1
- package/src/flow/models/fields/__tests__/InputFieldModel.test.tsx +16 -0
- package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +1 -0
- package/src/flow/models/fields/mobile-components/__tests__/MobileSelect.test.tsx +20 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/client-v2",
|
|
3
|
-
"version": "2.4.0-alpha.
|
|
3
|
+
"version": "2.4.0-alpha.12",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "es/index.mjs",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"@formily/antd-v5": "1.2.3",
|
|
28
28
|
"@formily/react": "^2.2.27",
|
|
29
29
|
"@formily/shared": "^2.2.27",
|
|
30
|
-
"@nocobase/evaluators": "2.4.0-alpha.
|
|
31
|
-
"@nocobase/flow-engine": "2.4.0-alpha.
|
|
32
|
-
"@nocobase/sdk": "2.4.0-alpha.
|
|
33
|
-
"@nocobase/shared": "2.4.0-alpha.
|
|
34
|
-
"@nocobase/utils": "2.4.0-alpha.
|
|
30
|
+
"@nocobase/evaluators": "2.4.0-alpha.12",
|
|
31
|
+
"@nocobase/flow-engine": "2.4.0-alpha.12",
|
|
32
|
+
"@nocobase/sdk": "2.4.0-alpha.12",
|
|
33
|
+
"@nocobase/shared": "2.4.0-alpha.12",
|
|
34
|
+
"@nocobase/utils": "2.4.0-alpha.12",
|
|
35
35
|
"ahooks": "^3.7.2",
|
|
36
36
|
"antd": "5.24.2",
|
|
37
37
|
"antd-style": "3.7.1",
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"react-router-dom": "^6.30.1",
|
|
50
50
|
"zxing-wasm": "^3.1.3"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "de0ec0596d238752ed56bae95600a59395c920ea"
|
|
53
53
|
}
|
|
@@ -46,21 +46,23 @@ LinkActionModel.registerFlow({
|
|
|
46
46
|
|
|
47
47
|
if (link) {
|
|
48
48
|
const isExternalLink = isURL(link);
|
|
49
|
+
// embed 是页面容器,不应销毁;仅弹窗视图在站内同窗口跳转后销毁。
|
|
50
|
+
const shouldDestroyView =
|
|
51
|
+
!!ctx.view &&
|
|
52
|
+
shouldDestroyViewAfterLinkNavigation({
|
|
53
|
+
openInNewWindow,
|
|
54
|
+
isExternalLink,
|
|
55
|
+
viewType: ctx.view.type,
|
|
56
|
+
});
|
|
49
57
|
handleLinkNavigation({
|
|
50
58
|
link,
|
|
51
59
|
openInNewWindow,
|
|
52
60
|
router: ctx.router,
|
|
53
61
|
isExternalLink,
|
|
62
|
+
// 弹窗会被销毁,用 replace 丢弃弹窗路由;页面(含移动端 embed)跳转需保留历史,以便逐级返回。
|
|
63
|
+
replace: shouldDestroyView,
|
|
54
64
|
});
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
ctx.view &&
|
|
58
|
-
shouldDestroyViewAfterLinkNavigation({
|
|
59
|
-
openInNewWindow,
|
|
60
|
-
isExternalLink,
|
|
61
|
-
viewType: ctx.view.type,
|
|
62
|
-
})
|
|
63
|
-
) {
|
|
65
|
+
if (shouldDestroyView) {
|
|
64
66
|
ctx.view.destroy();
|
|
65
67
|
}
|
|
66
68
|
} else {
|
|
@@ -25,10 +25,11 @@ export function handleLinkNavigation(options: {
|
|
|
25
25
|
openInNewWindow?: boolean;
|
|
26
26
|
router: { navigate: (to: string, options?: { replace?: boolean }) => void };
|
|
27
27
|
isExternalLink: boolean;
|
|
28
|
+
replace?: boolean;
|
|
28
29
|
setLocationHref?: (url: string) => void;
|
|
29
30
|
openWindow?: (url?: string, target?: string) => Window | null;
|
|
30
31
|
}) {
|
|
31
|
-
const { link, openInNewWindow, router, isExternalLink } = options;
|
|
32
|
+
const { link, openInNewWindow, router, isExternalLink, replace = false } = options;
|
|
32
33
|
const setLocationHref = options.setLocationHref ?? ((url: string) => (window.location.href = url));
|
|
33
34
|
const openWindow = options.openWindow ?? ((url?: string, target?: string) => window.open(url, target));
|
|
34
35
|
|
|
@@ -44,7 +45,8 @@ export function handleLinkNavigation(options: {
|
|
|
44
45
|
|
|
45
46
|
// 该辅助方法仅负责导航,是否关闭弹窗由调用方按场景决定;
|
|
46
47
|
// 在弹窗上下文中,错误的关闭时机会把新路由回滚为原页面。
|
|
47
|
-
|
|
48
|
+
// 默认 push 新的历史记录,保证浏览器/手机右滑返回能逐级回退;仅在需要丢弃当前弹窗路由时由调用方传 replace。
|
|
49
|
+
router.navigate(link, { replace });
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
/**
|
|
@@ -22,6 +22,20 @@ describe('handleLinkNavigation', () => {
|
|
|
22
22
|
isExternalLink: false,
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
+
expect(navigate).toHaveBeenCalledWith('/target-page', { replace: false });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should replace history entry when caller requests replace', () => {
|
|
29
|
+
const navigate = vi.fn();
|
|
30
|
+
|
|
31
|
+
handleLinkNavigation({
|
|
32
|
+
link: '/target-page',
|
|
33
|
+
openInNewWindow: false,
|
|
34
|
+
router: { navigate },
|
|
35
|
+
isExternalLink: false,
|
|
36
|
+
replace: true,
|
|
37
|
+
});
|
|
38
|
+
|
|
25
39
|
expect(navigate).toHaveBeenCalledWith('/target-page', { replace: true });
|
|
26
40
|
});
|
|
27
41
|
|
|
@@ -58,7 +58,7 @@ export class InputFieldModel extends FieldModel {
|
|
|
58
58
|
return <ScanInput {...this.props} />;
|
|
59
59
|
}
|
|
60
60
|
const { enableScan, disableManualInput, ...inputProps } = this.props;
|
|
61
|
-
return <IMESafeInput {...inputProps} />;
|
|
61
|
+
return <IMESafeInput {...inputProps} style={{ verticalAlign: 'top', ...inputProps.style }} />;
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -27,6 +27,22 @@ function createInputFieldModel(props?: Record<string, unknown>) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
describe('InputFieldModel', () => {
|
|
30
|
+
it('aligns plain inputs with the top of other filter form controls', () => {
|
|
31
|
+
const model = createInputFieldModel();
|
|
32
|
+
|
|
33
|
+
render(<>{model.render()}</>);
|
|
34
|
+
|
|
35
|
+
expect(screen.getByRole('textbox')).toHaveStyle({ verticalAlign: 'top' });
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('preserves explicitly configured input styles', () => {
|
|
39
|
+
const model = createInputFieldModel({ style: { verticalAlign: 'middle', width: 200 } });
|
|
40
|
+
|
|
41
|
+
render(<>{model.render()}</>);
|
|
42
|
+
|
|
43
|
+
expect(screen.getByRole('textbox')).toHaveStyle({ verticalAlign: 'middle', width: '200px' });
|
|
44
|
+
});
|
|
45
|
+
|
|
30
46
|
it('renders the normal input when scan input is disabled', () => {
|
|
31
47
|
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
32
48
|
const model = createInputFieldModel({ disableManualInput: true, enableScan: false });
|
|
@@ -388,6 +388,26 @@ describe('MobileLazySelect', () => {
|
|
|
388
388
|
resetMockState();
|
|
389
389
|
});
|
|
390
390
|
|
|
391
|
+
it.each([false, true])('updates the disabled trigger state in %s multiple mode', (multiple) => {
|
|
392
|
+
const onDropdownVisibleChange = vi.fn();
|
|
393
|
+
const { rerender } = renderMobileLazySelect({ multiple, onDropdownVisibleChange });
|
|
394
|
+
|
|
395
|
+
rerender({ disabled: true });
|
|
396
|
+
|
|
397
|
+
expect(mockState.selectProps?.disabled).toBe(true);
|
|
398
|
+
act(() => {
|
|
399
|
+
mockState.selectProps?.onClick?.();
|
|
400
|
+
});
|
|
401
|
+
expect(screen.queryByTestId('popup')).not.toBeInTheDocument();
|
|
402
|
+
expect(onDropdownVisibleChange).not.toHaveBeenCalled();
|
|
403
|
+
|
|
404
|
+
rerender({ disabled: false });
|
|
405
|
+
|
|
406
|
+
expect(mockState.selectProps?.disabled).toBe(false);
|
|
407
|
+
openLazyPopup();
|
|
408
|
+
expect(onDropdownVisibleChange).toHaveBeenCalledWith(true);
|
|
409
|
+
});
|
|
410
|
+
|
|
391
411
|
it('renders a translated cancel action after searching', () => {
|
|
392
412
|
renderMobileLazySelect();
|
|
393
413
|
|