| import { useRef } from 'react'; | |
| import { useRecoilState, useRecoilValue } from 'recoil'; | |
| import { useUpdateMessageMutation } from 'librechat-data-provider'; | |
| import type { TEditProps } from '~/common'; | |
| import store from '~/store'; | |
| import Container from './Container'; | |
| import { useLocalize } from '~/hooks'; | |
| const EditMessage = ({ | |
| text, | |
| message, | |
| isSubmitting, | |
| ask, | |
| enterEdit, | |
| siblingIdx, | |
| setSiblingIdx, | |
| }: TEditProps) => { | |
| const [messages, setMessages] = useRecoilState(store.messages); | |
| const conversation = useRecoilValue(store.conversation); | |
| const textEditor = useRef<HTMLDivElement | null>(null); | |
| const { conversationId, parentMessageId, messageId } = message; | |
| const updateMessageMutation = useUpdateMessageMutation(conversationId ?? ''); | |
| const localize = useLocalize(); | |
| const resubmitMessage = () => { | |
| const text = textEditor?.current?.innerText ?? ''; | |
| if (message.isCreatedByUser) { | |
| ask({ | |
| text, | |
| parentMessageId, | |
| conversationId, | |
| }); | |
| setSiblingIdx((siblingIdx ?? 0) - 1); | |
| } else { | |
| const parentMessage = messages?.find((msg) => msg.messageId === parentMessageId); | |
| if (!parentMessage) { | |
| return; | |
| } | |
| ask( | |
| { ...parentMessage }, | |
| { | |
| editedText: text, | |
| editedMessageId: messageId, | |
| isRegenerate: true, | |
| isEdited: true, | |
| }, | |
| ); | |
| setSiblingIdx((siblingIdx ?? 0) - 1); | |
| } | |
| enterEdit(true); | |
| }; | |
| const updateMessage = () => { | |
| if (!messages) { | |
| return; | |
| } | |
| const text = textEditor?.current?.innerText ?? ''; | |
| updateMessageMutation.mutate({ | |
| conversationId: conversationId ?? '', | |
| model: conversation?.model ?? 'gpt-3.5-turbo', | |
| messageId, | |
| text, | |
| }); | |
| setMessages(() => | |
| messages.map((msg) => | |
| msg.messageId === messageId | |
| ? { | |
| ...msg, | |
| text, | |
| isEdited: true, | |
| } | |
| : msg, | |
| ), | |
| ); | |
| enterEdit(true); | |
| }; | |
| return ( | |
| <Container> | |
| <div | |
| data-testid="message-text-editor" | |
| className="markdown prose dark:prose-invert light w-full whitespace-pre-wrap break-words border-none focus:outline-none" | |
| contentEditable={true} | |
| ref={textEditor} | |
| suppressContentEditableWarning={true} | |
| > | |
| {text} | |
| </div> | |
| <div className="mt-2 flex w-full justify-center text-center"> | |
| <button | |
| className="btn btn-primary relative mr-2" | |
| disabled={isSubmitting} | |
| onClick={resubmitMessage} | |
| > | |
| {localize('com_ui_save')} {'&'} {localize('com_ui_submit')} | |
| </button> | |
| <button | |
| className="btn btn-secondary relative mr-2" | |
| disabled={isSubmitting} | |
| onClick={updateMessage} | |
| > | |
| {localize('com_ui_save')} | |
| </button> | |
| <button className="btn btn-neutral relative" onClick={() => enterEdit(true)}> | |
| {localize('com_ui_cancel')} | |
| </button> | |
| </div> | |
| </Container> | |
| ); | |
| }; | |
| export default EditMessage; | |