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,66 +111,60 @@ const ToolSelect = ({ ...@@ -107,66 +111,60 @@ 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>
{status !== undefined && status !== PluginStatusEnum.Normal && ( <Flex gap={1} minW={0} justifySelf={'end'} alignItems={'center'}>
<MyTooltip label={t(PluginStatusMap[status].tooltip)}> {status !== undefined && status !== PluginStatusEnum.Normal && (
<MyTag <MyTooltip label={t(PluginStatusMap[status].tooltip)}>
display={'block'} <MyTag
className="unHoverStyle" display={'block'}
mr={2} className="unHoverStyle"
colorSchema={PluginStatusMap[status].tagColor} colorSchema={PluginStatusMap[status].tagColor}
type="borderFill" type="borderFill"
> >
{t(PluginStatusMap[status].label)} {t(PluginStatusMap[status].label)}
</MyTag>
</MyTooltip>
)}
{toolError && (
<MyTag colorSchema="red" type="fill" className="unHoverStyle">
<MyIcon name={'common/error'} w={'14px'} mr={1} />
<Box color={'red.600'} maxW={'150px'} className="textEllipsis">
{t(toolError as any)}
</Box>
</MyTag> </MyTag>
</MyTooltip> )}
)} {isUnconfigured && (
{toolError && ( <MyTag colorSchema="blue" type="fill" className="unHoverStyle">
<MyTag colorSchema="red" type="fill" className="unHoverStyle"> {t('app:wait_for_config')}
<MyIcon name={'common/error'} w={'14px'} mr={1} /> </MyTag>
<Box color={'red.600'} maxW={'150px'} className="textEllipsis"> )}
{t(toolError as any)} {/* Edit icon */}
</Box> {hasFormInput && !toolError && (
</MyTag> <MyIconButton
)} className="hoverStyle"
{isUnconfigured && ( display={['flex', 'none']}
<MyTag colorSchema="blue" type="fill" className="unHoverStyle"> icon="common/setting"
{t('app:wait_for_config')} onClick={() => setConfigTool(item)}
</MyTag> />
)} )}
{/* Edit icon */} {/* Delete icon */}
{hasFormInput && !toolError && ( <Box className="hoverStyle" display={['flex', 'none']}>
<MyIconButton <MyIconButton
className="hoverStyle" icon="delete"
display={['flex', 'none']} hoverBg="red.50"
icon="common/setting" hoverColor="red.600"
onClick={() => setConfigTool(item)} onClick={(e) => {
/> e.stopPropagation();
)} onRemoveTool(item.pluginId!);
{/* Delete icon */} }}
<Box className="hoverStyle" display={['flex', 'none']} ml={0.5}> />
<MyIconButton </Box>
icon="delete" </Flex>
hoverBg="red.50" </Grid>
hoverColor="red.600"
onClick={(e) => {
e.stopPropagation();
onRemoveTool(item.pluginId!);
}}
/>
</Box>
</Flex>
</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 ? ( <IconButton
<Button aria-label={t('common:Remove')}
size={'sm'} size={'xsSquare'}
variant={'grayDanger'} color={'myGray.600'}
leftIcon={<MyIcon name={'delete'} w={'16px'} mr={-1} />} minW={'24px'}
onClick={() => onRemoveTool(template)} w={'24px'}
px={2} h={'24px'}
fontSize={'mini'} variant={'whiteDanger'}
> icon={<MyIcon name={'delete'} w={'13px'} />}
{t('common:Remove')} onClick={() => onRemoveTool(template)}
</Button> />
) : template.flowNodeType === 'toolSet' ? ( ) : template.flowNodeType === 'toolSet' ? (
<Flex gap={2}> <>
<Button
size={'xs'}
variant={'whiteBase'}
h={'24px'}
minW={'unset'}
px={2}
isLoading={isLoading}
leftIcon={<MyIcon name={'common/arrowRight'} w={'14px'} />}
iconSpacing={1}
onClick={() => setParentId(template.id)}
fontSize={'mini'}
fontWeight={'500'}
>
{t('common:Open')}
</Button>
<IconButton
aria-label={t('common:Add')}
size={'xsSquare'}
minW={'24px'}
w={'24px'}
h={'24px'}
variant={'whiteBase'}
icon={<MyIcon name={'common/addLight'} w={'13px'} />}
isLoading={isLoading}
onClick={() => onClickAdd(template)}
/>
</>
) : template.isFolder ? (
<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 ) : (
size={'sm'} <IconButton
variant={'primaryOutline'} aria-label={t('common:Add')}
leftIcon={<MyIcon name={'common/addLight'} w={'16px'} mr={-1.5} />} size={'xsSquare'}
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'} )}
> </Flex>
{t('common:Add')} </Grid>
</Button>
</Flex>
) : template.isFolder ? (
<Button
size={'sm'}
variant={'whiteBase'}
leftIcon={<MyIcon name={'common/arrowRight'} w={'16px'} mr={-1.5} />}
onClick={() => setParentId(template.id)}
px={2}
fontSize={'mini'}
>
{t('common:Open')}
</Button>
) : (
<Button
size={'sm'}
variant={'primaryOutline'}
leftIcon={<MyIcon name={'common/addLight'} w={'16px'} mr={-1.5} />}
isLoading={isLoading}
onClick={() => onClickAdd(template)}
px={2}
fontSize={'mini'}
>
{t('common:Add')}
</Button>
)}
</Flex>
</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