diff --git a/packages/core/client/src/schema-component/antd/page/Page.tsx b/packages/core/client/src/schema-component/antd/page/Page.tsx index 28c93b84eef..77df149e1ab 100644 --- a/packages/core/client/src/schema-component/antd/page/Page.tsx +++ b/packages/core/client/src/schema-component/antd/page/Page.tsx @@ -17,7 +17,7 @@ import classNames from 'classnames'; import React, { memo, useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; import { useTranslation } from 'react-i18next'; -import { Outlet, useOutletContext, useParams, useSearchParams } from 'react-router-dom'; +import { NavigateFunction, Outlet, useOutletContext, useParams, useSearchParams } from 'react-router-dom'; import { FormDialog } from '..'; import { useStyles as useAClStyles } from '../../../acl/style'; import { useRequest } from '../../../api-client'; @@ -112,7 +112,7 @@ export const Page = (props) => { }} onChange={(activeKey) => { setLoading(true); - navigate(`/admin/${pageUid}/tabs/${activeKey}`, { replace: true }); + navigateToTab(activeKey, navigate); setTimeout(() => { setLoading(false); }, 50); @@ -319,3 +319,24 @@ const PageContent = memo( }, ); PageContent.displayName = 'PageContent'; + +export function navigateToTab(activeKey: string, navigate: NavigateFunction, pathname = window.location.pathname) { + if (pathname.endsWith('/')) { + pathname = pathname.slice(0, -1); + } + + if (isTabPage(pathname)) { + navigate(`${pathname.replace(/\/tabs\/[^/]+$/, `/tabs/${activeKey}`)}`, { replace: true }); + } else { + navigate(`${pathname}/tabs/${activeKey}`, { replace: true }); + } +} + +export function isTabPage(pathname: string) { + if (pathname.endsWith('/')) { + pathname = pathname.slice(0, -1); + } + + const list = pathname.split('/'); + return list[list.length - 2] === 'tabs'; +} diff --git a/packages/core/client/src/schema-component/antd/page/__tests__/page.test.tsx b/packages/core/client/src/schema-component/antd/page/__tests__/page.test.tsx index 22a338ebaff..1eb0fb60705 100644 --- a/packages/core/client/src/schema-component/antd/page/__tests__/page.test.tsx +++ b/packages/core/client/src/schema-component/antd/page/__tests__/page.test.tsx @@ -7,11 +7,11 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -import { render, screen, waitFor, renderAppOptions, userEvent } from '@nocobase/test/client'; +import { DocumentTitleProvider, Form, FormItem, Grid, IconPicker, Input } from '@nocobase/client'; +import { render, renderAppOptions, screen, userEvent, waitFor } from '@nocobase/test/client'; import React from 'react'; import App1 from '../demos/demo1'; -import { Page } from '../Page'; -import { DocumentTitleProvider, Form, FormItem, Grid, IconPicker, Input } from '@nocobase/client'; +import { isTabPage, navigateToTab, Page } from '../Page'; describe('Page', () => { it('should render correctly', async () => { @@ -159,3 +159,46 @@ describe('Page', () => { }); }); }); + +describe('utils', () => { + it('isTabPage', () => { + expect(isTabPage('/admin')).toBe(false); + expect(isTabPage('/admin/test/tabs/tabId')).toBe(true); + expect(isTabPage('/admin/test/tabs/tabId/')).toBe(true); + }); + + it('navigateToTab', () => { + const navigate1 = vi.fn(); + const navigate2 = vi.fn(); + const navigate3 = vi.fn(); + const navigate4 = vi.fn(); + const navigate5 = vi.fn(); + const navigate6 = vi.fn(); + const navigate7 = vi.fn(); + const navigate8 = vi.fn(); + + navigateToTab('tabId', navigate1, '/admin/test'); + expect(navigate1).toBeCalledWith('/admin/test/tabs/tabId', { replace: true }); + + navigateToTab('tabId', navigate2, '/admin/test/'); + expect(navigate2).toBeCalledWith('/admin/test/tabs/tabId', { replace: true }); + + navigateToTab('tabId', navigate3, '/admin/test/tabs/oldTabId'); + expect(navigate3).toBeCalledWith('/admin/test/tabs/tabId', { replace: true }); + + navigateToTab('tabId', navigate4, '/admin/test/tabs/oldTabId/'); + expect(navigate4).toBeCalledWith('/admin/test/tabs/tabId', { replace: true }); + + navigateToTab('tabId', navigate5, '/admin/test/tabs/tab1/pages/pageId/tabs/tab2'); + expect(navigate5).toBeCalledWith('/admin/test/tabs/tab1/pages/pageId/tabs/tabId', { replace: true }); + + navigateToTab('tabId', navigate6, '/admin/test/tabs/tab1/pages/pageId/tabs/tab2/'); + expect(navigate6).toBeCalledWith('/admin/test/tabs/tab1/pages/pageId/tabs/tabId', { replace: true }); + + navigateToTab('tabId', navigate7, '/admin/test/tabs/tab1/pages/pageId'); + expect(navigate7).toBeCalledWith('/admin/test/tabs/tab1/pages/pageId/tabs/tabId', { replace: true }); + + navigateToTab('tabId', navigate8, '/admin/test/tabs/tab1/pages/pageId/'); + expect(navigate8).toBeCalledWith('/admin/test/tabs/tab1/pages/pageId/tabs/tabId', { replace: true }); + }); +});