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 = ({
return (
<MyTooltip key={item.id} label={item.intro}>
<Flex
<Grid
overflow={'hidden'}
alignItems={'center'}
p={2.5}
gridTemplateColumns={'auto minmax(0, 1fr) auto'}
columnGap={2}
minW={0}
h={'46px'}
px={3}
py={0}
bg={'white'}
boxShadow={'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'}
borderRadius={'md'}
borderRadius={'6px'}
border={'base'}
borderColor={toolError ? 'red.600' : ''}
borderColor={toolError ? 'red.600' : 'myGray.200'}
userSelect={'none'}
_hover={{
borderColor: toolError ? 'red.600' : 'primary.300',
......@@ -107,66 +111,60 @@ const ToolSelect = ({
}
}}
>
<Avatar src={item.avatar} w={'1.5rem'} h={'1.5rem'} borderRadius={'sm'} />
<Box
flex={'1 0 0'}
ml={2}
gap={2}
className={'textEllipsis'}
fontSize={'sm'}
color={'myGray.900'}
>
<Avatar src={item.avatar} w={'28px'} h={'28px'} borderRadius={'sm'} />
<Box minW={0} className={'textEllipsis'} fontSize={'sm'} color={'myGray.900'}>
{item.name}
</Box>
{status !== undefined && status !== PluginStatusEnum.Normal && (
<MyTooltip label={t(PluginStatusMap[status].tooltip)}>
<MyTag
display={'block'}
className="unHoverStyle"
mr={2}
colorSchema={PluginStatusMap[status].tagColor}
type="borderFill"
>
{t(PluginStatusMap[status].label)}
<Flex gap={1} minW={0} justifySelf={'end'} alignItems={'center'}>
{status !== undefined && status !== PluginStatusEnum.Normal && (
<MyTooltip label={t(PluginStatusMap[status].tooltip)}>
<MyTag
display={'block'}
className="unHoverStyle"
colorSchema={PluginStatusMap[status].tagColor}
type="borderFill"
>
{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>
</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>
)}
{isUnconfigured && (
<MyTag colorSchema="blue" type="fill" className="unHoverStyle">
{t('app:wait_for_config')}
</MyTag>
)}
{/* Edit icon */}
{hasFormInput && !toolError && (
<MyIconButton
className="hoverStyle"
display={['flex', 'none']}
icon="common/setting"
onClick={() => setConfigTool(item)}
/>
)}
{/* Delete icon */}
<Box className="hoverStyle" display={['flex', 'none']} ml={0.5}>
<MyIconButton
icon="delete"
hoverBg="red.50"
hoverColor="red.600"
onClick={(e) => {
e.stopPropagation();
onRemoveTool(item.pluginId!);
}}
/>
</Box>
</Flex>
)}
{isUnconfigured && (
<MyTag colorSchema="blue" type="fill" className="unHoverStyle">
{t('app:wait_for_config')}
</MyTag>
)}
{/* Edit icon */}
{hasFormInput && !toolError && (
<MyIconButton
className="hoverStyle"
display={['flex', 'none']}
icon="common/setting"
onClick={() => setConfigTool(item)}
/>
)}
{/* Delete icon */}
<Box className="hoverStyle" display={['flex', 'none']}>
<MyIconButton
icon="delete"
hoverBg="red.50"
hoverColor="red.600"
onClick={(e) => {
e.stopPropagation();
onRemoveTool(item.pluginId!);
}}
/>
</Box>
</Flex>
</Grid>
</MyTooltip>
);
})}
......
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 { 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 { useRequest } from '@fastgpt/web/hooks/useRequest';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
......@@ -160,12 +160,18 @@ const ToolSelectModal = ({ onClose, ...props }: Props & { onClose: () => void })
return (
<MyModal
isOpen
title={t('app:tool_select')}
iconSrc="core/app/toolCall"
title={
<Flex alignItems={'center'} gap={2}>
<MyIcon name="core/app/toolCall" w={'18px'} color={'primary.600'} />
<Box>{t('app:tool_select')}</Box>
</Flex>
}
onClose={onClose}
size="lg"
maxW={['90vw', '700px']}
w={'700px'}
h={['90vh', '80vh']}
bodyStyles={{ p: 0, overflow: 'hidden' }}
>
{/* Header: row and search */}
<Box px={[3, 6]} pt={4} display={'flex'} justifyContent={'space-between'} w={'full'}>
......@@ -307,9 +313,19 @@ const RenderList = React.memo(function RenderList({
return (
<>
{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) => {
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 (
<MyTooltip
key={template.id}
......@@ -329,7 +345,7 @@ const RenderList = React.memo(function RenderList({
flex={'1 0 0'}
overflow={'hidden'}
>
{t(parseI18nString(template.name, i18n.language))}
{name}
</Box>
{isSystemTool && (
<Box color={'myGray.500'}>
......@@ -338,8 +354,7 @@ const RenderList = React.memo(function RenderList({
)}
</Flex>
<Box mt={2} color={'myGray.500'} maxH={'100px'} overflow={'hidden'}>
{t(parseI18nString(template.intro || '', i18n.language)) ||
t('common:core.workflow.Not intro')}
{intro}
</Box>
{isSystemTool && (
<CostTooltip
......@@ -350,8 +365,12 @@ const RenderList = React.memo(function RenderList({
</Box>
}
>
<Flex
<Grid
alignItems={'center'}
gridTemplateColumns={'auto minmax(0, 1fr) auto'}
columnGap={2}
minW={0}
minH={'54px'}
py={3}
px={3}
_hover={{ bg: 'myWhite.600' }}
......@@ -365,79 +384,89 @@ const RenderList = React.memo(function RenderList({
borderRadius={'sm'}
flexShrink={0}
/>
<Box flex={'1 0 0'} ml={3}>
<Box minW={0}>
<Box
color={'myGray.900'}
fontWeight={'500'}
fontSize={'sm'}
className="textEllipsis"
>
{t(parseI18nString(template.name, i18n.language))}
{name}
</Box>
</Box>
<Box flex={1} />
{selected ? (
<Button
size={'sm'}
variant={'grayDanger'}
leftIcon={<MyIcon name={'delete'} w={'16px'} mr={-1} />}
onClick={() => onRemoveTool(template)}
px={2}
fontSize={'mini'}
>
{t('common:Remove')}
</Button>
) : template.flowNodeType === 'toolSet' ? (
<Flex gap={2}>
<Flex gap={2} minW={0} justifySelf={'end'} alignItems={'center'}>
{selected ? (
<IconButton
aria-label={t('common:Remove')}
size={'xsSquare'}
color={'myGray.600'}
minW={'24px'}
w={'24px'}
h={'24px'}
variant={'whiteDanger'}
icon={<MyIcon name={'delete'} w={'13px'} />}
onClick={() => onRemoveTool(template)}
/>
) : template.flowNodeType === 'toolSet' ? (
<>
<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
size={'sm'}
size={'xs'}
variant={'whiteBase'}
h={'24px'}
minW={'unset'}
px={2}
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)}
px={2}
fontSize={'mini'}
fontWeight={'500'}
>
{t('common:Open')}
</Button>
<Button
size={'sm'}
variant={'primaryOutline'}
leftIcon={<MyIcon name={'common/addLight'} w={'16px'} mr={-1.5} />}
) : (
<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)}
px={2}
fontSize={'mini'}
>
{t('common:Add')}
</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>
/>
)}
</Flex>
</Grid>
</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