mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-27 12:51:26 +08:00
refactor(code-block): extract code block editing logic to custom hook
Move code block editing functionality from Messages component to useEditCodeBlock hook for better reusability and maintainability
This commit is contained in:
parent
d2b25af146
commit
d3d02712a4
@ -39,7 +39,7 @@ interface Props {
|
||||
language: string
|
||||
// Message Block ID
|
||||
blockId: string
|
||||
onSave: (newContent: string) => void
|
||||
onSave: (newContent: string) => Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -25,7 +25,7 @@ interface UseMermaidFixTool {
|
||||
/** Mermaid code */
|
||||
content: string
|
||||
}
|
||||
onSave: (newContent: string) => void
|
||||
onSave: (newContent: string) => Promise<void>
|
||||
setError: (error: unknown) => void
|
||||
setTools: React.Dispatch<React.SetStateAction<ActionTool[]>>
|
||||
}
|
||||
@ -136,7 +136,7 @@ export const useMermaidFixTool = ({ enabled, context, onSave, setError, setTools
|
||||
if (parsedResult.success) {
|
||||
const validResult = parsedResult.data
|
||||
if (validResult.fixed) {
|
||||
onSave(validResult.result)
|
||||
await onSave(validResult.result)
|
||||
setError(undefined)
|
||||
} else {
|
||||
window.toast.warning({ title: t('code_block.mermaid_fix.failed'), description: validResult.reason })
|
||||
|
||||
@ -12,6 +12,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { useStore } from 'react-redux'
|
||||
const logger = loggerService.withContext('useChatContext')
|
||||
|
||||
// TODO: use useContext to refactor it.
|
||||
export const useChatContext = (activeTopic: Topic) => {
|
||||
const { t } = useTranslation()
|
||||
const store = useStore<RootState>()
|
||||
|
||||
55
src/renderer/src/hooks/useEditCodeBlock.ts
Normal file
55
src/renderer/src/hooks/useEditCodeBlock.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { loggerService } from '@logger'
|
||||
import store, { useAppDispatch } from '@renderer/store'
|
||||
import { messageBlocksSelectors, updateOneBlock } from '@renderer/store/messageBlock'
|
||||
import { updateMessageAndBlocksThunk } from '@renderer/store/thunk/messageThunk'
|
||||
import type { MessageBlock } from '@renderer/types/newMessage'
|
||||
import { MessageBlockType } from '@renderer/types/newMessage'
|
||||
import { updateCodeBlock } from '@renderer/utils/markdown'
|
||||
import { isTextLikeBlock } from '@renderer/utils/messageUtils/is'
|
||||
import { t } from 'i18next'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
const logger = loggerService.withContext('useEditCodeBlock')
|
||||
|
||||
export const useEditCodeBlock = () => {
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const editCodeBlock = useCallback(
|
||||
async (data: { topicId: string; msgBlockId: string; codeBlockId: string; newContent: string }) => {
|
||||
const { topicId, msgBlockId, codeBlockId, newContent } = data
|
||||
|
||||
const msgBlock = messageBlocksSelectors.selectById(store.getState(), msgBlockId)
|
||||
|
||||
// FIXME: 目前 error block 没有 content
|
||||
if (msgBlock && isTextLikeBlock(msgBlock) && msgBlock.type !== MessageBlockType.ERROR) {
|
||||
try {
|
||||
const updatedRaw = updateCodeBlock(msgBlock.content, codeBlockId, newContent)
|
||||
const updatedBlock: MessageBlock = {
|
||||
...msgBlock,
|
||||
content: updatedRaw,
|
||||
updatedAt: new Date().toISOString()
|
||||
}
|
||||
|
||||
dispatch(updateOneBlock({ id: msgBlockId, changes: { content: updatedRaw } }))
|
||||
await dispatch(updateMessageAndBlocksThunk(topicId, null, [updatedBlock]))
|
||||
|
||||
window.toast.success(t('code_block.edit.save.success'))
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`Failed to save code block ${codeBlockId} content to message block ${msgBlockId}:`,
|
||||
error as Error
|
||||
)
|
||||
window.toast.error(t('code_block.edit.save.failed.label'))
|
||||
}
|
||||
} else {
|
||||
logger.error(
|
||||
`Failed to save code block ${codeBlockId} content to message block ${msgBlockId}: no such message block or the block doesn't have a content field`
|
||||
)
|
||||
window.toast.error(t('code_block.edit.save.failed.label'))
|
||||
}
|
||||
},
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
return editCodeBlock
|
||||
}
|
||||
@ -34,7 +34,7 @@ const CodeBlock: React.FC<Props> = ({ children, className, node, blockId }) => {
|
||||
const isStreaming = useMemo(() => msgBlock?.status === MessageBlockStatus.STREAMING, [msgBlock?.status])
|
||||
|
||||
const handleSave = useCallback(
|
||||
(newContent: string) => {
|
||||
async (newContent: string) => {
|
||||
if (id !== undefined) {
|
||||
EventEmitter.emit(EVENT_NAMES.EDIT_CODE_BLOCK, {
|
||||
msgBlockId: blockId,
|
||||
|
||||
@ -5,6 +5,7 @@ import { LoadingIcon } from '@renderer/components/Icons'
|
||||
import { LOAD_MORE_COUNT } from '@renderer/config/constant'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useChatContext } from '@renderer/hooks/useChatContext'
|
||||
import { useEditCodeBlock } from '@renderer/hooks/useEditCodeBlock'
|
||||
import { useMessageOperations, useTopicMessages } from '@renderer/hooks/useMessageOperations'
|
||||
import useScrollPosition from '@renderer/hooks/useScrollPosition'
|
||||
import { useShortcut } from '@renderer/hooks/useShortcuts'
|
||||
@ -15,22 +16,18 @@ import { getDefaultTopic } from '@renderer/services/AssistantService'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||
import { getContextCount, getGroupedMessages, getUserMessage } from '@renderer/services/MessagesService'
|
||||
import { estimateHistoryTokens } from '@renderer/services/TokenService'
|
||||
import store, { useAppDispatch } from '@renderer/store'
|
||||
import { messageBlocksSelectors, updateOneBlock } from '@renderer/store/messageBlock'
|
||||
import { useAppDispatch } from '@renderer/store'
|
||||
import { newMessagesActions } from '@renderer/store/newMessage'
|
||||
import { saveMessageAndBlocksToDB, updateMessageAndBlocksThunk } from '@renderer/store/thunk/messageThunk'
|
||||
import { saveMessageAndBlocksToDB } from '@renderer/store/thunk/messageThunk'
|
||||
import type { Assistant, Topic } from '@renderer/types'
|
||||
import type { MessageBlock } from '@renderer/types/newMessage'
|
||||
import { type Message, MessageBlockType } from '@renderer/types/newMessage'
|
||||
import { type Message } from '@renderer/types/newMessage'
|
||||
import {
|
||||
captureScrollableAsBlob,
|
||||
captureScrollableAsDataURL,
|
||||
removeSpecialCharactersForFileName,
|
||||
runAsyncFunction
|
||||
} from '@renderer/utils'
|
||||
import { updateCodeBlock } from '@renderer/utils/markdown'
|
||||
import { getMainTextContent } from '@renderer/utils/messageUtils/find'
|
||||
import { isTextLikeBlock } from '@renderer/utils/messageUtils/is'
|
||||
import { last } from 'lodash'
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@ -70,6 +67,7 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic, o
|
||||
const messages = useTopicMessages(topic.id)
|
||||
const { displayCount, clearTopicMessages, deleteMessage, createTopicBranch } = useMessageOperations(topic)
|
||||
const { setTimeoutTimer } = useTimer()
|
||||
const editCodeBlock = useEditCodeBlock()
|
||||
|
||||
const { isMultiSelectMode, handleSelectMessage } = useChatContext(topic)
|
||||
|
||||
@ -205,36 +203,12 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic, o
|
||||
EVENT_NAMES.EDIT_CODE_BLOCK,
|
||||
async (data: { msgBlockId: string; codeBlockId: string; newContent: string }) => {
|
||||
const { msgBlockId, codeBlockId, newContent } = data
|
||||
|
||||
const msgBlock = messageBlocksSelectors.selectById(store.getState(), msgBlockId)
|
||||
|
||||
// FIXME: 目前 error block 没有 content
|
||||
if (msgBlock && isTextLikeBlock(msgBlock) && msgBlock.type !== MessageBlockType.ERROR) {
|
||||
try {
|
||||
const updatedRaw = updateCodeBlock(msgBlock.content, codeBlockId, newContent)
|
||||
const updatedBlock: MessageBlock = {
|
||||
...msgBlock,
|
||||
content: updatedRaw,
|
||||
updatedAt: new Date().toISOString()
|
||||
}
|
||||
|
||||
dispatch(updateOneBlock({ id: msgBlockId, changes: { content: updatedRaw } }))
|
||||
await dispatch(updateMessageAndBlocksThunk(topic.id, null, [updatedBlock]))
|
||||
|
||||
window.toast.success(t('code_block.edit.save.success'))
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`Failed to save code block ${codeBlockId} content to message block ${msgBlockId}:`,
|
||||
error as Error
|
||||
)
|
||||
window.toast.error(t('code_block.edit.save.failed.label'))
|
||||
}
|
||||
} else {
|
||||
logger.error(
|
||||
`Failed to save code block ${codeBlockId} content to message block ${msgBlockId}: no such message block or the block doesn't have a content field`
|
||||
)
|
||||
window.toast.error(t('code_block.edit.save.failed.label'))
|
||||
}
|
||||
return editCodeBlock({
|
||||
topicId: topic.id,
|
||||
msgBlockId,
|
||||
codeBlockId,
|
||||
newContent
|
||||
})
|
||||
}
|
||||
)
|
||||
]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user