feat(sessions): add sessions tab with basic functionality and translations

- Create new SessionsTab component with mock data
- Add session item component with context menu for edit/delete
- Include session tab in main navigation
- Add English translations for session-related strings
This commit is contained in:
icarus 2025-09-18 19:26:25 +08:00
parent af6a3c87d6
commit 27f98b02a6
4 changed files with 145 additions and 1 deletions

View File

@ -16,6 +16,14 @@
},
"edit": {
"title": "Edit Agent"
},
"session": {
"delete": {
"content": "Are you sure to delete this session?",
"title": "Delete session"
},
"label_one": "Session",
"label_other": "Sessions"
}
},
"agents": {

View File

@ -0,0 +1,33 @@
import { useRuntime } from '@renderer/hooks/useRuntime'
import { AgentSessionEntity } from '@renderer/types'
import { FC, memo } from 'react'
interface AssistantsTabProps {}
const SessionsTab: FC<AssistantsTabProps> = () => {
const { chat } = useRuntime()
const { activeAgentId } = chat
const mockData: AgentSessionEntity[] = [
{
accessible_paths: [],
model: '',
id: 'test',
agent_id: '',
agent_type: 'claude-code',
created_at: '',
updated_at: ''
}
]
return (
<div className="agents-tab h-full w-full p-2">
{/* TODO: Add session button */}
Active Agent ID: {activeAgentId}
{mockData.map((session) => (
<div key={session.id}>Not implemented</div>
))}
</div>
)
}
export default memo(SessionsTab)

View File

@ -0,0 +1,98 @@
import { Button, cn, useDisclosure } from '@heroui/react'
import { loggerService } from '@logger'
import { DeleteIcon, EditIcon } from '@renderer/components/Icons'
import { AgentSessionEntity } from '@renderer/types'
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from '@renderer/ui/context-menu'
import { FC, memo, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
const logger = loggerService.withContext('AgentItem')
interface SessionItemProps {
session: AgentSessionEntity
isActive: boolean
onDelete: (session: AgentSessionEntity) => void
onPress: () => void
}
const SessionItem: FC<SessionItemProps> = ({ session, isActive, onDelete, onPress }) => {
const { t } = useTranslation()
// const { isOpen, onOpen, onClose } = useDisclosure()
const { onOpen } = useDisclosure()
const SessionLabel = useCallback(() => {
const displayName = session.name ?? session.id
return (
<Button onPress={onPress}>
<span className="text-sm">{displayName}</span>
</Button>
)
}, [session.id, session.name, onPress])
const handleClick = () => logger.debug('not implemented')
return (
<>
<ContextMenu modal={false}>
<ContextMenuTrigger>
<Container onClick={handleClick} className={isActive ? 'active' : ''}>
<SessionLabelContainer className="name" title={session.name ?? session.id}>
<SessionLabel />
</SessionLabelContainer>
</Container>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem
key="edit"
onClick={() => {
onOpen()
}}>
<EditIcon size={14} />
{t('common.edit')}
</ContextMenuItem>
<ContextMenuItem
key="delete"
className="text-danger"
onClick={() => {
window.modal.confirm({
title: t('agent.session.delete.title'),
content: t('agent.session.delete.content'),
centered: true,
okButtonProps: { danger: true },
onOk: () => onDelete(session)
})
}}>
<DeleteIcon size={14} className="lucide-custom text-danger" />
<span className="text-danger">{t('common.delete')}</span>
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
{/* TODO: Add a session modal here */}
</>
)
}
const Container: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ className, ...props }) => (
<div
{...props}
className={cn(
'relative flex h-[37px] flex-row justify-between p-2',
'rounded-[var(--list-item-border-radius)]',
'border-[0.5px] border-transparent',
'w-[calc(var(--assistants-width)_-_20px)]',
'hover:bg-[var(--color-list-item-hover)]',
'cursor-pointer',
className?.includes('active') && 'bg-[var(--color-list-item)] shadow-sm',
className
)}
/>
)
const SessionLabelContainer: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ className, ...props }) => (
<div
{...props}
className={cn('text-[13px] text-[var(--color-text)]', 'flex flex-row items-center gap-2', className)}
/>
)
export default memo(SessionItem)

View File

@ -11,6 +11,7 @@ import styled from 'styled-components'
import { AgentsTab as Agents } from './AgentsTab'
import Assistants from './AssistantsTab'
import Sessions from './SessionsTab'
import Settings from './SettingsTab'
import Topics from './TopicsTab'
@ -114,6 +115,9 @@ const HomeTabs: FC<Props> = ({
<TabItem active={tab === 'topic'} onClick={() => setTab('topic')}>
{t('common.topics')}
</TabItem>
<TabItem active={tab === 'sessions'} onClick={() => setTab('sessions')}>
{t('agent.session.label_other')}
</TabItem>
<TabItem active={tab === 'settings'} onClick={() => setTab('settings')}>
{t('settings.title')}
</TabItem>
@ -140,7 +144,6 @@ const HomeTabs: FC<Props> = ({
onCreateDefaultAssistant={onCreateDefaultAssistant}
/>
)}
{tab === 'agents' && <Agents />}
{tab === 'topic' && (
<Topics
assistant={activeAssistant}
@ -149,6 +152,8 @@ const HomeTabs: FC<Props> = ({
position={position}
/>
)}
{tab === 'agents' && <Agents />}
{tab === 'sessions' && <Sessions />}
{tab === 'settings' && <Settings assistant={activeAssistant} />}
</TabContent>
</Container>