Commit 70e837d4 by siigure Committed by GitHub

fix(chat): add MyTooltip for app name overflow handling (#7322)

parent 94134b04
...@@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next'; ...@@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next';
import { Box, Flex, Image } from '@chakra-ui/react'; import { Box, Flex, Image } from '@chakra-ui/react';
import Avatar from '@fastgpt/web/components/common/Avatar'; import Avatar from '@fastgpt/web/components/common/Avatar';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { useSystem } from '@fastgpt/web/hooks/useSystem';
import { ChatItemContext } from '@/web/core/chat/context/chatItemContext'; import { ChatItemContext } from '@/web/core/chat/context/chatItemContext';
import { DEFAULT_LOGO_BANNER_URL } from '@/pageComponents/chat/constants'; import { DEFAULT_LOGO_BANNER_URL } from '@/pageComponents/chat/constants';
...@@ -37,21 +38,24 @@ const ChatSliderHeader = ({ title, banner }: Props) => { ...@@ -37,21 +38,24 @@ const ChatSliderHeader = ({ title, banner }: Props) => {
const isHomePane = pane === ChatSidebarPaneEnum.HOME && activeAppId === homeAppId; const isHomePane = pane === ChatSidebarPaneEnum.HOME && activeAppId === homeAppId;
const isAllAppsPane = pane === ChatSidebarPaneEnum.ALL_APPS; const isAllAppsPane = pane === ChatSidebarPaneEnum.ALL_APPS;
const headerTitle = title || (isCurrentAppReady ? appName : '');
return isPc ? ( return isPc ? (
<Flex py={4} px={[2, 2]} gap={2} alignItems={'center'} fontSize={'sm'}> <Flex py={4} px={[2, 2]} gap={2} alignItems={'center'} fontSize={'sm'}>
{!title && <Avatar src={isCurrentAppReady ? appAvatar : undefined} borderRadius={'md'} />} {!title && <Avatar src={isCurrentAppReady ? appAvatar : undefined} borderRadius={'md'} />}
<Box <MyTooltip label={headerTitle} showOnlyWhenOverflow>
flex={'1 0 0'} <Box
w={0} flex={'1 0 0'}
fontWeight={'bold'} w={0}
fontSize={title ? '16px' : 'inherit'} fontWeight={'bold'}
color={title ? 'myGray.900' : 'inherit'} fontSize={title ? '16px' : 'inherit'}
className={'textEllipsis'} color={title ? 'myGray.900' : 'inherit'}
> className={'textEllipsis'}
{title || (isCurrentAppReady ? appName : '')} >
</Box> {headerTitle}
</Box>
</MyTooltip>
</Flex> </Flex>
) : ( ) : (
<> <>
......
...@@ -9,6 +9,7 @@ import { useUserStore } from '@/web/support/user/useUserStore'; ...@@ -9,6 +9,7 @@ import { useUserStore } from '@/web/support/user/useUserStore';
import UserAvatarPopover from '@/pageComponents/chat/UserAvatarPopover'; import UserAvatarPopover from '@/pageComponents/chat/UserAvatarPopover';
import MyBox from '@fastgpt/web/components/common/MyBox'; import MyBox from '@fastgpt/web/components/common/MyBox';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { import {
ChatSidebarPaneEnum, ChatSidebarPaneEnum,
DEFAULT_LOGO_BANNER_COLLAPSED_URL, DEFAULT_LOGO_BANNER_COLLAPSED_URL,
...@@ -545,9 +546,9 @@ const ChatSlider = ({ activeAppId }: Props) => { ...@@ -545,9 +546,9 @@ const ChatSlider = ({ activeAppId }: Props) => {
})} })}
> >
<Avatar src={item.avatar} w={'20px'} h={'20px'} borderRadius={'6px'} /> <Avatar src={item.avatar} w={'20px'} h={'20px'} borderRadius={'6px'} />
<Box className={'textEllipsis'}> <MyTooltip label={item.name} showOnlyWhenOverflow>
{item.name} <Box className={'textEllipsis'}>{item.name}</Box>
</Box> </MyTooltip>
</Flex> </Flex>
))} ))}
</MyBox> </MyBox>
......
...@@ -51,6 +51,7 @@ import { useAppChatGenerateStatusSync } from '@/pageComponents/chat/ChatWindow/u ...@@ -51,6 +51,7 @@ import { useAppChatGenerateStatusSync } from '@/pageComponents/chat/ChatWindow/u
import { postMarkChatRead } from '@/web/core/chat/history/api'; import { postMarkChatRead } from '@/web/core/chat/history/api';
import { useSandboxEditor, useSandboxStatus } from '@/pageComponents/chat/SandboxEditor/hook'; import { useSandboxEditor, useSandboxStatus } from '@/pageComponents/chat/SandboxEditor/hook';
import type { GetHistoriesBodyType } from '@fastgpt/global/openapi/core/chat/history/api'; import type { GetHistoriesBodyType } from '@fastgpt/global/openapi/core/chat/history/api';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
const logger = getLogger(LogCategories.MODULE.CHAT.ITEM); const logger = getLogger(LogCategories.MODULE.CHAT.ITEM);
...@@ -384,17 +385,19 @@ const OutLink = (props: Props) => { ...@@ -384,17 +385,19 @@ const OutLink = (props: Props) => {
flexShrink={0} flexShrink={0}
/> />
)} )}
<Box <MyTooltip label={mobileHeaderAppName} showOnlyWhenOverflow>
minW={0} <Box
fontSize="16px" minW={0}
fontWeight={500} fontSize="16px"
color="myGray.900" fontWeight={500}
overflow="hidden" color="myGray.900"
whiteSpace="nowrap" overflow="hidden"
textOverflow="clip" whiteSpace="nowrap"
> textOverflow="clip"
{mobileHeaderAppName} >
</Box> {mobileHeaderAppName}
</Box>
</MyTooltip>
</Flex> </Flex>
{hideMenu === '1' ? ( {hideMenu === '1' ? (
......
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { describe, expect, it } from 'vitest';
const longAppName = 'qa-auto-qa-1784240694258-简单Agent鉴权';
const overflowExamples = [
'qa-auto-qa-1784240694258-简单Agent鉴权',
'qa-auto-qa-1784240694258-simple-agent-auth-with-extra-long-english-name'
];
const readProjectFile = (relativePath: string) =>
readFileSync(resolve(process.cwd(), relativePath), 'utf-8');
const expectOverflowNameHasHoverFullText = ({
nodeName,
source,
nameExpression
}: {
nodeName: string;
source: string;
nameExpression: string;
}) => {
const nameIndex = source.indexOf(nameExpression);
expect(nameIndex, `${nodeName}: 未找到应用名渲染表达式 ${nameExpression}`).toBeGreaterThanOrEqual(
0
);
const snippet = source.slice(Math.max(0, nameIndex - 500), nameIndex + 500);
const hasOverflowStyle =
snippet.includes('textEllipsis') ||
snippet.includes('textOverflow') ||
snippet.includes('isTruncated');
const hasFullNameHoverAffordance =
snippet.includes('MyTooltip') ||
snippet.includes('Tooltip') ||
snippet.includes('showOnlyWhenOverflow') ||
snippet.includes('title=');
const hasOverflowOnlyTooltip = snippet.includes('showOnlyWhenOverflow');
const hasFullNameLabel = snippet.includes(`label=${nameExpression}`);
expect(
hasOverflowStyle,
`${nodeName}: ${longAppName} 这类长应用名应先被单行截断,测试才能覆盖 hover 展示全名场景`
).toBe(true);
expect(
hasFullNameHoverAffordance,
`${nodeName}: 长应用名被截断后 hover 不能展示完整名称,应用名节点附近缺少 MyTooltip/Tooltip/title/showOnlyWhenOverflow`
).toBe(true);
expect(
hasOverflowOnlyTooltip,
`${nodeName}: 短应用名不应出现多余 hover 展示,应使用 showOnlyWhenOverflow 限制只在溢出时展示`
).toBe(true);
expect(
hasFullNameLabel,
`${nodeName}: hover 展示内容必须使用完整应用名字段 ${nameExpression},不能使用截断后的展示文本`
).toBe(true);
};
describe('chat app name overflow hover disclosure', () => {
it('门户最近使用应用:截断后的应用名 hover 应展示完整名称', () => {
const source = readProjectFile('src/pageComponents/chat/slider/index.tsx');
expectOverflowNameHasHoverFullText({
nodeName: '门户最近使用应用',
source,
nameExpression: '{item.name}'
});
});
it('门户聊天历史侧栏顶部应用名:截断后 hover 应展示完整名称', () => {
const source = readProjectFile('src/pageComponents/chat/slider/ChatSliderHeader.tsx');
expectOverflowNameHasHoverFullText({
nodeName: '门户聊天历史侧栏顶部应用名',
source,
nameExpression: '{headerTitle}'
});
});
it('免登链接应用:截断后的应用名 hover 应展示完整名称', () => {
const source = readProjectFile('src/pages/chat/share.tsx');
expectOverflowNameHasHoverFullText({
nodeName: '免登链接应用',
source,
nameExpression: '{mobileHeaderAppName}'
});
});
it('短名称不应出现多余 hover 展示,中文/英文长名称溢出时才展示', () => {
const tooltipSource = readProjectFile(
'../../packages/web/components/common/MyTooltip/index.tsx'
);
expect(overflowExamples).toHaveLength(2);
expect(tooltipSource).toContain('target.scrollWidth > target.clientWidth');
expect(tooltipSource).toContain('showOnlyWhenOverflow && !isOverflow');
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment