refactor: update message handling and state management

- Simplified message editing logic by removing unnecessary success/error logging.
- Added `updatedAt` timestamp to message updates for better tracking.
- Refactored `editMessageBlocks` to accept message ID and updates directly.
- Removed unused `getTopicLimit` function from `TopicManager`.
- Updated message rendering to use `updatedAt` when available.
- Enhanced type definitions to include `updatedAt` in message structure.
This commit is contained in:
MyPrototypeWhat 2025-05-09 18:42:00 +08:00
parent 5b95d20294
commit 6da1d08c9a
7 changed files with 28 additions and 38 deletions

View File

@ -79,7 +79,7 @@ export function useMessageOperations(topic: Topic) {
) )
/** /**
* Redux state / Edits a message. (Currently only updates Redux state). * / Edits a message.
* 使 newMessagesActions.updateMessage. * 使 newMessagesActions.updateMessage.
*/ */
const editMessage = useCallback( const editMessage = useCallback(
@ -92,17 +92,12 @@ export function useMessageOperations(topic: Topic) {
const messageUpdates: Partial<Message> & Pick<Message, 'id'> = { const messageUpdates: Partial<Message> & Pick<Message, 'id'> = {
id: messageId, id: messageId,
updatedAt: new Date().toISOString(),
...updates ...updates
} }
// Call the thunk with topic.id and only message updates // Call the thunk with topic.id and only message updates
const success = await dispatch(updateMessageAndBlocksThunk(topic.id, messageUpdates, [])) await dispatch(updateMessageAndBlocksThunk(topic.id, messageUpdates, []))
if (success) {
console.log(`[useMessageOperations] Successfully edited message ${messageId} properties.`)
} else {
console.error(`[useMessageOperations] Failed to edit message ${messageId} properties.`)
}
}, },
[dispatch, topic.id] [dispatch, topic.id]
) )
@ -133,9 +128,16 @@ export function useMessageOperations(topic: Topic) {
const files = findFileBlocks(message).map((block) => block.file) const files = findFileBlocks(message).map((block) => block.file)
const usage = await estimateUserPromptUsage({ content: editedContent, files }) const usage = await estimateUserPromptUsage({ content: editedContent, files })
const messageUpdates: Partial<Message> & Pick<Message, 'id'> = {
id: message.id,
updatedAt: new Date().toISOString(),
usage
}
await dispatch(updateMessageAndBlocksThunk(topic.id, { id: message.id, usage }, [])) await dispatch(
newMessagesActions.updateMessage({ topicId: topic.id, messageId: message.id, updates: messageUpdates })
)
// 对于message的修改会在下面的thunk中保存
await dispatch(resendUserMessageWithEditThunk(topic.id, message, mainTextBlockId, editedContent, assistant)) await dispatch(resendUserMessageWithEditThunk(topic.id, message, mainTextBlockId, editedContent, assistant))
}, },
[dispatch, topic.id] [dispatch, topic.id]
@ -313,29 +315,23 @@ export function useMessageOperations(topic: Topic) {
* Uses the generalized thunk for persistence. * Uses the generalized thunk for persistence.
*/ */
const editMessageBlocks = useCallback( const editMessageBlocks = useCallback(
// messageId?: string async (messageId: string, updates: Partial<MessageBlock>) => {
async (blockUpdatesListRaw: Partial<MessageBlock>[]) => {
if (!topic?.id) { if (!topic?.id) {
console.error('[editMessageBlocks] Topic prop is not valid.') console.error('[editMessageBlocks] Topic prop is not valid.')
return return
} }
if (!blockUpdatesListRaw || blockUpdatesListRaw.length === 0) {
console.warn('[editMessageBlocks] Received empty block updates list.') const blockUpdatesListProcessed = {
return updatedAt: new Date().toISOString(),
...updates
} }
const blockUpdatesListProcessed = blockUpdatesListRaw.map((update) => ({ const messageUpdates: Partial<Message> & Pick<Message, 'id'> = {
...update, id: messageId,
updatedAt: new Date().toISOString() updatedAt: new Date().toISOString()
}))
const success = await dispatch(updateMessageAndBlocksThunk(topic.id, null, blockUpdatesListProcessed))
if (success) {
// console.log(`[useMessageOperations] Successfully processed block updates for message ${messageId}.`)
} else {
// console.error(`[useMessageOperations] Failed to process block updates for message ${messageId}.`)
} }
await dispatch(updateMessageAndBlocksThunk(topic.id, messageUpdates, [blockUpdatesListProcessed]))
}, },
[dispatch, topic.id] [dispatch, topic.id]
) )

