perf: confirm ux (#4843)

* perf: delete tip ux

* perf: confirm ux
This commit is contained in:
Archer
2025-05-20 13:41:56 +08:00
committed by GitHub
parent 1dac2b70ec
commit d44c338059
18 changed files with 309 additions and 391 deletions

View File

@@ -15,6 +15,7 @@ weight: 790
## ⚙️ 优化 ## ⚙️ 优化
1. LLM stream调用默认超时调大。 1. LLM stream调用默认超时调大。
2. 部分确认交互优化。
## 🐛 修复 ## 🐛 修复

View File

@@ -11,15 +11,16 @@ import {
HStack, HStack,
Box, Box,
Button, Button,
PopoverArrow PopoverArrow,
Portal
} from '@chakra-ui/react'; } from '@chakra-ui/react';
const PopoverConfirm = ({ const PopoverConfirm = ({
content, content,
showCancel, showCancel = true,
type, type,
Trigger, Trigger,
placement = 'bottom-start', placement = 'auto',
offset, offset,
onConfirm, onConfirm,
confirmText, confirmText,
@@ -50,7 +51,7 @@ const PopoverConfirm = ({
}; };
if (type && map[type]) return map[type]; if (type && map[type]) return map[type];
return map.info; return map.info;
}, [type, t]); }, [type]);
const firstFieldRef = React.useRef(null); const firstFieldRef = React.useRef(null);
const { onOpen, onClose, isOpen } = useDisclosure(); const { onOpen, onClose, isOpen } = useDisclosure();
@@ -67,7 +68,7 @@ const PopoverConfirm = ({
onClose={onClose} onClose={onClose}
placement={placement} placement={placement}
offset={offset} offset={offset}
closeOnBlur={false} closeOnBlur={true}
trigger={'click'} trigger={'click'}
openDelay={100} openDelay={100}
closeDelay={100} closeDelay={100}
@@ -75,6 +76,7 @@ const PopoverConfirm = ({
lazyBehavior="keepMounted" lazyBehavior="keepMounted"
arrowSize={10} arrowSize={10}
strategy={'fixed'} strategy={'fixed'}
computePositionOnMount={true}
> >
<PopoverTrigger>{Trigger}</PopoverTrigger> <PopoverTrigger>{Trigger}</PopoverTrigger>
<PopoverContent p={4}> <PopoverContent p={4}>
@@ -82,15 +84,25 @@ const PopoverConfirm = ({
<HStack alignItems={'flex-start'} color={'myGray.700'}> <HStack alignItems={'flex-start'} color={'myGray.700'}>
<MyIcon name={map.icon as any} w={'1.5rem'} /> <MyIcon name={map.icon as any} w={'1.5rem'} />
<Box fontSize={'sm'}>{content}</Box> <Box fontSize={'sm'} whiteSpace={'pre-wrap'}>
{content}
</Box>
</HStack> </HStack>
<HStack mt={1} justifyContent={'flex-end'}> <HStack mt={2} justifyContent={'flex-end'}>
{showCancel && ( {showCancel && (
<Button variant={'whiteBase'} size="sm" onClick={onClose}> <Button variant={'whiteBase'} size="sm" onClick={onClose}>
{cancelText || t('common:Cancel')} {cancelText || t('common:Cancel')}
</Button> </Button>
)} )}
<Button isLoading={loading} variant={map.variant} size="sm" onClick={onclickConfirm}> <Button
isLoading={loading}
variant={map.variant}
size="sm"
onClick={async (e) => {
e.stopPropagation();
await onclickConfirm();
}}
>
{confirmText || t('common:Confirm')} {confirmText || t('common:Confirm')}
</Button> </Button>
</HStack> </HStack>

View File

@@ -221,7 +221,8 @@ const Button = defineStyleConfig({
boxShadow: '0px 0px 1px 0px rgba(19, 51, 107, 0.08), 0px 1px 2px 0px rgba(19, 51, 107, 0.05)', boxShadow: '0px 0px 1px 0px rgba(19, 51, 107, 0.08), 0px 1px 2px 0px rgba(19, 51, 107, 0.05)',
_hover: { _hover: {
color: 'red.600', color: 'red.600',
borderColor: 'red.300' borderColor: 'red.300',
bg: 'red.50'
}, },
_active: { _active: {
color: 'red.600' color: 'red.600'
@@ -281,11 +282,11 @@ const Button = defineStyleConfig({
bg: 'transparent', bg: 'transparent',
transition: 'background 0.1s', transition: 'background 0.1s',
_hover: { _hover: {
bg: 'myGray.150', bg: 'red.50',
color: 'red.600' color: 'red.600'
}, },
_active: { _active: {
bg: 'myGray.150' bg: 'red.50'
}, },
_disabled: { _disabled: {
color: 'myGray.800 !important' color: 'myGray.800 !important'

View File

@@ -5,14 +5,13 @@ import { FolderIcon } from '@fastgpt/global/common/file/image/constants';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import MyDivider from '@fastgpt/web/components/common/MyDivider'; import MyDivider from '@fastgpt/web/components/common/MyDivider';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { type PermissionValueType } from '@fastgpt/global/support/permission/type';
import CollaboratorContextProvider, { import CollaboratorContextProvider, {
type MemberManagerInputPropsType type MemberManagerInputPropsType
} from '../../support/permission/MemberManager/context'; } from '../../support/permission/MemberManager/context';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useSystemStore } from '@/web/common/system/useSystemStore';
import ResumeInherit from '@/components/support/permission/ResumeInheritText'; import ResumeInherit from '@/components/support/permission/ResumeInheritText';
import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm';
const FolderSlideCard = ({ const FolderSlideCard = ({
refreshDeps, refreshDeps,
@@ -47,11 +46,6 @@ const FolderSlideCard = ({
const { t } = useTranslation(); const { t } = useTranslation();
const { feConfigs } = useSystemStore(); const { feConfigs } = useSystemStore();
const { ConfirmModal, openConfirm } = useConfirm({
type: 'delete',
content: deleteTip
});
return ( return (
<Box w={'13rem'}> <Box w={'13rem'}>
<Box> <Box>
@@ -93,22 +87,26 @@ const FolderSlideCard = ({
{t('common:Move')} {t('common:Move')}
</Button> </Button>
{managePer.permission.isOwner && ( {managePer.permission.isOwner && (
<Button <PopoverConfirm
variant={'transparentDanger'} Trigger={
pl={1} <Button
leftIcon={<MyIcon name={'delete'} w={'1rem'} />} variant={'transparentDanger'}
transform={'none !important'} pl={1}
w={'100%'} leftIcon={<MyIcon name={'delete'} w={'1rem'} />}
justifyContent={'flex-start'} transform={'none !important'}
size={'sm'} w={'100%'}
fontSize={'mini'} justifyContent={'flex-start'}
mt={3} size={'sm'}
onClick={() => { fontSize={'mini'}
openConfirm(onDelete)(); mt={3}
}} >
> {t('common:delete_folder')}
{t('common:delete_folder')} </Button>
</Button> }
type="delete"
content={deleteTip}
onConfirm={onDelete}
/>
)} )}
</Box> </Box>
</> </>
@@ -177,8 +175,6 @@ const FolderSlideCard = ({
</Box> </Box>
</> </>
)} )}
<ConfirmModal />
</Box> </Box>
); );
}; };

View File

@@ -37,7 +37,7 @@ import HighlightText from '@fastgpt/web/components/common/String/HighlightText';
import { defaultChatInputGuideConfig } from '@fastgpt/global/core/app/constants'; import { defaultChatInputGuideConfig } from '@fastgpt/global/core/app/constants';
import ChatFunctionTip from './Tip'; import ChatFunctionTip from './Tip';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm';
const csvTemplate = `"第一列内容" const csvTemplate = `"第一列内容"
"只会将第一列内容导入,其余列会被忽略" "只会将第一列内容导入,其余列会被忽略"
@@ -191,10 +191,6 @@ const LexiconConfigModal = ({ appId, onClose }: { appId: string; onClose: () =>
const [searchKey, setSearchKey] = useState(''); const [searchKey, setSearchKey] = useState('');
const { openConfirm: openConfirmDel, ConfirmModal: DelConfirmModal } = useConfirm({
type: 'delete'
});
const { const {
scrollDataList, scrollDataList,
setData, setData,
@@ -355,24 +351,26 @@ const LexiconConfigModal = ({ appId, onClose }: { appId: string; onClose: () =>
> >
{t('common:Delete')} {t('common:Delete')}
</Button> </Button>
<Button
variant={'whiteBase'} <PopoverConfirm
display={selectedRows.length !== 0 ? 'none' : 'flex'} Trigger={
size={'sm'} <Button
leftIcon={<MyIcon name={'delete'} boxSize={4} />} variant={'whiteBase'}
onClick={() => display={selectedRows.length !== 0 ? 'none' : 'flex'}
openConfirmDel( size={'sm'}
() => { leftIcon={<MyIcon name={'delete'} boxSize={4} />}
onDeleteAllData(); >
setSelectedRows([]); {t('chat:Delete_all')}
}, </Button>
undefined,
t('chat:delete_all_input_guide_confirm')
)()
} }
> type="delete"
{t('chat:Delete_all')} content={t('chat:delete_all_input_guide_confirm')}
</Button> onConfirm={() => {
onDeleteAllData();
setSelectedRows([]);
}}
/>
<Button <Button
display={selectedRows.length !== 0 ? 'none' : 'flex'} display={selectedRows.length !== 0 ? 'none' : 'flex'}
onClick={() => { onClick={() => {
@@ -504,7 +502,6 @@ const LexiconConfigModal = ({ appId, onClose }: { appId: string; onClose: () =>
})} })}
</ScrollList> </ScrollList>
<DelConfirmModal />
<File onSelect={onSelectFile} /> <File onSelect={onSelectFile} />
</MyModal> </MyModal>
); );

View File

@@ -41,7 +41,6 @@ import {
} from '@/web/core/ai/config'; } from '@/web/core/ai/config';
import MyBox from '@fastgpt/web/components/common/MyBox'; import MyBox from '@fastgpt/web/components/common/MyBox';
import { type SystemModelItemType } from '@fastgpt/service/core/ai/type'; import { type SystemModelItemType } from '@fastgpt/service/core/ai/type';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import MyIconButton from '@fastgpt/web/components/common/Icon/button'; import MyIconButton from '@fastgpt/web/components/common/Icon/button';
import JsonEditor from '@fastgpt/web/components/common/Textarea/JsonEditor'; import JsonEditor from '@fastgpt/web/components/common/Textarea/JsonEditor';
import { clientInitData } from '@/web/common/system/staticData'; import { clientInitData } from '@/web/common/system/staticData';
@@ -54,6 +53,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
import AIModelSelector from '@/components/Select/AIModelSelector'; import AIModelSelector from '@/components/Select/AIModelSelector';
import MyDivider from '@fastgpt/web/components/common/MyDivider'; import MyDivider from '@fastgpt/web/components/common/MyDivider';
import { AddModelButton } from './AddModelBox'; import { AddModelButton } from './AddModelBox';
import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm';
const MyModal = dynamic(() => import('@fastgpt/web/components/common/MyModal')); const MyModal = dynamic(() => import('@fastgpt/web/components/common/MyModal'));
const ModelEditModal = dynamic(() => import('./AddModelBox').then((mod) => mod.ModelEditModal)); const ModelEditModal = dynamic(() => import('./AddModelBox').then((mod) => mod.ModelEditModal));
@@ -260,10 +260,6 @@ const ModelTable = ({ Tab }: { Tab: React.ReactNode }) => {
onSuccess: refreshModels onSuccess: refreshModels
}); });
const { ConfirmModal, openConfirm } = useConfirm({
type: 'delete',
content: t('account:model.delete_model_confirm')
});
const { runAsync: deleteModel } = useRequest2(deleteSystemModel, { const { runAsync: deleteModel } = useRequest2(deleteSystemModel, {
onSuccess: refreshModels onSuccess: refreshModels
}); });
@@ -459,10 +455,15 @@ const ModelTable = ({ Tab }: { Tab: React.ReactNode }) => {
onClick={() => onEditModel(item.model)} onClick={() => onEditModel(item.model)}
/> />
{item.isCustom && ( {item.isCustom && (
<MyIconButton <PopoverConfirm
icon={'delete'} Trigger={
hoverColor={'red.500'} <Box>
onClick={() => openConfirm(() => deleteModel({ model: item.model }))()} <MyIconButton icon={'delete'} hoverColor={'red.500'} />
</Box>
}
type="delete"
content={t('account:model.delete_model_confirm')}
onConfirm={() => deleteModel({ model: item.model })}
/> />
)} )}
</HStack> </HStack>
@@ -475,7 +476,6 @@ const ModelTable = ({ Tab }: { Tab: React.ReactNode }) => {
</Flex> </Flex>
</MyBox> </MyBox>
<ConfirmModal />
{!!editModelData && ( {!!editModelData && (
<ModelEditModal <ModelEditModal
modelData={editModelData} modelData={editModelData}
@@ -510,9 +510,6 @@ const JsonConfigModal = ({
} }
}); });
const { openConfirm, ConfirmModal } = useConfirm({
content: t('account:model.json_config_confirm')
});
const { runAsync } = useRequest2(putUpdateWithJson, { const { runAsync } = useRequest2(putUpdateWithJson, {
onSuccess: () => { onSuccess: () => {
onSuccess(); onSuccess();
@@ -542,18 +539,14 @@ const JsonConfigModal = ({
<Button variant={'whiteBase'} mr={4} onClick={onClose}> <Button variant={'whiteBase'} mr={4} onClick={onClose}>
{t('common:Cancel')} {t('common:Cancel')}
</Button> </Button>
<Button
onClick={() =>
openConfirm(() => {
return runAsync({ config: data });
})()
}
>
{t('common:Confirm')}
</Button>
</ModalFooter>
<ConfirmModal /> <PopoverConfirm
Trigger={<Button>{t('common:Confirm')}</Button>}
type="info"
content={t('account:model.json_config_confirm')}
onConfirm={() => runAsync({ config: data })}
/>
</ModalFooter>
</MyModal> </MyModal>
); );
}; };

View File

@@ -16,7 +16,6 @@ import {
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useUserStore } from '@/web/support/user/useUserStore'; import { useUserStore } from '@/web/support/user/useUserStore';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { import {
delRemoveMember, delRemoveMember,
getTeamMembers, getTeamMembers,
@@ -50,6 +49,8 @@ import { type PaginationResponse } from '@fastgpt/web/common/fetch/type';
import _ from 'lodash'; import _ from 'lodash';
import MySelect from '@fastgpt/web/components/common/MySelect'; import MySelect from '@fastgpt/web/components/common/MySelect';
import { useEditTitle } from '@/web/common/hooks/useEditTitle'; import { useEditTitle } from '@/web/common/hooks/useEditTitle';
import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm';
import MyIconButton from '@fastgpt/web/components/common/Icon/button';
const InviteModal = dynamic(() => import('./Invite/InviteModal')); const InviteModal = dynamic(() => import('./Invite/InviteModal'));
const TeamTagModal = dynamic(() => import('@/components/support/user/team/TeamTagModal')); const TeamTagModal = dynamic(() => import('@/components/support/user/team/TeamTagModal'));
@@ -121,9 +122,6 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
errorToast: t('account_team:sync_member_failed') errorToast: t('account_team:sync_member_failed')
}); });
const { ConfirmModal: ConfirmLeaveTeamModal, openConfirm: openLeaveConfirm } = useConfirm({
content: t('account_team:confirm_leave_team')
});
const { runAsync: onLeaveTeam } = useRequest2(delLeaveTeam, { const { runAsync: onLeaveTeam } = useRequest2(delLeaveTeam, {
onSuccess() { onSuccess() {
const defaultTeam = myTeams[0]; const defaultTeam = myTeams[0];
@@ -132,19 +130,10 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
errorToast: t('account_team:user_team_leave_team_failed') errorToast: t('account_team:user_team_leave_team_failed')
}); });
const { ConfirmModal: ConfirmRemoveMemberModal, openConfirm: openRemoveMember } = useConfirm({
type: 'delete'
});
const { runAsync: onRemoveMember } = useRequest2(delRemoveMember, { const { runAsync: onRemoveMember } = useRequest2(delRemoveMember, {
onSuccess: onRefreshMembers onSuccess: onRefreshMembers
}); });
const { ConfirmModal: ConfirmRestoreMemberModal, openConfirm: openRestoreMember } = useConfirm({
type: 'common',
title: t('account_team:restore_tip_title'),
iconSrc: 'common/confirm/restoreTip',
iconColor: 'primary.500'
});
const { runAsync: onRestore } = useRequest2(postRestoreMember, { const { runAsync: onRestore } = useRequest2(postRestoreMember, {
onSuccess: onRefreshMembers, onSuccess: onRefreshMembers,
successToast: t('common:Success'), successToast: t('common:Success'),
@@ -247,16 +236,22 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
</Button> </Button>
)} )}
{!userInfo?.team.permission.isOwner && ( {!userInfo?.team.permission.isOwner && (
<Button <PopoverConfirm
variant={'whitePrimary'} Trigger={
size="md" <Button
borderRadius={'md'} variant={'whitePrimary'}
ml={3} size="md"
leftIcon={<MyIcon name={'support/account/loginoutLight'} w={'14px'} />} borderRadius={'md'}
onClick={() => openLeaveConfirm(onLeaveTeam)()} ml={3}
> leftIcon={<MyIcon name={'support/account/loginoutLight'} w={'14px'} />}
{t('account_team:user_team_leave_team')} >
</Button> {t('account_team:user_team_leave_team')}
</Button>
}
type="delete"
content={t('account_team:confirm_leave_team')}
onConfirm={() => onLeaveTeam()}
/>
)} )}
</HStack> </HStack>
</Flex> </Flex>
@@ -317,62 +312,48 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
member.role !== TeamMemberRoleEnum.owner && member.role !== TeamMemberRoleEnum.owner &&
member.tmbId !== userInfo?.team.tmbId && member.tmbId !== userInfo?.team.tmbId &&
(member.status === TeamMemberStatusEnum.active ? ( (member.status === TeamMemberStatusEnum.active ? (
<> <HStack>
<Icon <MyIconButton
mr={2} icon={'edit'}
name={'edit'} size="1rem"
cursor={'pointer'} hoverColor={'blue.500'}
w="1rem"
p="1"
borderRadius="sm"
_hover={{
color: 'blue.600',
bgColor: 'myGray.100'
}}
onClick={() => handleEditMemberName(member.tmbId, member.memberName)} onClick={() => handleEditMemberName(member.tmbId, member.memberName)}
/> />
<Icon <PopoverConfirm
name={'common/trash'} Trigger={
cursor={'pointer'} <Box>
w="1rem" <MyIconButton
p="1" icon={'common/trash'}
borderRadius="sm" hoverColor={'red.500'}
_hover={{ hoverBg="red.50"
color: 'red.600', size={'1rem'}
bgColor: 'myGray.100' />
}} </Box>
onClick={() => { }
openRemoveMember( type="delete"
() => onRemoveMember(member.tmbId), content={t('account_team:remove_tip', {
undefined, username: member.memberName
t('account_team:remove_tip', { })}
username: member.memberName onConfirm={() => onRemoveMember(member.tmbId)}
})
)();
}}
/> />
</> </HStack>
) : ( ) : (
member.status === TeamMemberStatusEnum.forbidden && ( member.status === TeamMemberStatusEnum.forbidden && (
<Icon <PopoverConfirm
name={'common/confirm/restoreTip'} Trigger={
cursor={'pointer'} <Box display={'inline-block'}>
w="1rem" <MyIconButton
p="1" icon={'common/confirm/restoreTip'}
borderRadius="sm" size={'1rem'}
_hover={{ hoverColor={'primary.500'}
color: 'primary.500', />
bgColor: 'myGray.100' </Box>
}} }
onClick={() => { type="info"
openRestoreMember( content={t('account_team:restore_tip', {
() => onRestore(member.tmbId), username: member.memberName
undefined, })}
t('account_team:restore_tip', { onConfirm={() => onRestore(member.tmbId)}
username: member.memberName
})
)();
}}
/> />
) )
))} ))}
@@ -381,14 +362,11 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
))} ))}
</Tbody> </Tbody>
</Table> </Table>
<ConfirmRemoveMemberModal />
<ConfirmRestoreMemberModal />
<EditMemberNameModal /> <EditMemberNameModal />
</TableContainer> </TableContainer>
</MemberScrollData> </MemberScrollData>
</MyBox> </MyBox>
<ConfirmLeaveTeamModal />
{isOpenInvite && userInfo?.team?.teamId && <InviteModal onClose={onCloseInvite} />} {isOpenInvite && userInfo?.team?.teamId && <InviteModal onClose={onCloseInvite} />}
{isOpenTeamTagsAsync && <TeamTagModal onClose={onCloseTeamTagsAsync} />} {isOpenTeamTagsAsync && <TeamTagModal onClose={onCloseTeamTagsAsync} />}
</> </>

View File

@@ -5,7 +5,6 @@ import type { IconNameType } from '@fastgpt/web/components/common/Icon/type';
function IconButton({ function IconButton({
name, name,
w = '1rem', w = '1rem',
h = '1rem',
...props ...props
}: { }: {
name: IconNameType; name: IconNameType;
@@ -14,7 +13,7 @@ function IconButton({
<MyIcon <MyIcon
name={name} name={name}
w={w} w={w}
h={h} h={w}
transition={'background 0.1s'} transition={'background 0.1s'}
cursor={'pointer'} cursor={'pointer'}
p="1" p="1"

View File

@@ -23,6 +23,7 @@ import {
SNADBOX_CODE_TEMPLATE SNADBOX_CODE_TEMPLATE
} from '@fastgpt/global/core/workflow/template/system/sandbox/constants'; } from '@fastgpt/global/core/workflow/template/system/sandbox/constants';
import MySelect from '@fastgpt/web/components/common/MySelect'; import MySelect from '@fastgpt/web/components/common/MySelect';
import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm';
const NodeCode = ({ data, selected }: NodeProps<FlowNodeItemType>) => { const NodeCode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -35,11 +36,6 @@ const NodeCode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs); const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
const onChangeNode = useContextSelector(WorkflowContext, (ctx) => ctx.onChangeNode); const onChangeNode = useContextSelector(WorkflowContext, (ctx) => ctx.onChangeNode);
// 重置模板确认
const { ConfirmModal: ResetTemplateConfirm, openConfirm: openResetTemplateConfirm } = useConfirm({
content: t('workflow:code.Reset template confirm')
});
// 切换语言确认 // 切换语言确认
const { ConfirmModal: SwitchLangConfirm, openConfirm: openSwitchLangConfirm } = useConfirm({ const { ConfirmModal: SwitchLangConfirm, openConfirm: openSwitchLangConfirm } = useConfirm({
content: t('workflow:code.Switch language confirm') content: t('workflow:code.Switch language confirm')
@@ -84,13 +80,16 @@ const NodeCode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
{codeType.value === 'py' && ( {codeType.value === 'py' && (
<QuestionTip ml={2} label={t('workflow:support_code_language')} /> <QuestionTip ml={2} label={t('workflow:support_code_language')} />
)} )}
<Box <PopoverConfirm
cursor={'pointer'} Trigger={
color={'primary.500'} <Box cursor={'pointer'} color={'primary.500'} fontSize={'xs'} ml="auto" mr={2}>
fontSize={'xs'} {t('workflow:code.Reset template')}
ml="auto" </Box>
mr={2} }
onClick={openResetTemplateConfirm(() => { showCancel
content={t('workflow:code.Reset template confirm')}
placement={'top-end'}
onConfirm={() =>
onChangeNode({ onChangeNode({
nodeId, nodeId,
type: 'updateInput', type: 'updateInput',
@@ -99,11 +98,9 @@ const NodeCode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
...item, ...item,
value: codeType.value === 'js' ? JS_TEMPLATE : PY_TEMPLATE value: codeType.value === 'js' ? JS_TEMPLATE : PY_TEMPLATE
} }
}); })
})} }
> />
{t('workflow:code.Reset template')}
</Box>
</Flex> </Flex>
<CodeEditor <CodeEditor
bg={'white'} bg={'white'}
@@ -123,7 +120,7 @@ const NodeCode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
); );
} }
}; };
}, [codeType, nodeId, onChangeNode, openResetTemplateConfirm, openSwitchLangConfirm, t]); }, [codeType, nodeId, onChangeNode, openSwitchLangConfirm, t]);
const { isTool, commonInputs } = splitToolInputs(inputs, nodeId); const { isTool, commonInputs } = splitToolInputs(inputs, nodeId);
@@ -146,7 +143,6 @@ const NodeCode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
<IOTitle text={t('common:Output')} /> <IOTitle text={t('common:Output')} />
<RenderOutput nodeId={nodeId} flowOutputList={outputs} /> <RenderOutput nodeId={nodeId} flowOutputList={outputs} />
</Container> </Container>
<ResetTemplateConfirm />
<SwitchLangConfirm /> <SwitchLangConfirm />
</NodeCard> </NodeCard>
); );

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useMemo, useState } from 'react'; import React, { useCallback, useState } from 'react';
import { type NodeProps } from 'reactflow'; import { type NodeProps } from 'reactflow';
import NodeCard from '../render/NodeCard'; import NodeCard from '../render/NodeCard';
import { type FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node.d'; import { type FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node.d';
@@ -19,9 +19,10 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
import ValueTypeLabel from '../render/ValueTypeLabel'; import ValueTypeLabel from '../render/ValueTypeLabel';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import PluginOutputEditModal, { defaultOutput } from './PluginOutputEditModal'; import PluginOutputEditModal, { defaultOutput } from './PluginOutputEditModal';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm';
import MyIconButton from '@fastgpt/web/components/common/Icon/button';
const customOutputConfig = { const customOutputConfig = {
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum), selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
@@ -102,10 +103,7 @@ function Reference({
input: FlowNodeInputItemType; input: FlowNodeInputItemType;
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { ConfirmModal, openConfirm } = useConfirm({
type: 'delete',
content: t('workflow:confirm_delete_field_tip')
});
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode); const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
const [editField, setEditField] = useState<FlowNodeInputItemType>(); const [editField, setEditField] = useState<FlowNodeInputItemType>();
@@ -161,25 +159,32 @@ function Reference({
{/* value */} {/* value */}
<ValueTypeLabel valueType={input.valueType} valueDesc={input.valueDesc} /> <ValueTypeLabel valueType={input.valueType} valueDesc={input.valueDesc} />
<MyIcon <MyIconButton
name={'common/settingLight'} icon={'common/settingLight'}
w={'14px'} size={'14px'}
cursor={'pointer'} ml={2}
ml={3}
color={'myGray.600'} color={'myGray.600'}
_hover={{ color: 'primary.500' }} hoverBg="primary.50"
hoverColor="primary.500"
onClick={() => setEditField(input)} onClick={() => setEditField(input)}
/> />
<MyIcon <PopoverConfirm
className="delete" Trigger={
name={'delete'} <Box ml={1}>
w={'14px'} <MyIconButton
color={'myGray.500'} icon="delete"
cursor={'pointer'} color={'myGray.600'}
ml={2} hoverBg="red.50"
_hover={{ color: 'red.600' }} size={'14px'}
onClick={openConfirm(onDel)} hoverColor="red.600"
/>
</Box>
}
placement={'bottom'}
type={'delete'}
content={t('workflow:confirm_delete_field_tip')}
onConfirm={onDel}
/> />
</Flex> </Flex>
<MyTooltip label={t('workflow:plugin_output_tool')}> <MyTooltip label={t('workflow:plugin_output_tool')}>
@@ -215,7 +220,6 @@ function Reference({
onSubmit={onUpdateField} onSubmit={onUpdateField}
/> />
)} )}
<ConfirmModal />
</> </>
); );
} }

View File

@@ -2,7 +2,6 @@ import React, { useCallback, useMemo, useRef } from 'react';
import { Box, Button, Card, Flex } from '@chakra-ui/react'; import { Box, Button, Card, Flex } from '@chakra-ui/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 { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { useContextSelector } from 'use-context-selector'; import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '../../../../context'; import { WorkflowContext } from '../../../../context';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip'; import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
@@ -19,6 +18,8 @@ import {
} from '@fastgpt/global/core/workflow/runtime/utils'; } from '@fastgpt/global/core/workflow/runtime/utils';
import { type ChatItemType, type UserChatItemValueItemType } from '@fastgpt/global/core/chat/type'; import { type ChatItemType, type UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants'; import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm';
import MyIconButton from '@fastgpt/web/components/common/Icon/button';
type NodeDebugResponseProps = { type NodeDebugResponseProps = {
nodeId: string; nodeId: string;
@@ -97,13 +98,6 @@ const NodeDebugResponse = ({ nodeId, debugResult }: NodeDebugResponseProps) => {
const response = debugResult?.response; const response = debugResult?.response;
const { openConfirm, ConfirmModal } = useConfirm({
content: t('common:core.workflow.Confirm stop debug')
});
const onStop = () => {
openConfirm(onStopNodeDebug)();
};
const interactive = debugResult?.workflowInteractiveResponse; const interactive = debugResult?.workflowInteractiveResponse;
const onNextInteractive = useCallback( const onNextInteractive = useCallback(
(userContent: string) => { (userContent: string) => {
@@ -196,14 +190,20 @@ const NodeDebugResponse = ({ nodeId, debugResult }: NodeDebugResponseProps) => {
{t('common:core.workflow.debug.Run result')} {t('common:core.workflow.debug.Run result')}
</Box> </Box>
{workflowDebugData?.nextRunNodes.length !== 0 && ( {workflowDebugData?.nextRunNodes.length !== 0 && (
<Button <PopoverConfirm
size={'sm'} Trigger={
leftIcon={<MyIcon name={'core/chat/stopSpeech'} w={'16px'} />} <Button
variant={'whiteDanger'} size={'sm'}
onClick={onStop} leftIcon={<MyIcon name={'core/chat/stopSpeech'} w={'16px'} />}
> variant={'whiteDanger'}
{t('common:core.workflow.Stop debug')} >
</Button> {t('common:core.workflow.Stop debug')}
</Button>
}
placement={'top'}
content={t('common:core.workflow.Confirm stop debug')}
onConfirm={onStopNodeDebug}
/>
)} )}
{!interactive && ( {!interactive && (
<> <>
@@ -266,7 +266,6 @@ const NodeDebugResponse = ({ nodeId, debugResult }: NodeDebugResponseProps) => {
)} )}
</Card> </Card>
)} )}
<ConfirmModal />
</> </>
) : null; ) : null;
}; };

View File

@@ -16,8 +16,8 @@ import { getInputComponentProps } from '@fastgpt/global/core/workflow/node/io/ut
import { ReferSelector, useReference } from '../Reference'; import { ReferSelector, useReference } from '../Reference';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import ValueTypeLabel from '../../../ValueTypeLabel'; import ValueTypeLabel from '../../../ValueTypeLabel';
import MyIcon from '@fastgpt/web/components/common/Icon'; import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import MyIconButton from '@fastgpt/web/components/common/Icon/button';
const FieldEditModal = dynamic(() => import('../../FieldEditModal')); const FieldEditModal = dynamic(() => import('../../FieldEditModal'));
@@ -95,7 +95,7 @@ const DynamicInputs = (props: RenderInputProps) => {
)} )}
</Box> </Box>
); );
}, [editField, dynamicInputs, item, keys, onAddField, props, t, t]); }, [editField, dynamicInputs, item, keys, onAddField, props, t]);
return Render; return Render;
}; };
@@ -110,10 +110,7 @@ function Reference({
}) { }) {
const { nodeId, inputs = [], item } = props; const { nodeId, inputs = [], item } = props;
const { t } = useTranslation(); const { t } = useTranslation();
const { ConfirmModal, openConfirm } = useConfirm({
type: 'delete',
content: t('workflow:confirm_delete_field_tip')
});
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode); const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
const keys = useMemo(() => { const keys = useMemo(() => {
@@ -187,25 +184,31 @@ function Reference({
{/* value */} {/* value */}
<ValueTypeLabel valueType={inputChildren.valueType} valueDesc={inputChildren.valueDesc} /> <ValueTypeLabel valueType={inputChildren.valueType} valueDesc={inputChildren.valueDesc} />
<MyIcon <MyIconButton
name={'common/settingLight'} icon="common/settingLight"
w={'14px'} ml={2}
cursor={'pointer'}
ml={3}
color={'myGray.600'} color={'myGray.600'}
_hover={{ color: 'primary.500' }} hoverBg="primary.50"
hoverColor="primary.500"
size={'14px'}
onClick={() => setEditField(inputChildren)} onClick={() => setEditField(inputChildren)}
/> />
<MyIcon <PopoverConfirm
className={'delete'} Trigger={
name={'delete'} <Box ml={1}>
w={'14px'} <MyIconButton
color={'myGray.500'} icon="delete"
cursor={'pointer'} color={'myGray.600'}
ml={2} hoverBg="red.50"
_hover={{ color: 'red.600' }} hoverColor="red.600"
onClick={openConfirm(onDel)} size={'14px'}
/>
</Box>
}
type={'delete'}
content={t('workflow:confirm_delete_field_tip')}
onConfirm={onDel}
/> />
</Flex> </Flex>
<ReferSelector <ReferSelector
@@ -225,7 +228,6 @@ function Reference({
onSubmit={onUpdateField} onSubmit={onUpdateField}
/> />
)} )}
<ConfirmModal />
</> </>
); );
} }

