From f127150ea1d94207d21f83d6b687a3534cfb0517 Mon Sep 17 00:00:00 2001 From: icarus Date: Fri, 19 Sep 2025 14:54:04 +0800 Subject: [PATCH] feat(sessions): implement session management ui and state - Rename Container to ButtonContainer for consistency - Add activeSessionId state to track active sessions per agent - Implement Sessions and SessionItem components with loading state - Add session selection and deletion functionality --- .../pages/home/Tabs/components/AgentItem.tsx | 6 +-- .../home/Tabs/components/SessionItem.tsx | 40 ++++++++++--------- .../pages/home/Tabs/components/Sessions.tsx | 34 ++++++++++++---- src/renderer/src/store/runtime.ts | 11 ++++- 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/src/renderer/src/pages/home/Tabs/components/AgentItem.tsx b/src/renderer/src/pages/home/Tabs/components/AgentItem.tsx index 55b947c4e5..79f50eaf16 100644 --- a/src/renderer/src/pages/home/Tabs/components/AgentItem.tsx +++ b/src/renderer/src/pages/home/Tabs/components/AgentItem.tsx @@ -36,11 +36,11 @@ const AgentItem: FC = ({ agent, isActive, onDelete, onPress }) = <> - + - + = ({ agent, isActive, onDelete, onPress }) = ) } -const Container: React.FC> = ({ className, children, ...props }) => ( +const ButtonContainer: React.FC> = ({ className, children, ...props }) => ( ) - }, [session.id, session.name, onPress]) - - const handleClick = () => logger.debug('not implemented') + }, [session.id, session.name]) return ( <> - + - + = ({ session, isActive, onDelete, onPres content: t('agent.session.delete.content'), centered: true, okButtonProps: { danger: true }, - onOk: () => onDelete(session) + onOk: () => onDelete() }) }}> @@ -72,20 +75,21 @@ const SessionItem: FC = ({ session, isActive, onDelete, onPres ) } -const Container: React.FC> = ({ className, ...props }) => ( -
> = ({ className, children, ...props }) => ( + ) const SessionLabelContainer: React.FC> = ({ className, ...props }) => ( diff --git a/src/renderer/src/pages/home/Tabs/components/Sessions.tsx b/src/renderer/src/pages/home/Tabs/components/Sessions.tsx index d0cb902f43..3d6889c782 100644 --- a/src/renderer/src/pages/home/Tabs/components/Sessions.tsx +++ b/src/renderer/src/pages/home/Tabs/components/Sessions.tsx @@ -1,23 +1,43 @@ -import { loggerService } from '@logger' +import { Spinner } from '@heroui/react' import { useSessions } from '@renderer/hooks/agents/useSessions' -import { memo } from 'react' +import { useAppDispatch } from '@renderer/store' +import { setActiveSessionIdAction } from '@renderer/store/runtime' +import { memo, useCallback } from 'react' -const logger = loggerService.withContext('SessionsTab') +import SessionItem from './SessionItem' + +// const logger = loggerService.withContext('SessionsTab') interface SessionsProps { agentId: string } const Sessions: React.FC = ({ agentId }) => { - const { sessions } = useSessions(agentId) - logger.debug('Sessions', sessions) + const { sessions, isLoading, deleteSession } = useSessions(agentId) + const dispatch = useAppDispatch() + + const setActiveSessionId = useCallback( + (agentId: string, sessionId: string | null) => { + dispatch(setActiveSessionIdAction({ agentId, sessionId })) + }, + [dispatch] + ) + + if (isLoading) return + + // if (error) return return (
{/* TODO: Add session button */} - Active Agent ID: {agentId} {sessions.map((session) => ( -
Not implemented
+ deleteSession(session.id)} + onPress={() => setActiveSessionId(agentId, session.id)} + /> ))}
) diff --git a/src/renderer/src/store/runtime.ts b/src/renderer/src/store/runtime.ts index 262116bb49..3911ee9dfb 100644 --- a/src/renderer/src/store/runtime.ts +++ b/src/renderer/src/store/runtime.ts @@ -7,8 +7,11 @@ export interface ChatState { isMultiSelectMode: boolean selectedMessageIds: string[] activeTopic: Topic | null - /** UI state. null represents no active agent, may active assistant */ + /** UI state. null represents no active agent */ activeAgentId: string | null + /** UI state. Map agent id to active session id. + * null represents no active session */ + activeSessionId: Record /** topic ids that are currently being renamed */ renamingTopics: string[] /** topic ids that are newly renamed */ @@ -81,6 +84,7 @@ const initialState: RuntimeState = { selectedMessageIds: [], activeTopic: null, activeAgentId: null, + activeSessionId: {}, renamingTopics: [], newlyRenamedTopics: [] }, @@ -148,6 +152,10 @@ const runtimeSlice = createSlice({ setActiveAgentId: (state, action: PayloadAction) => { state.chat.activeAgentId = action.payload }, + setActiveSessionIdAction: (state, action: PayloadAction<{ agentId: string; sessionId: string | null }>) => { + const { agentId, sessionId } = action.payload + state.chat.activeSessionId[agentId] = sessionId + }, setRenamingTopics: (state, action: PayloadAction) => { state.chat.renamingTopics = action.payload }, @@ -187,6 +195,7 @@ export const { setSelectedMessageIds, setActiveTopic, setActiveAgentId, + setActiveSessionIdAction, setRenamingTopics, setNewlyRenamedTopics, // WebSearch related actions