diff --git a/packages/core/client/src/modules/menu/PageMenuItem.tsx b/packages/core/client/src/modules/menu/PageMenuItem.tsx index 012e48fb0a..675de5746a 100644 --- a/packages/core/client/src/modules/menu/PageMenuItem.tsx +++ b/packages/core/client/src/modules/menu/PageMenuItem.tsx @@ -85,7 +85,6 @@ export const PageMenuItem = () => { children: [ { type: NocoBaseDesktopRouteType.tabs, - title: '{{t("Unnamed")}}', schemaUid: tabSchemaUid, tabSchemaName, hidden: true, diff --git a/packages/core/client/src/modules/menu/__e2e__/dragAndDrop.test.ts b/packages/core/client/src/modules/menu/__e2e__/dragAndDrop.test.ts index 59f3931cac..770cefd04d 100644 --- a/packages/core/client/src/modules/menu/__e2e__/dragAndDrop.test.ts +++ b/packages/core/client/src/modules/menu/__e2e__/dragAndDrop.test.ts @@ -23,6 +23,7 @@ test('single page', async ({ page, mockPage }) => { await page.getByLabel('block-item-TreeSelect-Target').locator('.ant-select').click(); await page.locator('.ant-select-dropdown').getByText(pageTitle2).click(); await page.getByRole('button', { name: 'OK', exact: true }).click(); + await page.waitForTimeout(500); const page1 = await page.getByRole('menu').getByText(pageTitle1).boundingBox(); const page2 = await page.getByRole('menu').getByText(pageTitle2).boundingBox(); //拖拽菜单排序符合预期 diff --git a/packages/core/client/src/schema-component/antd/menu/Menu.Designer.tsx b/packages/core/client/src/schema-component/antd/menu/Menu.Designer.tsx index 4c867d23a9..d9c8037336 100644 --- a/packages/core/client/src/schema-component/antd/menu/Menu.Designer.tsx +++ b/packages/core/client/src/schema-component/antd/menu/Menu.Designer.tsx @@ -190,7 +190,6 @@ const InsertMenuItems = (props) => { children: [ { type: NocoBaseDesktopRouteType.tabs, - title: '{{t("Unnamed")}}', schemaUid: tabSchemaUid, tabSchemaName, hidden: true, @@ -199,12 +198,14 @@ const InsertMenuItems = (props) => { }); // 2. 然后再把路由移动到对应的位置 - await moveRoute({ - sourceId: data?.data?.id, - targetId: route?.id, - sortField: 'sort', - method: insertPositionToMethod[insertPosition], - }); + if (insertPositionToMethod[insertPosition]) { + await moveRoute({ + sourceId: data?.data?.id, + targetId: route?.id, + sortField: 'sort', + method: insertPositionToMethod[insertPosition], + }); + } // 3. 插入一个对应的 Schema dn.insertAdjacent( @@ -267,12 +268,14 @@ const InsertMenuItems = (props) => { ); // 2. 然后再把路由移动到对应的位置 - await moveRoute({ - sourceId: data?.data?.id, - targetId: route?.id, - sortField: 'sort', - method: insertPositionToMethod[insertPosition], - }); + if (insertPositionToMethod[insertPosition]) { + await moveRoute({ + sourceId: data?.data?.id, + targetId: route?.id, + sortField: 'sort', + method: insertPositionToMethod[insertPosition], + }); + } // 3. 插入一个对应的 Schema dn.insertAdjacent(insertPosition, { @@ -318,14 +321,14 @@ export const MenuDesigner = () => { f.dataSource = component === 'Menu.SubMenu' ? [ - { label: t('Before'), value: 'beforeBegin' }, - { label: t('After'), value: 'afterEnd' }, - { label: t('Inner'), value: 'beforeEnd' }, - ] + { label: t('Before'), value: 'beforeBegin' }, + { label: t('After'), value: 'afterEnd' }, + { label: t('Inner'), value: 'beforeEnd' }, + ] : [ - { label: t('Before'), value: 'beforeBegin' }, - { label: t('After'), value: 'afterEnd' }, - ]; + { label: t('Before'), value: 'beforeBegin' }, + { label: t('After'), value: 'afterEnd' }, + ]; }); }); }, @@ -401,9 +404,9 @@ export const MenuDesigner = () => { options: href || params ? { - href, - params, - } + href, + params, + } : undefined, }); } diff --git a/packages/core/test/src/e2e/e2eUtils.ts b/packages/core/test/src/e2e/e2eUtils.ts index dc69d9a814..f3a46dd8ce 100644 --- a/packages/core/test/src/e2e/e2eUtils.ts +++ b/packages/core/test/src/e2e/e2eUtils.ts @@ -614,7 +614,7 @@ const _test = base.extend({ const page = await getPage(browser); const deletePage = async (pageName: string) => { - await page.getByText(pageName, { exact: true }).hover(); + await page.getByLabel(pageName, { exact: true }).hover(); await page.getByRole('button', { name: 'designer-schema-settings-' }).hover(); await page.getByRole('menuitem', { name: 'Delete', exact: true }).click(); await page.getByRole('button', { name: 'OK', exact: true }).click(); diff --git a/packages/plugins/@nocobase/plugin-client/src/client/routesTableSchema.tsx b/packages/plugins/@nocobase/plugin-client/src/client/routesTableSchema.tsx index d5092fb0e0..734ad1a04b 100644 --- a/packages/plugins/@nocobase/plugin-client/src/client/routesTableSchema.tsx +++ b/packages/plugins/@nocobase/plugin-client/src/client/routesTableSchema.tsx @@ -11,6 +11,7 @@ import { CheckOutlined, CloseOutlined } from '@ant-design/icons'; import { useField, useForm } from '@formily/react'; import { + CollectionField, css, getGroupMenuSchema, getLinkMenuSchema, @@ -236,13 +237,13 @@ export const createRoutesTableSchema = (collectionName: string, basename: string 'x-component': 'IconPicker', 'x-reactions': isMobile ? { - dependencies: ['type'], - fulfill: { - state: { - required: '{{$deps[0] !== "tabs"}}', - }, + dependencies: ['type'], + fulfill: { + state: { + required: '{{$deps[0] !== "tabs"}}', }, - } + }, + } : undefined, }, // 由于历史原因,桌面端使用的是 'href' 作为 key,移动端使用的是 'url' 作为 key @@ -426,7 +427,6 @@ export const createRoutesTableSchema = (collectionName: string, basename: string schemaUid: tabSchemaUid, parentId: res?.data?.data?.id, type: NocoBaseDesktopRouteType.tabs, - title: '{{t("Unnamed")}}', tabSchemaName, hidden: true, }); @@ -488,7 +488,17 @@ export const createRoutesTableSchema = (collectionName: string, basename: string properties: { title: { type: 'string', - 'x-component': 'CollectionField', + 'x-component': function Com(props) { + const record = useCollectionRecordData(); + const { t } = useTranslation(); + let value = props.value; + + if (record.type === NocoBaseDesktopRouteType.tabs && _.isNil(props.value)) { + value = t('Unnamed'); + } + + return ; + }, 'x-read-pretty': true, 'x-component-props': { ellipsis: true, @@ -565,9 +575,8 @@ export const createRoutesTableSchema = (collectionName: string, basename: string } if (recordData.type === NocoBaseDesktopRouteType.page) { - const path = `${basenameOfCurrentRouter.slice(0, -1)}${basename}/${ - isMobile ? recordData.schemaUid : recordData.menuSchemaUid - }`; + const path = `${basenameOfCurrentRouter.slice(0, -1)}${basename}/${isMobile ? recordData.schemaUid : recordData.menuSchemaUid + }`; // 在点击 Access 按钮时,会用到 recordData._path = path; @@ -687,13 +696,13 @@ export const createRoutesTableSchema = (collectionName: string, basename: string 'x-component': 'IconPicker', 'x-reactions': isMobile ? { - dependencies: ['type'], - fulfill: { - state: { - required: '{{$deps[0] !== "tabs"}}', - }, + dependencies: ['type'], + fulfill: { + state: { + required: '{{$deps[0] !== "tabs"}}', }, - } + }, + } : undefined, }, // 由于历史原因,桌面端使用的是 'href' 作为 key,移动端使用的是 'url' 作为 key @@ -889,7 +898,6 @@ export const createRoutesTableSchema = (collectionName: string, basename: string await createRoute({ parentId: res?.data?.data?.id, type: NocoBaseDesktopRouteType.tabs, - title: '{{t("Unnamed")}}', schemaUid: tabSchemaUid, tabSchemaName, hidden: true, @@ -977,13 +985,13 @@ export const createRoutesTableSchema = (collectionName: string, basename: string 'x-component': 'IconPicker', 'x-reactions': isMobile ? { - dependencies: ['type'], - fulfill: { - state: { - required: '{{$deps[0] !== "tabs"}}', - }, + dependencies: ['type'], + fulfill: { + state: { + required: '{{$deps[0] !== "tabs"}}', }, - } + }, + } : undefined, }, // 由于历史原因,桌面端使用的是 'href' 作为 key,移动端使用的是 'url' 作为 key @@ -1259,13 +1267,13 @@ function useCreateRouteSchema(isMobile: boolean) { [NocoBaseDesktopRouteType.page]: isMobile ? getMobilePageSchema(pageSchemaUid, tabSchemaUid).schema : getPageMenuSchema({ - title, - icon, - pageSchemaUid, - tabSchemaUid, - menuSchemaUid, - tabSchemaName, - }), + title, + icon, + pageSchemaUid, + tabSchemaUid, + menuSchemaUid, + tabSchemaName, + }), [NocoBaseDesktopRouteType.group]: getGroupMenuSchema({ title, icon, schemaUid: menuSchemaUid }), [NocoBaseDesktopRouteType.link]: getLinkMenuSchema({ title, icon, schemaUid: menuSchemaUid, href, params }), }; diff --git a/packages/plugins/@nocobase/plugin-client/src/server/migrations/2024122912211-transform-menu-schema-to-routes.ts b/packages/plugins/@nocobase/plugin-client/src/server/migrations/2024122912211-transform-menu-schema-to-routes.ts index 743d0d96e7..6e6748af54 100644 --- a/packages/plugins/@nocobase/plugin-client/src/server/migrations/2024122912211-transform-menu-schema-to-routes.ts +++ b/packages/plugins/@nocobase/plugin-client/src/server/migrations/2024122912211-transform-menu-schema-to-routes.ts @@ -165,7 +165,7 @@ export async function schemaToRoutes(schema: any, uiSchemas: any) { // Tab return { type: 'tabs', - title: item.title || '{{t("Unnamed")}}', + title: item.title, icon: item['x-component-props']?.icon, schemaUid: item['x-uid'], tabSchemaName: key, diff --git a/packages/plugins/@nocobase/plugin-mobile/src/client/mobile-layout/mobile-tab-bar/types/MobileTabBar.Page/initializer.tsx b/packages/plugins/@nocobase/plugin-mobile/src/client/mobile-layout/mobile-tab-bar/types/MobileTabBar.Page/initializer.tsx index 6d42f81113..f6f8bace7a 100644 --- a/packages/plugins/@nocobase/plugin-mobile/src/client/mobile-layout/mobile-tab-bar/types/MobileTabBar.Page/initializer.tsx +++ b/packages/plugins/@nocobase/plugin-mobile/src/client/mobile-layout/mobile-tab-bar/types/MobileTabBar.Page/initializer.tsx @@ -69,7 +69,6 @@ export const mobileTabBarSchemaInitializerItem: SchemaInitializerItemActionModal values: { type: 'tabs', parentId, - title: 'Unnamed', schemaUid: firstTabUid, hidden: true, } as MobileRouteItem, diff --git a/packages/plugins/@nocobase/plugin-mobile/src/client/pages/dynamic-page/header/tabs/MobilePageTabs.tsx b/packages/plugins/@nocobase/plugin-mobile/src/client/pages/dynamic-page/header/tabs/MobilePageTabs.tsx index 7abb150a96..ad5191184a 100644 --- a/packages/plugins/@nocobase/plugin-mobile/src/client/pages/dynamic-page/header/tabs/MobilePageTabs.tsx +++ b/packages/plugins/@nocobase/plugin-mobile/src/client/pages/dynamic-page/header/tabs/MobilePageTabs.tsx @@ -12,6 +12,7 @@ import React, { FC, useCallback } from 'react'; import { Navigate, useNavigate, useParams } from 'react-router-dom'; import { DndContext, DndContextProps, Icon, SortableItem, useCompile } from '@nocobase/client'; +import { useTranslation } from 'react-i18next'; import { useMobileRoutes } from '../../../../mobile-providers'; import { useMobilePage } from '../../context'; import { MobilePageTabInitializer } from './initializer'; @@ -24,6 +25,7 @@ export const MobilePageTabs: FC = () => { const displayTabs = activeTabBarItem?.enableTabs === undefined ? _displayTabs : activeTabBarItem.enableTabs; const compile = useCompile(); + const { t } = useTranslation(); const navigate = useNavigate(); const { componentCls, hashId } = useStyles(); @@ -60,19 +62,20 @@ export const MobilePageTabs: FC = () => { {activeTabBarItem.children?.map((item) => { if (item.hideInMenu) return null; + const title = item.title ? compile(item.title) : t('Unnamed'); return ( {item.icon ? ( - {compile(item.title)} + {title} ) : ( - compile(item.title) + title )} }