View File

@@ -7,7 +7,6 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { useUserStore } from '@/web/support/user/useUserStore'; import { useUserStore } from '@/web/support/user/useUserStore';
import MyMenu from '@fastgpt/web/components/common/MyMenu'; import MyMenu from '@fastgpt/web/components/common/MyMenu';
import { useContextSelector } from 'use-context-selector'; import { useContextSelector } from 'use-context-selector';
@@ -16,6 +15,7 @@ import MyBox from '@fastgpt/web/components/common/MyBox';
import { formatTimeToChatTime } from '@fastgpt/global/common/string/time'; import { formatTimeToChatTime } from '@fastgpt/global/common/string/time';
import { ChatItemContext } from '@/web/core/chat/context/chatItemContext'; import { ChatItemContext } from '@/web/core/chat/context/chatItemContext';
import { useChatStore } from '@/web/core/chat/context/useChatStore'; import { useChatStore } from '@/web/core/chat/context/useChatStore';
import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm';
type HistoryItemType = { type HistoryItemType = {
id: string; id: string;
@@ -73,9 +73,6 @@ const ChatHistorySlider = ({ confirmClearText }: { confirmClearText: string }) =
title: t('common:core.chat.Custom History Title'), title: t('common:core.chat.Custom History Title'),
placeholder: t('common:core.chat.Custom History Title Description') placeholder: t('common:core.chat.Custom History Title Description')
}); });
const { openConfirm, ConfirmModal } = useConfirm({
content: confirmClearText
});
const canRouteToDetail = useMemo( const canRouteToDetail = useMemo(
() => appId && userInfo?.team.permission.hasWritePer && showRouteToAppDetail, () => appId && userInfo?.team.permission.hasWritePer && showRouteToAppDetail,
@@ -153,19 +150,21 @@ const ChatHistorySlider = ({ confirmClearText }: { confirmClearText: string }) =
</Button> </Button>
{/* Clear */} {/* Clear */}
{isPc && histories.length > 0 && ( {isPc && histories.length > 0 && (
<IconButton <PopoverConfirm
ml={3} Trigger={
h={'100%'} <Box ml={3} h={'100%'}>
variant={'whiteDanger'} <IconButton
size={'mdSquare'} variant={'whiteDanger'}
aria-label={''} size={'mdSquare'}
borderRadius={'50%'} aria-label={''}
icon={<MyIcon name={'common/clearLight'} w={'16px'} />} borderRadius={'50%'}
onClick={() => icon={<MyIcon name={'common/clearLight'} w={'16px'} />}
openConfirm(() => { />
onClearHistory(); </Box>
})()
} }
type="delete"
content={confirmClearText}
onConfirm={() => onClearHistory()}
/> />
)} )}
</Flex> </Flex>
@@ -314,7 +313,6 @@ const ChatHistorySlider = ({ confirmClearText }: { confirmClearText: string }) =
</Flex> </Flex>
)} )}
<EditTitleModal /> <EditTitleModal />
<ConfirmModal />
</MyBox> </MyBox>
); );
}; };

