From 46ca79ef5c0bbe2cdd3686c69b4843b034e8f577 Mon Sep 17 00:00:00 2001 From: MyPrototypeWhat <43230886+MyPrototypeWhat@users.noreply.github.com> Date: Thu, 22 May 2025 14:57:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20add=20functionality=20to=20insert=20mes?= =?UTF-8?q?sages=20at=20a=20specific=20index=20in=20the=E2=80=A6=20(#6299)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add functionality to insert messages at a specific index in the Redux store - Introduced a new interface for inserting messages at a specified index. - Implemented the insertMessageAtIndex reducer to handle message insertion. - Updated saveMessageAndBlocksToDB to support message insertion logic. - Modified appendAssistantResponseThunk to utilize the new insertion functionality. * feat: integrate multi-select mode handling in MessageGroup component - Added useChatContext hook to access multi-select mode state. - Updated isGrouped logic to account for multi-select mode, ensuring proper message grouping behavior. - Enhanced MessageWrapper styles for better layout management in different modes. --------- Co-authored-by: kangfenmao --- .../src/pages/home/Messages/MessageGroup.tsx | 17 +++++++++++++- src/renderer/src/store/newMessage.ts | 21 ++++++++++++++++++ src/renderer/src/store/thunk/messageThunk.ts | 22 +++++++++++++------ 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/renderer/src/pages/home/Messages/MessageGroup.tsx b/src/renderer/src/pages/home/Messages/MessageGroup.tsx index 86b20d8266..e5631bf2a6 100644 --- a/src/renderer/src/pages/home/Messages/MessageGroup.tsx +++ b/src/renderer/src/pages/home/Messages/MessageGroup.tsx @@ -1,5 +1,6 @@ import Scrollbar from '@renderer/components/Scrollbar' import { MessageEditingProvider } from '@renderer/context/MessageEditingContext' +import { useChatContext } from '@renderer/hooks/useChatContext' import { useMessageOperations } from '@renderer/hooks/useMessageOperations' import { useSettings } from '@renderer/hooks/useSettings' import { MultiModelMessageStyle } from '@renderer/store/settings' @@ -24,6 +25,7 @@ interface Props { const MessageGroup = ({ messages, topic, hidePresetMessages, registerMessageElement }: Props) => { const { editMessage } = useMessageOperations(topic) const { multiModelMessageStyle: multiModelMessageStyleSetting, gridColumns, gridPopoverTrigger } = useSettings() + const { isMultiSelectMode } = useChatContext(topic) const [multiModelMessageStyle, setMultiModelMessageStyle] = useState( messages[0].multiModelMessageStyle || multiModelMessageStyleSetting @@ -59,7 +61,7 @@ const MessageGroup = ({ messages, topic, hidePresetMessages, registerMessageElem [editMessage, selectedMessageId] ) - const isGrouped = messageLength > 1 && messages.every((m) => m.role === 'assistant') + const isGrouped = isMultiSelectMode ? false : messageLength > 1 && messages.every((m) => m.role === 'assistant') const isHorizontal = multiModelMessageStyle === 'horizontal' const isGrid = multiModelMessageStyle === 'grid' @@ -298,6 +300,19 @@ interface MessageWrapperProps { const MessageWrapper = styled(Scrollbar)` width: 100%; + &.horizontal { + display: inline-block; + } + &.grid { + display: inline-block; + } + &.fold { + display: none; + &.selected { + display: inline-block; + } + } + ${({ $layout, $isGrouped }) => { if ($layout === 'horizontal' && $isGrouped) { return css` diff --git a/src/renderer/src/store/newMessage.ts b/src/renderer/src/store/newMessage.ts index 927b7c8b4a..1a90a73ec6 100644 --- a/src/renderer/src/store/newMessage.ts +++ b/src/renderer/src/store/newMessage.ts @@ -59,6 +59,13 @@ interface RemoveMessagesPayload { messageIds: string[] } +// Payload for inserting a message at a specific index +interface InsertMessageAtIndexPayload { + topicId: string + message: Message + index: number +} + // 4. Create the Slice with Refactored Reducers const messagesSlice = createSlice({ name: 'newMessages', @@ -95,6 +102,20 @@ const messagesSlice = createSlice({ state.loadingByTopic[topicId] = false } }, + insertMessageAtIndex(state, action: PayloadAction) { + const { topicId, message, index } = action.payload + messagesAdapter.addOne(state, message) // Add message to entities + if (!state.messageIdsByTopic[topicId]) { + state.messageIdsByTopic[topicId] = [] + } + // Ensure index is within bounds + const safeIndex = Math.max(0, Math.min(index, state.messageIdsByTopic[topicId].length)) + state.messageIdsByTopic[topicId].splice(safeIndex, 0, message.id) // Insert ID at specified index + + if (!(topicId in state.loadingByTopic)) { + state.loadingByTopic[topicId] = false + } + }, updateMessage( state, action: PayloadAction<{ diff --git a/src/renderer/src/store/thunk/messageThunk.ts b/src/renderer/src/store/thunk/messageThunk.ts index 29281fb155..566aa6e6e3 100644 --- a/src/renderer/src/store/thunk/messageThunk.ts +++ b/src/renderer/src/store/thunk/messageThunk.ts @@ -49,20 +49,24 @@ const handleChangeLoadingOfTopic = async (topicId: string) => { store.dispatch(newMessagesActions.setTopicLoading({ topicId, loading: false })) } // TODO: 后续可以将db操作移到Listener Middleware中 -export const saveMessageAndBlocksToDB = async (message: Message, blocks: MessageBlock[]) => { +export const saveMessageAndBlocksToDB = async (message: Message, blocks: MessageBlock[], messageIndex: number = -1) => { try { if (blocks.length > 0) { await db.message_blocks.bulkPut(blocks) } const topic = await db.topics.get(message.topicId) if (topic) { - const messageIndex = topic.messages.findIndex((m) => m.id === message.id) + const _messageIndex = topic.messages.findIndex((m) => m.id === message.id) const updatedMessages = [...topic.messages] - if (messageIndex !== -1) { - updatedMessages[messageIndex] = message + if (_messageIndex !== -1) { + updatedMessages[_messageIndex] = message } else { - updatedMessages.push(message) + if (messageIndex !== -1) { + updatedMessages.splice(messageIndex, 0, message) + } else { + updatedMessages.push(message) + } } await db.topics.update(message.topicId, { messages: updatedMessages }) } else { @@ -1244,10 +1248,14 @@ export const appendAssistantResponseThunk = }) // 3. Update Redux Store - dispatch(newMessagesActions.addMessage({ topicId, message: newAssistantStub })) + const currentTopicMessageIds = getState().messages.messageIdsByTopic[topicId] || [] + const existingMessageIndex = currentTopicMessageIds.findIndex((id) => id === existingAssistantMessageId) + const insertAtIndex = existingMessageIndex !== -1 ? existingMessageIndex + 1 : currentTopicMessageIds.length + + dispatch(newMessagesActions.insertMessageAtIndex({ topicId, message: newAssistantStub, index: insertAtIndex })) // 4. Update Database (Save the stub to the topic's message list) - await saveMessageAndBlocksToDB(newAssistantStub, []) + await saveMessageAndBlocksToDB(newAssistantStub, [], insertAtIndex) // 5. Prepare and queue the processing task const assistantConfigForThisCall = {