Commit 4f30121d by Finley Ge Committed by GitHub

refactor(app): optimize tool selector UI/UX (#7127)

Refactor tool selector and modal layout to improve responsiveness and
consistency. Update grid structures, adjust padding and sizing, and
streamline component interaction flows.
parent 2a715bcc
...@@ -84,15 +84,19 @@ const ToolSelect = ({ ...@@ -84,15 +84,19 @@ const ToolSelect = ({
return ( return (
<MyTooltip key={item.id} label={item.intro}> <MyTooltip key={item.id} label={item.intro}>
<Flex <Grid
overflow={'hidden'} overflow={'hidden'}
alignItems={'center'} alignItems={'center'}
p={2.5} gridTemplateColumns={'auto minmax(0, 1fr) auto'}
columnGap={2}
minW={0}
h={'46px'}
px={3}
py={0}
bg={'white'} bg={'white'}
boxShadow={'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'} borderRadius={'6px'}
borderRadius={'md'}
border={'base'} border={'base'}
borderColor={toolError ? 'red.600' : ''} borderColor={toolError ? 'red.600' : 'myGray.200'}
userSelect={'none'} userSelect={'none'}
_hover={{ _hover={{
borderColor: toolError ? 'red.600' : 'primary.300', borderColor: toolError ? 'red.600' : 'primary.300',
...@@ -107,24 +111,17 @@ const ToolSelect = ({ ...@@ -107,24 +111,17 @@ const ToolSelect = ({
} }
}} }}
> >
<Avatar src={item.avatar} w={'1.5rem'} h={'1.5rem'} borderRadius={'sm'} /> <Avatar src={item.avatar} w={'28px'} h={'28px'} borderRadius={'sm'} />
<Box <Box minW={0} className={'textEllipsis'} fontSize={'sm'} color={'myGray.900'}>
flex={'1 0 0'}
ml={2}
gap={2}
className={'textEllipsis'}
fontSize={'sm'}
color={'myGray.900'}
>
{item.name} {item.name}
</Box> </Box>
<Flex gap={1} minW={0} justifySelf={'end'} alignItems={'center'}>
{status !== undefined && status !== PluginStatusEnum.Normal && ( {status !== undefined && status !== PluginStatusEnum.Normal && (
<MyTooltip label={t(PluginStatusMap[status].tooltip)}> <MyTooltip label={t(PluginStatusMap[status].tooltip)}>
<MyTag <MyTag
display={'block'} display={'block'}
className="unHoverStyle" className="unHoverStyle"
mr={2}
colorSchema={PluginStatusMap[status].tagColor} colorSchema={PluginStatusMap[status].tagColor}
type="borderFill" type="borderFill"
> >
...@@ -155,7 +152,7 @@ const ToolSelect = ({ ...@@ -155,7 +152,7 @@ const ToolSelect = ({
/> />
)} )}
{/* Delete icon */} {/* Delete icon */}
<Box className="hoverStyle" display={['flex', 'none']} ml={0.5}> <Box className="hoverStyle" display={['flex', 'none']}>
<MyIconButton <MyIconButton
icon="delete" icon="delete"
hoverBg="red.50" hoverBg="red.50"
...@@ -167,6 +164,7 @@ const ToolSelect = ({ ...@@ -167,6 +164,7 @@ const ToolSelect = ({
/> />
</Box> </Box>
</Flex> </Flex>
</Grid>
</MyTooltip> </MyTooltip>
); );
})} })}
......
import React, { useCallback, useState, useMemo } from 'react'; import React, { useCallback, useState, useMemo } from 'react';
import MyModal from '@fastgpt/web/components/common/MyModal'; import MyModal from '@fastgpt/web/components/v2/common/MyModal';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { parseI18nString } from '@fastgpt/global/common/i18n/utils'; import { parseI18nString } from '@fastgpt/global/common/i18n/utils';
import { Box, Button, Flex, Grid } from '@chakra-ui/react'; import { Box, Button, Flex, Grid, IconButton } from '@chakra-ui/react';
import FillRowTabs from '@fastgpt/web/components/common/Tabs/FillRowTabs'; import FillRowTabs from '@fastgpt/web/components/common/Tabs/FillRowTabs';
import { useRequest } from '@fastgpt/web/hooks/useRequest'; import { useRequest } from '@fastgpt/web/hooks/useRequest';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip'; import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
...@@ -160,12 +160,18 @@ const ToolSelectModal = ({ onClose, ...props }: Props & { onClose: () => void }) ...@@ -160,12 +160,18 @@ const ToolSelectModal = ({ onClose, ...props }: Props & { onClose: () => void })
return ( return (
<MyModal <MyModal
isOpen isOpen
title={t('app:tool_select')} title={
iconSrc="core/app/toolCall" <Flex alignItems={'center'} gap={2}>
<MyIcon name="core/app/toolCall" w={'18px'} color={'primary.600'} />
<Box>{t('app:tool_select')}</Box>
</Flex>
}
onClose={onClose} onClose={onClose}
size="lg"
maxW={['90vw', '700px']} maxW={['90vw', '700px']}
w={'700px'} w={'700px'}
h={['90vh', '80vh']} h={['90vh', '80vh']}
bodyStyles={{ p: 0, overflow: 'hidden' }}
> >
{/* Header: row and search */} {/* Header: row and search */}
<Box px={[3, 6]} pt={4} display={'flex'} justifyContent={'space-between'} w={'full'}> <Box px={[3, 6]} pt={4} display={'flex'} justifyContent={'space-between'} w={'full'}>
...@@ -307,9 +313,19 @@ const RenderList = React.memo(function RenderList({ ...@@ -307,9 +313,19 @@ const RenderList = React.memo(function RenderList({
return ( return (
<> <>
{templates.length > 0 ? ( {templates.length > 0 ? (
<Grid gridTemplateColumns={['1fr', '1fr 1fr']} gap={3} px={[3, 6]}> <Grid
gridTemplateColumns={['minmax(0, 1fr)', 'repeat(2, minmax(0, 1fr))']}
columnGap={3}
rowGap={3}
px={[3, 6]}
>
{templates.map((template) => { {templates.map((template) => {
const selected = selectedTools.some((tool) => tool.pluginId === template.id); const selected = selectedTools.some((tool) => tool.pluginId === template.id);
const name = t(parseI18nString(template.name, i18n.language));
const intro =
t(parseI18nString(template.intro || '', i18n.language)) ||
t('common:core.workflow.Not intro');
return ( return (
<MyTooltip <MyTooltip
key={template.id} key={template.id}
...@@ -329,7 +345,7 @@ const RenderList = React.memo(function RenderList({ ...@@ -329,7 +345,7 @@ const RenderList = React.memo(function RenderList({
flex={'1 0 0'} flex={'1 0 0'}
overflow={'hidden'} overflow={'hidden'}
> >
{t(parseI18nString(template.name, i18n.language))} {name}
</Box> </Box>
{isSystemTool && ( {isSystemTool && (
<Box color={'myGray.500'}> <Box color={'myGray.500'}>
...@@ -338,8 +354,7 @@ const RenderList = React.memo(function RenderList({ ...@@ -338,8 +354,7 @@ const RenderList = React.memo(function RenderList({
)} )}
</Flex> </Flex>
<Box mt={2} color={'myGray.500'} maxH={'100px'} overflow={'hidden'}> <Box mt={2} color={'myGray.500'} maxH={'100px'} overflow={'hidden'}>
{t(parseI18nString(template.intro || '', i18n.language)) || {intro}
t('common:core.workflow.Not intro')}
</Box> </Box>
{isSystemTool && ( {isSystemTool && (
<CostTooltip <CostTooltip
...@@ -350,8 +365,12 @@ const RenderList = React.memo(function RenderList({ ...@@ -350,8 +365,12 @@ const RenderList = React.memo(function RenderList({
</Box> </Box>
} }
> >
<Flex <Grid
alignItems={'center'} alignItems={'center'}
gridTemplateColumns={'auto minmax(0, 1fr) auto'}
columnGap={2}
minW={0}
minH={'54px'}
py={3} py={3}
px={3} px={3}
_hover={{ bg: 'myWhite.600' }} _hover={{ bg: 'myWhite.600' }}
...@@ -365,79 +384,89 @@ const RenderList = React.memo(function RenderList({ ...@@ -365,79 +384,89 @@ const RenderList = React.memo(function RenderList({
borderRadius={'sm'} borderRadius={'sm'}
flexShrink={0} flexShrink={0}
/> />
<Box flex={'1 0 0'} ml={3}> <Box minW={0}>
<Box <Box
color={'myGray.900'} color={'myGray.900'}
fontWeight={'500'} fontWeight={'500'}
fontSize={'sm'} fontSize={'sm'}
className="textEllipsis" className="textEllipsis"
> >
{t(parseI18nString(template.name, i18n.language))} {name}
</Box> </Box>
</Box> </Box>
<Box flex={1} /> <Flex gap={2} minW={0} justifySelf={'end'} alignItems={'center'}>
{selected ? ( {selected ? (
<Button <IconButton
size={'sm'} aria-label={t('common:Remove')}
variant={'grayDanger'} size={'xsSquare'}
leftIcon={<MyIcon name={'delete'} w={'16px'} mr={-1} />} color={'myGray.600'}
minW={'24px'}
w={'24px'}
h={'24px'}
variant={'whiteDanger'}
icon={<MyIcon name={'delete'} w={'13px'} />}
onClick={() => onRemoveTool(template)} onClick={() => onRemoveTool(template)}
px={2} />
fontSize={'mini'}
>
{t('common:Remove')}
</Button>
) : template.flowNodeType === 'toolSet' ? ( ) : template.flowNodeType === 'toolSet' ? (
<Flex gap={2}> <>
<Button <Button
size={'sm'} size={'xs'}
variant={'whiteBase'} variant={'whiteBase'}
h={'24px'}
minW={'unset'}
px={2}
isLoading={isLoading} isLoading={isLoading}
leftIcon={<MyIcon name={'common/arrowRight'} w={'16px'} mr={-1.5} />} leftIcon={<MyIcon name={'common/arrowRight'} w={'14px'} />}
iconSpacing={1}
onClick={() => setParentId(template.id)} onClick={() => setParentId(template.id)}
px={2}
fontSize={'mini'} fontSize={'mini'}
fontWeight={'500'}
> >
{t('common:Open')} {t('common:Open')}
</Button> </Button>
<Button <IconButton
size={'sm'} aria-label={t('common:Add')}
variant={'primaryOutline'} size={'xsSquare'}
leftIcon={<MyIcon name={'common/addLight'} w={'16px'} mr={-1.5} />} minW={'24px'}
w={'24px'}
h={'24px'}
variant={'whiteBase'}
icon={<MyIcon name={'common/addLight'} w={'13px'} />}
isLoading={isLoading} isLoading={isLoading}
onClick={() => onClickAdd(template)} onClick={() => onClickAdd(template)}
px={2} />
fontSize={'mini'} </>
>
{t('common:Add')}
</Button>
</Flex>
) : template.isFolder ? ( ) : template.isFolder ? (
<Button <Button
size={'sm'} size={'xs'}
variant={'whiteBase'} variant={'whiteBase'}
leftIcon={<MyIcon name={'common/arrowRight'} w={'16px'} mr={-1.5} />} h={'24px'}
onClick={() => setParentId(template.id)} minW={'unset'}
px={2} px={2}
isLoading={isLoading}
leftIcon={<MyIcon name={'common/arrowRight'} w={'14px'} />}
iconSpacing={1}
onClick={() => setParentId(template.id)}
fontSize={'mini'} fontSize={'mini'}
fontWeight={'500'}
> >
{t('common:Open')} {t('common:Open')}
</Button> </Button>
) : ( ) : (
<Button <IconButton
size={'sm'} aria-label={t('common:Add')}
variant={'primaryOutline'} size={'xsSquare'}
leftIcon={<MyIcon name={'common/addLight'} w={'16px'} mr={-1.5} />} minW={'24px'}
w={'24px'}
h={'24px'}
variant={'whiteBase'}
icon={<MyIcon name={'common/addLight'} w={'13px'} />}
isLoading={isLoading} isLoading={isLoading}
onClick={() => onClickAdd(template)} onClick={() => onClickAdd(template)}
px={2} />
fontSize={'mini'}
>
{t('common:Add')}
</Button>
)} )}
</Flex> </Flex>
</Grid>
</MyTooltip> </MyTooltip>
); );
})} })}
......
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