View File

@@ -3,7 +3,7 @@ import { type Dispatch, type ReactNode, type SetStateAction, useState } from 're
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { createContext, useContextSelector } from 'use-context-selector'; import { createContext, useContextSelector } from 'use-context-selector';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants'; import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useDisclosure } from '@chakra-ui/react'; import { useDisclosure } from '@chakra-ui/react';
import { checkTeamWebSyncLimit } from '@/web/support/user/team/api'; import { checkTeamWebSyncLimit } from '@/web/support/user/team/api';
import { getDatasetCollections, postWebsiteSync } from '@/web/core/dataset/api'; import { getDatasetCollections, postWebsiteSync } from '@/web/core/dataset/api';

View File

@@ -3,22 +3,12 @@ import { useTranslation } from 'next-i18next';
import { strIsLink } from '@fastgpt/global/common/string/tools'; import { strIsLink } from '@fastgpt/global/common/string/tools';
import { useToast } from '@fastgpt/web/hooks/useToast'; import { useToast } from '@fastgpt/web/hooks/useToast';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { getDocPath } from '@/web/common/system/doc'; import { getDocPath } from '@/web/common/system/doc';
import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useMyStep } from '@fastgpt/web/hooks/useStep'; import { useMyStep } from '@fastgpt/web/hooks/useStep';
import MyDivider from '@fastgpt/web/components/common/MyDivider'; import MyDivider from '@fastgpt/web/components/common/MyDivider';
import React, { useRef } from 'react'; import React from 'react';
import { import { Box, Link, Input, Button, ModalBody, ModalFooter, Stack } from '@chakra-ui/react';
Box,
Link,
Input,
Button,
ModalBody,
ModalFooter,
Textarea,
Stack
} from '@chakra-ui/react';
import { import {
DataChunkSplitModeEnum, DataChunkSplitModeEnum,
DatasetCollectionDataProcessModeEnum DatasetCollectionDataProcessModeEnum
@@ -33,6 +23,7 @@ import CollectionChunkForm, {
} from '../Form/CollectionChunkForm'; } from '../Form/CollectionChunkForm';
import { getLLMDefaultChunkSize } from '@fastgpt/global/core/dataset/training/utils'; import { getLLMDefaultChunkSize } from '@fastgpt/global/core/dataset/training/utils';
import { type ChunkSettingsType } from '@fastgpt/global/core/dataset/type'; import { type ChunkSettingsType } from '@fastgpt/global/core/dataset/type';
import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm';
export type WebsiteConfigFormType = { export type WebsiteConfigFormType = {
websiteConfig: { websiteConfig: {
@@ -78,10 +69,6 @@ const WebsiteConfigModal = ({
const isEdit = !!websiteConfig?.url; const isEdit = !!websiteConfig?.url;
const { ConfirmModal, openConfirm } = useConfirm({
type: 'common'
});
const { activeStep, goToPrevious, goToNext, MyStep } = useMyStep({ const { activeStep, goToPrevious, goToNext, MyStep } = useMyStep({
defaultStep: 0, defaultStep: 0,
steps steps
@@ -186,73 +173,31 @@ const WebsiteConfigModal = ({
<Button variant={'whiteBase'} onClick={goToPrevious}> <Button variant={'whiteBase'} onClick={goToPrevious}>
{t('common:last_step')} {t('common:last_step')}
</Button> </Button>
<Button <PopoverConfirm
ml={2} Trigger={<Button ml={2}>{t('common:core.dataset.website.Start Sync')}</Button>}
onClick={form.handleSubmit((data) => { content={
openConfirm( isEdit
() => ? t('common:core.dataset.website.Confirm Update Tips')
onSuccess({ : t('common:core.dataset.website.Confirm Create Tips')
websiteConfig: websiteInfoGetValues(), }
chunkSettings: collectionChunkForm2StoreChunkData({ onConfirm={() =>
...data, form.handleSubmit((data) =>
agentModel: datasetDetail.agentModel, onSuccess({
vectorModel: datasetDetail.vectorModel websiteConfig: websiteInfoGetValues(),
}) chunkSettings: collectionChunkForm2StoreChunkData({
}), ...data,
undefined, agentModel: datasetDetail.agentModel,
isEdit vectorModel: datasetDetail.vectorModel
? t('common:core.dataset.website.Confirm Update Tips') })
: t('common:core.dataset.website.Confirm Create Tips') })
)(); )()
})} }
> />
{t('common:core.dataset.website.Start Sync')}
</Button>
</> </>
)} )}
</ModalFooter> </ModalFooter>
<ConfirmModal />
</MyModal> </MyModal>
); );
}; };
export default WebsiteConfigModal; export default WebsiteConfigModal;
const PromptTextarea = ({
defaultValue,
onChange,
onClose
}: {
defaultValue: string;
onChange: (e: string) => void;
onClose: () => void;
}) => {
const ref = useRef<HTMLTextAreaElement>(null);
const { t } = useTranslation();
return (
<MyModal
isOpen
title={t('common:core.dataset.import.Custom prompt')}
iconSrc="modal/edit"
w={'600px'}
onClose={onClose}
>
<ModalBody whiteSpace={'pre-wrap'} fontSize={'sm'} px={[3, 6]} pt={[3, 6]}>
<Textarea ref={ref} rows={8} fontSize={'sm'} defaultValue={defaultValue} />
<Box>{Prompt_AgentQA.fixedText}</Box>
</ModalBody>
<ModalFooter>
<Button
onClick={() => {
const val = ref.current?.value || Prompt_AgentQA.description;
onChange(val);
onClose();
}}
>
{t('common:Confirm')}
</Button>
</ModalFooter>
</MyModal>
);
};

View File

@@ -7,7 +7,6 @@ import {
} from '@/web/core/dataset/api'; } from '@/web/core/dataset/api';
import { useToast } from '@fastgpt/web/hooks/useToast'; import { useToast } from '@fastgpt/web/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils'; import { getErrText } from '@fastgpt/global/common/error/utils';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
@@ -32,6 +31,7 @@ import { ImportDataSourceEnum } from '@fastgpt/global/core/dataset/constants';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import TrainingStates from './CollectionCard/TrainingStates'; import TrainingStates from './CollectionCard/TrainingStates';
import { getTextValidLength } from '@fastgpt/global/common/string/utils'; import { getTextValidLength } from '@fastgpt/global/common/string/utils';
import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm';
const DataCard = () => { const DataCard = () => {
const theme = useTheme(); const theme = useTheme();
@@ -90,28 +90,22 @@ const DataCard = () => {
const canWrite = useMemo(() => datasetDetail.permission.hasWritePer, [datasetDetail]); const canWrite = useMemo(() => datasetDetail.permission.hasWritePer, [datasetDetail]);
const { openConfirm, ConfirmModal } = useConfirm({ const onDeleteOneData = useMemoizedFn(async (dataId: string) => {
content: t('common:dataset.Confirm to delete the data'), try {
type: 'delete' await delOneDatasetDataById(dataId);
}); setDatasetDataList((prev) => {
const onDeleteOneData = useMemoizedFn((dataId: string) => { return prev.filter((data) => data._id !== dataId);
openConfirm(async () => { });
try { toast({
await delOneDatasetDataById(dataId); title: t('common:delete_success'),
setDatasetDataList((prev) => { status: 'success'
return prev.filter((data) => data._id !== dataId); });
}); } catch (error) {
toast({ toast({
title: t('common:delete_success'), title: getErrText(error),
status: 'success' status: 'error'
}); });
} catch (error) { }
toast({
title: getErrText(error),
status: 'error'
});
}
})();
}); });
return ( return (
@@ -333,18 +327,24 @@ const DataCard = () => {
{getTextValidLength(item.q + item.a || '')} {getTextValidLength(item.q + item.a || '')}
</Flex> </Flex>
{canWrite && ( {canWrite && (
<IconButton <PopoverConfirm
display={'flex'} Trigger={
p={1} <IconButton
boxShadow={'1'} display={'flex'}
icon={<MyIcon name={'common/trash'} w={'14px'} color={'myGray.600'} />} p={1}
variant={'whiteDanger'} boxShadow={'1'}
size={'xsSquare'} icon={<MyIcon name={'common/trash'} w={'14px'} />}
onClick={(e) => { variant={'whiteDanger'}
e.stopPropagation(); size={'xsSquare'}
onDeleteOneData(item._id); aria-label={''}
}} onClick={(e) => {
aria-label={''} e.stopPropagation();
}}
/>
}
content={t('common:dataset.Confirm to delete the data')}
type="delete"
onConfirm={() => onDeleteOneData(item._id)}
/> />
)} )}
</Flex> </Flex>
@@ -386,7 +386,6 @@ const DataCard = () => {
onClose={() => setErrorModalId('')} onClose={() => setErrorModalId('')}
/> />
)} )}
<ConfirmModal />
</MyBox> </MyBox>
); );
}; };

View File

@@ -55,10 +55,6 @@ const Info = ({ datasetId }: { datasetId: string }) => {
const vllmModelList = useMemo(() => getVlmModelList(), [getVlmModelList]); const vllmModelList = useMemo(() => getVlmModelList(), [getVlmModelList]);
const vlmModel = watch('vlmModel'); const vlmModel = watch('vlmModel');
const { ConfirmModal: ConfirmDelModal } = useConfirm({
content: t('common:core.dataset.Delete Confirm'),
type: 'delete'
});
const { openConfirm: onOpenConfirmRebuild, ConfirmModal: ConfirmRebuildModal } = useConfirm({ const { openConfirm: onOpenConfirmRebuild, ConfirmModal: ConfirmRebuildModal } = useConfirm({
title: t('common:action_confirm'), title: t('common:action_confirm'),
content: t('dataset:confirm_to_rebuild_embedding_tip'), content: t('dataset:confirm_to_rebuild_embedding_tip'),
@@ -414,7 +410,6 @@ const Info = ({ datasetId }: { datasetId: string }) => {
</> </>
)} )}
<ConfirmDelModal />
<ConfirmRebuildModal countDown={10} /> <ConfirmRebuildModal countDown={10} />
<ConfirmSyncScheduleModal /> <ConfirmSyncScheduleModal />
{editedDataset && ( {editedDataset && (

View File

@@ -25,12 +25,11 @@ import EditMcpModal, {
} from '@/pageComponents/dashboard/mcp/EditModal'; } from '@/pageComponents/dashboard/mcp/EditModal';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip'; import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
import MyIconButton from '@fastgpt/web/components/common/Icon/button'; import MyIconButton from '@fastgpt/web/components/common/Icon/button';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { type McpKeyType } from '@fastgpt/global/support/mcp/type'; import { type McpKeyType } from '@fastgpt/global/support/mcp/type';
import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { useSystem } from '@fastgpt/web/hooks/useSystem';
import { useUserStore } from '@/web/support/user/useUserStore'; import { useUserStore } from '@/web/support/user/useUserStore';
import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm';
const UsageWay = dynamic(() => import('@/pageComponents/dashboard/mcp/usageWay'), { const UsageWay = dynamic(() => import('@/pageComponents/dashboard/mcp/usageWay'), {
ssr: false ssr: false
@@ -52,10 +51,6 @@ const McpServer = () => {
const [editMcp, setEditMcp] = useState<EditMcForm>(); const [editMcp, setEditMcp] = useState<EditMcForm>();
const [usageWay, setUsageWay] = useState<McpKeyType>(); const [usageWay, setUsageWay] = useState<McpKeyType>();
const { openConfirm: openDelConfirm, ConfirmModal: DelConfirmModal } = useConfirm({
type: 'delete',
content: t('dashboard_mcp:delete_mcp_server_confirm_tip')
});
const { runAsync: onDeleteMcpServer } = useRequest2(deleteMcpServer, { const { runAsync: onDeleteMcpServer } = useRequest2(deleteMcpServer, {
manual: true, manual: true,
onSuccess: () => { onSuccess: () => {
@@ -146,10 +141,19 @@ const McpServer = () => {
} }
/> />
<MyIconButton <PopoverConfirm
icon="delete" Trigger={
hoverColor={'red.600'} <Box>
onClick={() => openDelConfirm(() => onDeleteMcpServer(mcp._id))()} <MyIconButton
icon="delete"
hoverBg="red.50"
hoverColor={'red.600'}
/>
</Box>
}
type="delete"
content={t('dashboard_mcp:delete_mcp_server_confirm_tip')}
onConfirm={() => onDeleteMcpServer(mcp._id)}
/> />
</HStack> </HStack>
</Td> </Td>
@@ -164,7 +168,6 @@ const McpServer = () => {
)} )}
</DashboardContainer> </DashboardContainer>
<DelConfirmModal />
{!!usageWay && <UsageWay mcp={usageWay} onClose={() => setUsageWay(undefined)} />} {!!usageWay && <UsageWay mcp={usageWay} onClose={() => setUsageWay(undefined)} />}
{!!editMcp && ( {!!editMcp && (
<EditMcpModal <EditMcpModal