From aadadf83534ee80f49e4a829eacbba1770d5d716 Mon Sep 17 00:00:00 2001 From: icarus Date: Sat, 27 Sep 2025 18:03:42 +0800 Subject: [PATCH] fix(session): remove redundant fulfilled dispatch and add loading indicators Remove the redundant dispatch of setTopicFulfilled in messageThunk since it's now handled in SessionItem. Add visual indicators for pending and fulfilled states in SessionItem to improve user feedback. --- .../home/Tabs/components/SessionItem.tsx | 47 +++++++++++++++++-- .../src/store/thunk/messageThunk.v2.ts | 1 - 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/renderer/src/pages/home/Tabs/components/SessionItem.tsx b/src/renderer/src/pages/home/Tabs/components/SessionItem.tsx index af0a8c037d..f71b9ef149 100644 --- a/src/renderer/src/pages/home/Tabs/components/SessionItem.tsx +++ b/src/renderer/src/pages/home/Tabs/components/SessionItem.tsx @@ -8,11 +8,15 @@ import { useSettings } from '@renderer/hooks/useSettings' import { useTimer } from '@renderer/hooks/useTimer' import { SessionSettingsPopup } from '@renderer/pages/settings/AgentSettings' import { SessionLabel } from '@renderer/pages/settings/AgentSettings/shared' +import { useAppDispatch, useAppSelector } from '@renderer/store' +import { newMessagesActions } from '@renderer/store/newMessage' import { AgentSessionEntity } from '@renderer/types' import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from '@renderer/ui/context-menu' +import { buildAgentSessionTopicId } from '@renderer/utils/agentSession' import { XIcon } from 'lucide-react' -import React, { FC, memo, startTransition, useState } from 'react' +import React, { FC, memo, startTransition, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' +import styled from 'styled-components' // const logger = loggerService.withContext('AgentItem') @@ -33,6 +37,7 @@ const SessionItem: FC = ({ session, agentId, isDisabled, isLoa const activeSessionId = chat.activeSessionId[agentId] const [isConfirmingDeletion, setIsConfirmingDeletion] = useState(false) const { setTimeoutTimer } = useTimer() + const dispatch = useAppDispatch() const { isEditing, isSaving, editValue, inputRef, startEdit, handleKeyDown, handleValueChange } = useInPlaceEdit({ onSave: async (value) => { @@ -86,6 +91,11 @@ const SessionItem: FC = ({ session, agentId, isDisabled, isLoa } const isActive = activeSessionId === session.id + const topicLoadingQuery = useAppSelector((state) => state.messages.loadingByTopic) + const topicFulfilledQuery = useAppSelector((state) => state.messages.fulfilledByTopic) + const sessionTopicId = buildAgentSessionTopicId(session.id) + const isPending = useMemo(() => topicLoadingQuery[sessionTopicId], [sessionTopicId, topicLoadingQuery]) + const isFulfilled = useMemo(() => topicFulfilledQuery[sessionTopicId], [sessionTopicId, topicFulfilledQuery]) return ( <> @@ -94,11 +104,16 @@ const SessionItem: FC = ({ session, agentId, isDisabled, isLoa { + dispatch(newMessagesActions.setTopicFulfilled({ topicId: sessionTopicId, fulfilled: false })) + onPress() + }} isActive={isActive} onDoubleClick={() => startEdit(session.name ?? '')} className="group"> - + + {isPending && !isActive && } + {isFulfilled && !isActive && } {isEditing && ( > = ({ /> ) +const PendingIndicator = styled.div.attrs({ + className: 'animation-pulse' +})` + --pulse-size: 5px; + width: 5px; + height: 5px; + position: absolute; + left: 3px; + top: 15px; + border-radius: 50%; + background-color: var(--color-status-warning); +` + +const FulfilledIndicator = styled.div.attrs({ + className: 'animation-pulse' +})` + --pulse-size: 5px; + width: 5px; + height: 5px; + position: absolute; + left: 3px; + top: 15px; + border-radius: 50%; + background-color: var(--color-status-success); +` + export default memo(SessionItem) diff --git a/src/renderer/src/store/thunk/messageThunk.v2.ts b/src/renderer/src/store/thunk/messageThunk.v2.ts index 3dc0ea7847..ec0aed947b 100644 --- a/src/renderer/src/store/thunk/messageThunk.v2.ts +++ b/src/renderer/src/store/thunk/messageThunk.v2.ts @@ -55,7 +55,6 @@ export const loadTopicMessagesThunkV2 = // Could dispatch an error action here if needed } finally { dispatch(newMessagesActions.setTopicLoading({ topicId, loading: false })) - dispatch(newMessagesActions.setTopicFulfilled({ topicId, fulfilled: true })) } }