View File

@ -107,14 +107,6 @@ export const autoRenameTopic = async (assistant: Assistant, topicId: string) =>
// Convert class to object with functions since class only has static methods // Convert class to object with functions since class only has static methods
// 只有静态方法,没必要用class可以export {} // 只有静态方法,没必要用class可以export {}
export const TopicManager = { export const TopicManager = {
async getTopicLimit(limit: number) {
return await db.topics
.orderBy('updatedAt') // 按 updatedAt 排序(默认升序)
.reverse() // 逆序(变成降序)
.limit(limit) // 取前 10 条
.toArray()
},
async getTopic(id: string) { async getTopic(id: string) {
return await db.topics.get(id) return await db.topics.get(id)
}, },

View File

@ -102,7 +102,7 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message }) => {
<UserName isBubbleStyle={isBubbleStyle} theme={theme}> <UserName isBubbleStyle={isBubbleStyle} theme={theme}>
{username} {username}
</UserName> </UserName>
<MessageTime>{dayjs(message.createdAt).format('MM/DD HH:mm')}</MessageTime> <MessageTime>{dayjs(message?.updatedAt ?? message.createdAt).format('MM/DD HH:mm')}</MessageTime>
</UserWrap> </UserWrap>
</AvatarWrapper> </AvatarWrapper>
</Container> </Container>

View File

@ -164,7 +164,7 @@ const MessageMenubar: FC<Props> = (props) => {
if (resendMessage) { if (resendMessage) {
resendUserMessageWithEdit(message, editedText, assistant) resendUserMessageWithEdit(message, editedText, assistant)
} else { } else {
editMessageBlocks([{ ...findMainTextBlocks(message)[0], content: editedText }]) editMessageBlocks(message.id, { id: findMainTextBlocks(message)[0].id, content: editedText })
} }
// // 更新消息内容,保留图片信息 // // 更新消息内容,保留图片信息
// await editMessage(message.id, { // await editMessage(message.id, {

View File

@ -867,6 +867,7 @@ export const resendMessageThunk =
const blockIdsToDelete = [...(originalMsg.blocks || [])] const blockIdsToDelete = [...(originalMsg.blocks || [])]
const resetMsg = resetAssistantMessage(originalMsg, { const resetMsg = resetAssistantMessage(originalMsg, {
status: AssistantMessageStatus.PENDING, status: AssistantMessageStatus.PENDING,
updatedAt: new Date().toISOString(),
...(assistantMessagesToReset.length === 1 ? { model: assistant.model } : {}) ...(assistantMessagesToReset.length === 1 ? { model: assistant.model } : {})
}) })
@ -969,7 +970,8 @@ export const regenerateAssistantResponseThunk =
// 5. Reset the message entity in Redux // 5. Reset the message entity in Redux
const resetAssistantMsg = resetAssistantMessage(messageToResetEntity, { const resetAssistantMsg = resetAssistantMessage(messageToResetEntity, {
status: AssistantMessageStatus.PENDING status: AssistantMessageStatus.PENDING,
updatedAt: new Date().toISOString()
}) })
dispatch( dispatch(
newMessagesActions.updateMessage({ newMessagesActions.updateMessage({

View File

@ -161,7 +161,7 @@ export type Message = {
assistantId: string assistantId: string
topicId: string topicId: string
createdAt: string createdAt: string
// updatedAt?: string updatedAt?: string
status: UserMessageStatus | AssistantMessageStatus status: UserMessageStatus | AssistantMessageStatus
// 消息元数据 // 消息元数据

View File

@ -384,7 +384,7 @@ export function resetMessage(
*/ */
export const resetAssistantMessage = ( export const resetAssistantMessage = (
originalMessage: Message, originalMessage: Message,
updates?: Partial<Pick<Message, 'status'>> // Primarily allow updating status updates?: Partial<Pick<Message, 'status' | 'updatedAt'>> // Primarily allow updating status
): Message => { ): Message => {
// Ensure we are only resetting assistant messages // Ensure we are only resetting assistant messages
if (originalMessage.role !== 'assistant') { if (originalMessage.role !== 'assistant') {