optimize ParentPaths component (#5179)

* optimize ParentPaths component

* fix dataset list diaplay

* component
This commit is contained in:
heheer
2025-07-10 18:16:03 +08:00
committed by GitHub
parent ac493db00f
commit 7a6a396f2a
12 changed files with 141 additions and 127 deletions

View File

@@ -45,6 +45,7 @@ export const iconPaths = {
'common/download': () => import('./icons/common/download.svg'), 'common/download': () => import('./icons/common/download.svg'),
'common/edit': () => import('./icons/common/edit.svg'), 'common/edit': () => import('./icons/common/edit.svg'),
'common/editor/resizer': () => import('./icons/common/editor/resizer.svg'), 'common/editor/resizer': () => import('./icons/common/editor/resizer.svg'),
'common/ellipsis': () => import('./icons/common/ellipsis.svg'),
'common/enable': () => import('./icons/common/enable.svg'), 'common/enable': () => import('./icons/common/enable.svg'),
'common/errorFill': () => import('./icons/common/errorFill.svg'), 'common/errorFill': () => import('./icons/common/errorFill.svg'),
'common/file/move': () => import('./icons/common/file/move.svg'), 'common/file/move': () => import('./icons/common/file/move.svg'),

View File

@@ -0,0 +1,4 @@
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" >
<path d="M221 592c-44.183 0-80-35.817-80-80s35.817-80 80-80 80 35.817 80 80-35.817 80-80 80z m291 0c-44.183 0-80-35.817-80-80s35.817-80 80-80 80 35.817 80 80-35.817 80-80 80z m291 0c-44.183 0-80-35.817-80-80s35.817-80 80-80 80 35.817 80 80-35.817 80-80 80z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 362 B

View File

@@ -326,6 +326,7 @@ const MyMenu = ({
<Box <Box
w={'100%'} w={'100%'}
color={child.description ? 'myGray.900' : 'inherit'} color={child.description ? 'myGray.900' : 'inherit'}
pr={child.icon ? 4 : 0}
{...sizeMapStyle[size].labelStyle} {...sizeMapStyle[size].labelStyle}
> >
{child.label} {child.label}

View File

@@ -1,67 +0,0 @@
import { Box, Flex } from '@chakra-ui/react';
import { type ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type';
import React, { useMemo } from 'react';
import { useTranslation } from 'next-i18next';
const ParentPaths = (props: {
paths?: ParentTreePathItemType[];
rootName?: string;
FirstPathDom?: React.ReactNode;
onClick: (parentId: string) => void;
fontSize?: string;
}) => {
const { t } = useTranslation();
const { paths = [], rootName = t('common:root_folder'), FirstPathDom, onClick, fontSize } = props;
const concatPaths = useMemo(
() => [
{
parentId: '',
parentName: rootName
},
...paths
],
[rootName, paths]
);
return paths.length === 0 && !!FirstPathDom ? (
<>{FirstPathDom}</>
) : (
<Flex flex={1} ml={-2}>
{concatPaths.map((item, i) => (
<Flex key={item.parentId || i} alignItems={'center'}>
<Box
fontSize={['sm', fontSize || 'sm']}
py={0.5}
px={1.5}
borderRadius={'md'}
{...(i === concatPaths.length - 1
? {
cursor: 'default',
color: 'myGray.700',
fontWeight: 'bold'
}
: {
cursor: 'pointer',
color: 'myGray.600',
_hover: {
bg: 'myGray.100'
},
onClick: () => {
onClick(item.parentId);
}
})}
>
{item.parentName}
</Box>
{i !== concatPaths.length - 1 && (
<Box mx={1} color={'myGray.500'}>
/
</Box>
)}
</Flex>
))}
</Flex>
);
};
export default React.memo(ParentPaths);

View File

@@ -3,6 +3,8 @@ import { type ParentTreePathItemType } from '@fastgpt/global/common/parentFolder
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
import MyMenu from '@fastgpt/web/components/common/MyMenu';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
const FolderPath = (props: { const FolderPath = (props: {
paths: ParentTreePathItemType[]; paths: ParentTreePathItemType[];
@@ -35,50 +37,116 @@ const FolderPath = (props: {
[rootName, paths] [rootName, paths]
); );
const displayPaths = useMemo(() => {
if (concatPaths.length <= 3) {
return concatPaths;
} else {
return [
concatPaths[0],
null,
concatPaths[concatPaths.length - 2],
concatPaths[concatPaths.length - 1]
];
}
}, [concatPaths]);
const renderPathItem = (item: (typeof concatPaths)[0] | null, index: number) => {
if (item === null) {
const middlePaths = concatPaths.slice(1, -2);
return (
<Flex alignItems={'center'} key={index}>
<MyMenu
Button={
<Box
fontSize={['sm', fontSize || 'sm']}
py={0.5}
px={1}
color={'myGray.600'}
borderRadius={'sm'}
cursor="pointer"
display={'flex'}
alignItems={'center'}
_hover={{
bg: 'myGray.200'
}}
>
<MyIcon name={'common/ellipsis'} color={'myGray.500'} width={'12px'} />
</Box>
}
trigger={'hover'}
size={'xs'}
menuList={[
{
children: middlePaths.map((pathItem) => ({
label: (
<Box overflow={'hidden'} textOverflow={'ellipsis'} whiteSpace={'nowrap'}>
{pathItem.parentName}
</Box>
),
icon: 'file/fill/folder',
onClick: () => onClick(pathItem.parentId)
}))
}
]}
/>
<MyIcon name={'common/line'} color={'myGray.500'} mx={1} width={'5px'} />
</Flex>
);
}
const isLast = index === displayPaths.length - 1;
const clickStyles = {
cursor: 'pointer',
_hover: {
bg: 'myGray.100',
...hoverStyle
},
onClick: () => {
onClick(item.parentId);
}
};
const shouldTruncate = !isLast && item.parentName.length > 10;
const displayName = shouldTruncate ? `${item.parentName.slice(0, 10)}...` : item.parentName;
const pathBox = (
<Box
fontSize={['xs', fontSize || 'sm']}
py={0.5}
px={1.5}
borderRadius={'sm'}
maxW={'45vw'}
className={'textEllipsis'}
{...(isLast && concatPaths.length > 1
? {
color: 'myGray.700',
fontWeight: 'bold'
}
: {
fontWeight: 'medium',
color: 'myGray.500',
...clickStyles
})}
{...(isLast && !forbidLastClick && clickStyles)}
>
{displayName}
</Box>
);
return (
<Flex key={item.parentId || index} alignItems={'center'}>
{shouldTruncate ? <MyTooltip label={item.parentName}>{pathBox}</MyTooltip> : pathBox}
{!isLast && <MyIcon name={'common/line'} color={'myGray.500'} mx={1} width={'5px'} />}
</Flex>
);
};
return paths.length === 0 && !!FirstPathDom ? ( return paths.length === 0 && !!FirstPathDom ? (
<>{FirstPathDom}</> <>{FirstPathDom}</>
) : ( ) : (
<Flex flex={1}> <Flex flex={1} ml={-2}>
{concatPaths.map((item, i) => { {displayPaths.map((item, index) => renderPathItem(item, index))}
const clickStyles = {
cursor: 'pointer',
_hover: {
bg: 'myGray.100',
...hoverStyle
},
onClick: () => {
onClick(item.parentId);
}
};
return (
<Flex key={item.parentId || i} alignItems={'center'}>
<Box
fontSize={['xs', fontSize || 'sm']}
py={0.5}
px={1.5}
borderRadius={'md'}
maxW={'45vw'}
className={'textEllipsis'}
{...(i === concatPaths.length - 1 && concatPaths.length > 1
? {
color: 'myGray.700',
fontWeight: 'bold'
}
: {
fontWeight: 'medium',
color: 'myGray.500',
...clickStyles
})}
{...(i === concatPaths.length - 1 && !forbidLastClick && clickStyles)}
>
{item.parentName}
</Box>
{i !== concatPaths.length - 1 && (
<MyIcon name={'common/line'} color={'myGray.500'} mx={1} width={'5px'} />
)}
</Flex>
);
})}
</Flex> </Flex>
); );
}; };

View File

@@ -51,7 +51,14 @@ const FolderSlideCard = ({
<Box> <Box>
<HStack> <HStack>
<MyIcon name={FolderIcon} w={'1.5rem'} /> <MyIcon name={FolderIcon} w={'1.5rem'} />
<Box color={'myGray.900'}>{name}</Box> <Box
color={'myGray.900'}
overflow={'hidden'}
textOverflow={'ellipsis'}
whiteSpace={'nowrap'}
>
{name}
</Box>
<MyIcon <MyIcon
name={'edit'} name={'edit'}
_hover={{ color: 'primary.600' }} _hover={{ color: 'primary.600' }}

View File

@@ -4,7 +4,7 @@ import { useQuery } from '@tanstack/react-query';
import React, { type Dispatch, useMemo, useState } from 'react'; import React, { type Dispatch, useMemo, useState } from 'react';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { Box } from '@chakra-ui/react'; import { Box } from '@chakra-ui/react';
import ParentPaths from '@/components/common/ParentPaths'; import FolderPath from '@/components/common/folder/Path';
import MyBox from '@fastgpt/web/components/common/MyBox'; import MyBox from '@fastgpt/web/components/common/MyBox';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
@@ -37,7 +37,7 @@ const DatasetSelectContainer = ({
iconSrc="/imgs/workflow/db.png" iconSrc="/imgs/workflow/db.png"
title={ title={
<Box fontWeight={'normal'}> <Box fontWeight={'normal'}>
<ParentPaths <FolderPath
paths={paths.map((path, i) => ({ paths={paths.map((path, i) => ({
parentId: path.parentId, parentId: path.parentId,
parentName: path.parentName parentName: path.parentName

View File

@@ -22,7 +22,7 @@ import {
} from '@fastgpt/global/core/dataset/constants'; } from '@fastgpt/global/core/dataset/constants';
import EditFolderModal, { useEditFolder } from '../../EditFolderModal'; import EditFolderModal, { useEditFolder } from '../../EditFolderModal';
import { TabEnum } from '../../../../pages/dataset/detail/index'; import { TabEnum } from '../../../../pages/dataset/detail/index';
import ParentPath from '@/components/common/ParentPaths'; import FolderPath from '@/components/common/folder/Path';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { ImportDataSourceEnum } from '@fastgpt/global/core/dataset/constants'; import { ImportDataSourceEnum } from '@fastgpt/global/core/dataset/constants';
@@ -117,7 +117,7 @@ const Header = ({ hasTrainingData }: { hasTrainingData: boolean }) => {
<MyBox display={['block', 'flex']} alignItems={'center'} gap={2}> <MyBox display={['block', 'flex']} alignItems={'center'} gap={2}>
<HStack flex={1}> <HStack flex={1}>
<Box flex={1} fontWeight={'500'} color={'myGray.900'} whiteSpace={'nowrap'}> <Box flex={1} fontWeight={'500'} color={'myGray.900'} whiteSpace={'nowrap'}>
<ParentPath <FolderPath
paths={paths.map((path, i) => ({ paths={paths.map((path, i) => ({
parentId: path.parentId, parentId: path.parentId,
parentName: i === paths.length - 1 ? `${path.parentName}` : path.parentName parentName: i === paths.length - 1 ? `${path.parentName}` : path.parentName

View File

@@ -8,7 +8,7 @@ import { DatasetPageContext } from '@/web/core/dataset/context/datasetPageContex
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs'; import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { useSystem } from '@fastgpt/web/hooks/useSystem';
import MyPopover from '@fastgpt/web/components/common/MyPopover'; import MyPopover from '@fastgpt/web/components/common/MyPopover';
import ParentPaths from '@/components/common/ParentPaths'; import FolderPath from '@/components/common/folder/Path';
import { getTrainingQueueLen } from '@/web/core/dataset/api'; import { getTrainingQueueLen } from '@/web/core/dataset/api';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
@@ -166,7 +166,7 @@ const NavBar = ({ currentTab }: { currentTab: TabEnum }) => {
</> </>
) : ( ) : (
<Flex py={'0.38rem'} px={2} h={10} ml={0.5}> <Flex py={'0.38rem'} px={2} h={10} ml={0.5}>
<ParentPaths <FolderPath
paths={paths} paths={paths}
onClick={(e) => { onClick={(e) => {
router.push(`/dataset/list?parentId=${e}`); router.push(`/dataset/list?parentId=${e}`);

View File

@@ -219,14 +219,14 @@ function List() {
} }
}} }}
> >
<HStack> <Flex w="100%">
<Avatar src={dataset.avatar} borderRadius={6} w={'28px'} /> <Avatar src={dataset.avatar} borderRadius={6} w={'28px'} flexShrink={0} />
<Box flex={'1 0 0'} className="textEllipsis3" color={'myGray.900'}> <Box width="0" flex="1" className="textEllipsis" color={'myGray.900'} ml={2}>
{dataset.name} {dataset.name}
</Box> </Box>
<Box mr={'-1.25rem'}> {dataset.type !== DatasetTypeEnum.folder && (
{dataset.type !== DatasetTypeEnum.folder && ( <Box flexShrink={0} ml={2}>
<SideTag <SideTag
type={dataset.type} type={dataset.type}
py={0.5} py={0.5}
@@ -234,9 +234,9 @@ function List() {
borderLeftRadius={'sm'} borderLeftRadius={'sm'}
borderRightRadius={0} borderRightRadius={0}
/> />
)} </Box>
</Box> )}
</HStack> </Flex>
<Box <Box
flex={1} flex={1}

View File

@@ -4,7 +4,7 @@ import { Box, Flex, Button, InputGroup, InputLeftElement, Input } from '@chakra-
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { serviceSideProps } from '@/web/common/i18n/utils'; import { serviceSideProps } from '@/web/common/i18n/utils';
import ParentPaths from '@/components/common/folder/Path'; import FolderPath from '@/components/common/folder/Path';
import List from '@/pageComponents/dataset/list/List'; import List from '@/pageComponents/dataset/list/List';
import { DatasetsContext } from './context'; import { DatasetsContext } from './context';
import DatasetContextProvider from './context'; import DatasetContextProvider from './context';
@@ -108,7 +108,7 @@ const Dataset = () => {
<Flex pt={[4, 6]} pl={3} pr={folderDetail ? [3, 6] : [3, 8]}> <Flex pt={[4, 6]} pl={3} pr={folderDetail ? [3, 6] : [3, 8]}>
<Flex flexGrow={1} flexDirection="column"> <Flex flexGrow={1} flexDirection="column">
<Flex alignItems={'center'} justifyContent={'space-between'}> <Flex alignItems={'center'} justifyContent={'space-between'}>
<ParentPaths <FolderPath
paths={paths} paths={paths}
FirstPathDom={ FirstPathDom={
<Flex flex={1} alignItems={'center'}> <Flex flex={1} alignItems={'center'}>

View File

@@ -1,6 +1,6 @@
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
import MyModal from '@fastgpt/web/components/common/MyModal'; import MyModal from '@fastgpt/web/components/common/MyModal';
import ParentPaths from '@/components/common/ParentPaths'; import FolderPath from '@/components/common/folder/Path';
import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { getDatasetCollectionPathById, getDatasetCollections } from '@/web/core/dataset/api'; import { getDatasetCollectionPathById, getDatasetCollections } from '@/web/core/dataset/api';
import { Box, Flex, ModalFooter, Button, useTheme, Grid, Card, ModalBody } from '@chakra-ui/react'; import { Box, Flex, ModalFooter, Button, useTheme, Grid, Card, ModalBody } from '@chakra-ui/react';
@@ -114,7 +114,7 @@ const SelectCollections = ({
iconSrc="/imgs/modal/move.svg" iconSrc="/imgs/modal/move.svg"
title={ title={
<Box> <Box>
<ParentPaths <FolderPath
paths={paths.map((path) => ({ paths={paths.map((path) => ({
parentId: path.parentId, parentId: path.parentId,
parentName: path.parentName parentName: path.parentName