diff --git a/web/src/pages/chat/chat-container/index.tsx b/web/src/pages/chat/chat-container/index.tsx index b1ac8ce3a..3f32e9241 100644 --- a/web/src/pages/chat/chat-container/index.tsx +++ b/web/src/pages/chat/chat-container/index.tsx @@ -191,7 +191,6 @@ const ChatContainer = () => { const { sendMessage } = useSendMessage(); const loading = useOneNamespaceEffectsLoading('chatModel', [ 'completeConversation', - 'getConversation', ]); const ref = useScrollToBottom(); useGetFileIcon(); diff --git a/web/src/pages/chat/hooks.ts b/web/src/pages/chat/hooks.ts index 8efa3209c..b3d6c128f 100644 --- a/web/src/pages/chat/hooks.ts +++ b/web/src/pages/chat/hooks.ts @@ -204,6 +204,24 @@ export const useSelectFirstDialogOnMount = () => { return dialogList; }; +export const useHandleItemHover = () => { + const [activated, setActivated] = useState(''); + + const handleItemEnter = (id: string) => { + setActivated(id); + }; + + const handleItemLeave = () => { + setActivated(''); + }; + + return { + activated, + handleItemEnter, + handleItemLeave, + }; +}; + //#region conversation export const useCreateTemporaryConversation = () => { @@ -477,4 +495,31 @@ export const useGetFileIcon = () => { return getFileIcon; }; +export const useRemoveConversation = () => { + const dispatch = useDispatch(); + const { dialogId } = useGetChatSearchParams(); + const { handleClickConversation } = useClickConversationCard(); + + const removeConversation = (conversationIds: Array) => async () => { + const ret = await dispatch({ + type: 'chatModel/removeConversation', + payload: { + dialog_id: dialogId, + conversation_ids: conversationIds, + }, + }); + + if (ret === 0) { + handleClickConversation(''); + } + + return ret; + }; + + const onRemoveConversation = (conversationIds: Array) => { + showDeleteConfirm({ onOk: removeConversation(conversationIds) }); + }; + + return { onRemoveConversation }; +}; //#endregion diff --git a/web/src/pages/chat/index.tsx b/web/src/pages/chat/index.tsx index 4e3124f32..580f0c428 100644 --- a/web/src/pages/chat/index.tsx +++ b/web/src/pages/chat/index.tsx @@ -11,8 +11,9 @@ import { Space, Tag, } from 'antd'; +import { MenuItemProps } from 'antd/lib/menu/MenuItem'; import classNames from 'classnames'; -import { useCallback, useState } from 'react'; +import { useCallback } from 'react'; import ChatConfigurationModal from './chat-configuration-modal'; import ChatContainer from './chat-container'; import { @@ -21,6 +22,8 @@ import { useFetchConversationList, useFetchDialog, useGetChatSearchParams, + useHandleItemHover, + useRemoveConversation, useRemoveDialog, useSelectConversationList, useSelectFirstDialogOnMount, @@ -31,32 +34,58 @@ import styles from './index.less'; const Chat = () => { const dialogList = useSelectFirstDialogOnMount(); - const [activated, setActivated] = useState(''); const { visible, hideModal, showModal } = useSetModalState(); const { setCurrentDialog, currentDialog } = useSetCurrentDialog(); const { onRemoveDialog } = useRemoveDialog(); + const { onRemoveConversation } = useRemoveConversation(); const { handleClickDialog } = useClickDialogCard(); const { handleClickConversation } = useClickConversationCard(); const { dialogId, conversationId } = useGetChatSearchParams(); const { list: conversationList, addTemporaryConversation } = useSelectConversationList(); + const { activated, handleItemEnter, handleItemLeave } = useHandleItemHover(); + const { + activated: conversationActivated, + handleItemEnter: handleConversationItemEnter, + handleItemLeave: handleConversationItemLeave, + } = useHandleItemHover(); useFetchDialog(dialogId, true); const handleAppCardEnter = (id: string) => () => { - setActivated(id); + handleItemEnter(id); }; - const handleAppCardLeave = () => { - setActivated(''); + const handleConversationCardEnter = (id: string) => () => { + handleConversationItemEnter(id); }; - const handleShowChatConfigurationModal = (dialogId?: string) => () => { - if (dialogId) { - setCurrentDialog(dialogId); - } - showModal(); - }; + const handleShowChatConfigurationModal = + (dialogId?: string): any => + (info: any) => { + info?.domEvent?.preventDefault(); + info?.domEvent?.stopPropagation(); + if (dialogId) { + setCurrentDialog(dialogId); + } + showModal(); + }; + + const handleRemoveDialog = + (dialogId: string): MenuItemProps['onClick'] => + ({ domEvent }) => { + domEvent.preventDefault(); + domEvent.stopPropagation(); + onRemoveDialog([dialogId]); + }; + + const handleRemoveConversation = + (conversationId: string): MenuItemProps['onClick'] => + ({ domEvent }) => { + domEvent.preventDefault(); + domEvent.stopPropagation(); + onRemoveConversation([conversationId]); + }; const handleDialogCardClick = (dialogId: string) => () => { handleClickDialog(dialogId); @@ -97,7 +126,35 @@ const Chat = () => { { type: 'divider' }, { key: '2', - onClick: () => onRemoveDialog([dialogId]), + onClick: handleRemoveDialog(dialogId), + label: ( + + + Delete chat + + ), + }, + ]; + + return appItems; + }; + + const buildConversationItems = (conversationId: string) => { + const appItems: MenuProps['items'] = [ + { + key: '1', + onClick: handleShowChatConfigurationModal(conversationId), + label: ( + + + Edit + + ), + }, + { type: 'divider' }, + { + key: '2', + onClick: handleRemoveConversation(conversationId), label: ( @@ -129,7 +186,7 @@ const Chat = () => { [styles.chatAppCardSelected]: dialogId === x.id, })} onMouseEnter={handleAppCardEnter(x.id)} - onMouseLeave={handleAppCardLeave} + onMouseLeave={handleItemLeave} onClick={handleDialogCardClick(x.id)} > @@ -176,11 +233,22 @@ const Chat = () => { key={x.id} hoverable onClick={handleConversationCardClick(x.id)} + onMouseEnter={handleConversationCardEnter(x.id)} + onMouseLeave={handleConversationItemLeave} className={classNames(styles.chatTitleCard, { [styles.chatTitleCardSelected]: x.id === conversationId, })} > -
{x.name}
+ +
{x.name}
+ {conversationActivated === x.id && x.id !== '' && ( +
+ + + +
+ )} +
))}
diff --git a/web/src/pages/chat/model.ts b/web/src/pages/chat/model.ts index 52894adb7..912d769a5 100644 --- a/web/src/pages/chat/model.ts +++ b/web/src/pages/chat/model.ts @@ -145,6 +145,19 @@ const model: DvaModel = { }); } }, + *removeConversation({ payload }, { call, put }) { + const { data } = yield call(chatService.removeConversation, { + conversation_ids: payload.conversation_ids, + }); + if (data.retcode === 0) { + yield put({ + type: 'listConversation', + payload: { dialog_id: payload.dialog_id }, + }); + message.success('Deleted successfully !'); + } + return data.retcode; + }, }, }; diff --git a/web/src/services/chatService.ts b/web/src/services/chatService.ts index 946de86ae..e2d8d3782 100644 --- a/web/src/services/chatService.ts +++ b/web/src/services/chatService.ts @@ -11,6 +11,7 @@ const { setConversation, completeConversation, listConversation, + removeConversation, } = api; const methods = { @@ -46,6 +47,10 @@ const methods = { url: completeConversation, method: 'post', }, + removeConversation: { + url: removeConversation, + method: 'post', + }, } as const; const chatService = registerServer(methods, request);