refactor(Inputbar, Messages): simplify clear topic functionality and improve message display logic

- Removed unused QuestionCircleOutlined icon and Popconfirm from Inputbar, replacing it with a direct button click for clearing topics.
- Refactored message display logic in Messages component to enhance clarity and maintainability, while preserving existing functionality.
This commit is contained in:
kangfenmao 2025-04-12 16:07:40 +08:00
parent d4bf8da225
commit 0e7c4e4bdd
2 changed files with 66 additions and 69 deletions

View File

@ -9,7 +9,6 @@ import {
HolderOutlined, HolderOutlined,
PaperClipOutlined, PaperClipOutlined,
PauseCircleOutlined, PauseCircleOutlined,
QuestionCircleOutlined,
ThunderboltOutlined, ThunderboltOutlined,
TranslationOutlined TranslationOutlined
} from '@ant-design/icons' } from '@ant-design/icons'
@ -40,7 +39,7 @@ import { Assistant, FileType, KnowledgeBase, KnowledgeItem, MCPServer, Message,
import { classNames, delay, formatFileSize, getFileExtension } from '@renderer/utils' import { classNames, delay, formatFileSize, getFileExtension } from '@renderer/utils'
import { getFilesFromDropEvent } from '@renderer/utils/input' import { getFilesFromDropEvent } from '@renderer/utils/input'
import { documentExts, imageExts, textExts } from '@shared/config/constant' import { documentExts, imageExts, textExts } from '@shared/config/constant'
import { Button, Popconfirm, Tooltip } from 'antd' import { Button, Tooltip } from 'antd'
import TextArea, { TextAreaRef } from 'antd/es/input/TextArea' import TextArea, { TextAreaRef } from 'antd/es/input/TextArea'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import Logger from 'electron-log/renderer' import Logger from 'electron-log/renderer'
@ -695,9 +694,7 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
textareaRef.current?.focus() textareaRef.current?.focus()
}) })
useShortcut('clear_topic', () => { useShortcut('clear_topic', clearTopic)
clearTopic()
})
useEffect(() => { useEffect(() => {
const _setEstimateTokenCount = debounce(setEstimateTokenCount, 100, { leading: false, trailing: true }) const _setEstimateTokenCount = debounce(setEstimateTokenCount, 100, { leading: false, trailing: true })
@ -991,17 +988,9 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
ToolbarButton={ToolbarButton} ToolbarButton={ToolbarButton}
/> />
<Tooltip placement="top" title={t('chat.input.clear', { Command: cleanTopicShortcut })} arrow> <Tooltip placement="top" title={t('chat.input.clear', { Command: cleanTopicShortcut })} arrow>
<Popconfirm <ToolbarButton type="text" onClick={clearTopic}>
title={t('chat.input.clear.content')} <ClearOutlined style={{ fontSize: 17 }} />
placement="top" </ToolbarButton>
onConfirm={clearTopic}
okButtonProps={{ danger: true }}
icon={<QuestionCircleOutlined style={{ color: 'red' }} />}
okText={t('chat.input.clear.title')}>
<ToolbarButton type="text">
<ClearOutlined style={{ fontSize: 17 }} />
</ToolbarButton>
</Popconfirm>
</Tooltip> </Tooltip>
<Tooltip placement="top" title={isExpended ? t('chat.input.collapse') : t('chat.input.expand')} arrow> <Tooltip placement="top" title={isExpended ? t('chat.input.collapse') : t('chat.input.expand')} arrow>
<ToolbarButton type="text" onClick={onToggleExpended}> <ToolbarButton type="text" onClick={onToggleExpended}>

View File

@ -38,42 +38,6 @@ interface MessagesProps {
setActiveTopic: (topic: Topic) => void setActiveTopic: (topic: Topic) => void
} }
const computeDisplayMessages = (messages: Message[], startIndex: number, displayCount: number) => {
const reversedMessages = [...messages].reverse()
// 如果剩余消息数量小于 displayCount直接返回所有剩余消息
if (reversedMessages.length - startIndex <= displayCount) {
return reversedMessages.slice(startIndex)
}
const userIdSet = new Set() // 用户消息 id 集合
const assistantIdSet = new Set() // 助手消息 askId 集合
const displayMessages: Message[] = []
// 处理单条消息的函数
const processMessage = (message: Message) => {
if (!message) return
const idSet = message.role === 'user' ? userIdSet : assistantIdSet
const messageId = message.role === 'user' ? message.id : message.askId
if (!idSet.has(messageId)) {
idSet.add(messageId)
displayMessages.push(message)
return
}
// 如果是相同 askId 的助手消息,也要显示
displayMessages.push(message)
}
// 遍历消息直到满足显示数量要求
for (let i = startIndex; i < reversedMessages.length && userIdSet.size + assistantIdSet.size < displayCount; i++) {
processMessage(reversedMessages[i])
}
return displayMessages
}
const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic }) => { const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic }) => {
const { t } = useTranslation() const { t } = useTranslation()
const { showTopics, topicPosition, showAssistants, messageNavigation } = useSettings() const { showTopics, topicPosition, showAssistants, messageNavigation } = useSettings()
@ -118,24 +82,36 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic })
} }
}, []) }, [])
const clearTopic = useCallback(
async (data: Topic) => {
const defaultTopic = getDefaultTopic(assistant.id)
if (data && data.id !== topic.id) {
await clearTopicMessages(data.id)
updateTopic({ ...data, name: defaultTopic.name } as Topic)
return
}
await clearTopicMessages()
setDisplayMessages([])
const _topic = getTopic(assistant, topic.id)
_topic && updateTopic({ ..._topic, name: defaultTopic.name } as Topic)
},
[assistant, clearTopicMessages, topic.id, updateTopic]
)
useEffect(() => { useEffect(() => {
const unsubscribes = [ const unsubscribes = [
EventEmitter.on(EVENT_NAMES.SEND_MESSAGE, scrollToBottom), EventEmitter.on(EVENT_NAMES.SEND_MESSAGE, scrollToBottom),
EventEmitter.on(EVENT_NAMES.CLEAR_MESSAGES, async (data: Topic) => { EventEmitter.on(EVENT_NAMES.CLEAR_MESSAGES, async (data: Topic) => {
const defaultTopic = getDefaultTopic(assistant.id) window.modal.confirm({
title: t('chat.input.clear.title'),
if (data && data.id !== topic.id) { content: t('chat.input.clear.content'),
await clearTopicMessages(data.id) centered: true,
updateTopic({ ...data, name: defaultTopic.name } as Topic) onOk: () => clearTopic(data)
return })
}
await clearTopicMessages()
setDisplayMessages([])
const _topic = getTopic(assistant, topic.id)
if (_topic) {
updateTopic({ ..._topic, name: defaultTopic.name } as Topic)
}
}), }),
EventEmitter.on(EVENT_NAMES.COPY_TOPIC_IMAGE, async () => { EventEmitter.on(EVENT_NAMES.COPY_TOPIC_IMAGE, async () => {
await captureScrollableDivAsBlob(containerRef, async (blob) => { await captureScrollableDivAsBlob(containerRef, async (blob) => {
@ -280,11 +256,43 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic })
) )
} }
interface LoaderProps { const computeDisplayMessages = (messages: Message[], startIndex: number, displayCount: number) => {
$loading: boolean const reversedMessages = [...messages].reverse()
// 如果剩余消息数量小于 displayCount直接返回所有剩余消息
if (reversedMessages.length - startIndex <= displayCount) {
return reversedMessages.slice(startIndex)
}
const userIdSet = new Set() // 用户消息 id 集合
const assistantIdSet = new Set() // 助手消息 askId 集合
const displayMessages: Message[] = []
// 处理单条消息的函数
const processMessage = (message: Message) => {
if (!message) return
const idSet = message.role === 'user' ? userIdSet : assistantIdSet
const messageId = message.role === 'user' ? message.id : message.askId
if (!idSet.has(messageId)) {
idSet.add(messageId)
displayMessages.push(message)
return
}
// 如果是相同 askId 的助手消息,也要显示
displayMessages.push(message)
}
// 遍历消息直到满足显示数量要求
for (let i = startIndex; i < reversedMessages.length && userIdSet.size + assistantIdSet.size < displayCount; i++) {
processMessage(reversedMessages[i])
}
return displayMessages
} }
const LoaderContainer = styled.div<LoaderProps>` const LoaderContainer = styled.div<{ $loading: boolean }>`
display: flex; display: flex;
justify-content: center; justify-content: center;
padding: 10px; padding: 10px;