### What problem does this PR solve? Fix: Using the Enter key does not send a complete message #6754 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)tags/v0.18.0
| @@ -11,8 +11,6 @@ import { | |||
| CloseCircleOutlined, | |||
| InfoCircleOutlined, | |||
| LoadingOutlined, | |||
| PaperClipOutlined, | |||
| SendOutlined, | |||
| } from '@ant-design/icons'; | |||
| import type { GetProp, UploadFile } from 'antd'; | |||
| import { | |||
| @@ -29,7 +27,7 @@ import { | |||
| UploadProps, | |||
| } from 'antd'; | |||
| import get from 'lodash/get'; | |||
| import { CircleStop } from 'lucide-react'; | |||
| import { CircleStop, Paperclip, SendHorizontal } from 'lucide-react'; | |||
| import { | |||
| ChangeEventHandler, | |||
| memo, | |||
| @@ -153,6 +151,14 @@ const MessageInput = ({ | |||
| const isUploadingFile = fileList.some((x) => x.status === 'uploading'); | |||
| const handlePressEnter = useCallback(async () => { | |||
| if (isUploadingFile) return; | |||
| const ids = getFileIds(fileList.filter((x) => isUploadSuccess(x))); | |||
| onPressEnter(ids); | |||
| setFileList([]); | |||
| }, [fileList, onPressEnter, isUploadingFile]); | |||
| const handleKeyDown = useCallback( | |||
| async (event: React.KeyboardEvent<HTMLTextAreaElement>) => { | |||
| // check if it was shift + enter | |||
| @@ -166,19 +172,6 @@ const MessageInput = ({ | |||
| [sendDisabled, isUploadingFile, sendLoading, handlePressEnter], | |||
| ); | |||
| const handlePressEnter = useCallback(async () => { | |||
| if (isUploadingFile) return; | |||
| const ids = getFileIds(fileList.filter((x) => isUploadSuccess(x))); | |||
| onPressEnter(ids); | |||
| setFileList([]); | |||
| }, [fileList, onPressEnter, isUploadingFile]); | |||
| const [isComposing, setIsComposing] = useState(false); | |||
| const handleCompositionStart = () => setIsComposing(true); | |||
| const handleCompositionEnd = () => setIsComposing(false); | |||
| const handleRemove = useCallback( | |||
| async (file: UploadFile) => { | |||
| const ids = get(file, 'response.data', []); | |||
| @@ -245,8 +238,6 @@ const MessageInput = ({ | |||
| autoSize={{ minRows: 2, maxRows: 10 }} | |||
| onKeyDown={handleKeyDown} | |||
| onChange={onInputChange} | |||
| onCompositionStart={handleCompositionStart} | |||
| onCompositionEnd={handleCompositionEnd} | |||
| /> | |||
| <Divider style={{ margin: '5px 30px 10px 0px' }} /> | |||
| <Flex justify="space-between" align="center"> | |||
| @@ -349,13 +340,13 @@ const MessageInput = ({ | |||
| }} | |||
| > | |||
| <Button type={'primary'} disabled={disabled}> | |||
| <PaperClipOutlined /> | |||
| <Paperclip className="size-4" /> | |||
| </Button> | |||
| </Upload> | |||
| )} | |||
| {sendLoading ? ( | |||
| <Button onClick={handleStopOutputMessage}> | |||
| <CircleStop /> | |||
| <CircleStop className="size-5" /> | |||
| </Button> | |||
| ) : ( | |||
| <Button | |||
| @@ -364,7 +355,7 @@ const MessageInput = ({ | |||
| loading={sendLoading} | |||
| disabled={sendDisabled || isUploadingFile || sendLoading} | |||
| > | |||
| <SendOutlined /> | |||
| <SendHorizontal className="size-5" /> | |||
| </Button> | |||
| )} | |||
| </Flex> | |||
| @@ -3,7 +3,7 @@ import SvgIcon from '@/components/svg-icon'; | |||
| import { IReference, IReferenceChunk } from '@/interfaces/database/chat'; | |||
| import { getExtension } from '@/utils/document-util'; | |||
| import { InfoCircleOutlined } from '@ant-design/icons'; | |||
| import { Button, Flex, Popover, Space } from 'antd'; | |||
| import { Button, Flex, Popover } from 'antd'; | |||
| import DOMPurify from 'dompurify'; | |||
| import { useCallback, useEffect, useMemo } from 'react'; | |||
| import Markdown from 'react-markdown'; | |||
| @@ -23,6 +23,7 @@ import 'katex/dist/katex.min.css'; // `rehype-katex` does not import the CSS for | |||
| import { preprocessLaTeX, replaceThinkToSection } from '@/utils/chat'; | |||
| import { replaceTextByOldReg } from '../utils'; | |||
| import classNames from 'classnames'; | |||
| import { pipe } from 'lodash/fp'; | |||
| import styles from './index.less'; | |||
| @@ -108,11 +109,7 @@ const MarkdownContent = ({ | |||
| const fileExtension = documentId ? getExtension(document?.doc_name) : ''; | |||
| const imageId = chunkItem?.image_id; | |||
| return ( | |||
| <Flex | |||
| key={chunkItem?.id} | |||
| gap={10} | |||
| className={styles.referencePopoverWrapper} | |||
| > | |||
| <div key={chunkItem?.id} className="flex gap-2"> | |||
| {imageId && ( | |||
| <Popover | |||
| placement="left" | |||
| @@ -129,12 +126,12 @@ const MarkdownContent = ({ | |||
| ></Image> | |||
| </Popover> | |||
| )} | |||
| <Space direction={'vertical'}> | |||
| <div className={'space-y-2 max-w-[40vw]'}> | |||
| <div | |||
| dangerouslySetInnerHTML={{ | |||
| __html: DOMPurify.sanitize(chunkItem?.content ?? ''), | |||
| }} | |||
| className={styles.chunkContentText} | |||
| className={classNames(styles.chunkContentText)} | |||
| ></div> | |||
| {documentId && ( | |||
| <Flex gap={'small'}> | |||
| @@ -152,7 +149,7 @@ const MarkdownContent = ({ | |||
| )} | |||
| <Button | |||
| type="link" | |||
| className={styles.documentLink} | |||
| className={classNames(styles.documentLink, 'text-wrap')} | |||
| onClick={handleDocumentButtonClick( | |||
| documentId, | |||
| chunkItem, | |||
| @@ -164,8 +161,8 @@ const MarkdownContent = ({ | |||
| </Button> | |||
| </Flex> | |||
| )} | |||
| </Space> | |||
| </Flex> | |||
| </div> | |||
| </div> | |||
| ); | |||
| }, | |||
| [reference, fileThumbnails, handleDocumentButtonClick], | |||
| @@ -46,7 +46,7 @@ const oldReg = /(#{2}\d+\${2})/g; | |||
| // To be compatible with the old index matching mode | |||
| export const replaceTextByOldReg = (text: string) => { | |||
| return text.replace(oldReg, function (substring) { | |||
| return text?.replace(oldReg, function (substring) { | |||
| return `~~${substring.slice(2, -2)}==`; | |||
| }); | |||
| }; | |||