mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-20 23:22:05 +08:00
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:
parent
af6a3c87d6
commit
27f98b02a6
@ -16,6 +16,14 @@
|
|||||||
},
|
},
|
||||||
"edit": {
|
"edit": {
|
||||||
"title": "Edit Agent"
|
"title": "Edit Agent"
|
||||||
|
},
|
||||||
|
"session": {
|
||||||
|
"delete": {
|
||||||
|
"content": "Are you sure to delete this session?",
|
||||||
|
"title": "Delete session"
|
||||||
|
},
|
||||||
|
"label_one": "Session",
|
||||||
|
"label_other": "Sessions"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"agents": {
|
"agents": {
|
||||||
|
|||||||
33
src/renderer/src/pages/home/Tabs/SessionsTab.tsx
Normal file
33
src/renderer/src/pages/home/Tabs/SessionsTab.tsx
Normal 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)
|
||||||
98
src/renderer/src/pages/home/Tabs/components/SessionItem.tsx
Normal file
98
src/renderer/src/pages/home/Tabs/components/SessionItem.tsx
Normal 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)
|
||||||
@ -11,6 +11,7 @@ import styled from 'styled-components'
|
|||||||
|
|
||||||
import { AgentsTab as Agents } from './AgentsTab'
|
import { AgentsTab as Agents } from './AgentsTab'
|
||||||
import Assistants from './AssistantsTab'
|
import Assistants from './AssistantsTab'
|
||||||
|
import Sessions from './SessionsTab'
|
||||||
import Settings from './SettingsTab'
|
import Settings from './SettingsTab'
|
||||||
import Topics from './TopicsTab'
|
import Topics from './TopicsTab'
|
||||||
|
|
||||||
@ -114,6 +115,9 @@ const HomeTabs: FC<Props> = ({
|
|||||||
<TabItem active={tab === 'topic'} onClick={() => setTab('topic')}>
|
<TabItem active={tab === 'topic'} onClick={() => setTab('topic')}>
|
||||||
{t('common.topics')}
|
{t('common.topics')}
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
<TabItem active={tab === 'sessions'} onClick={() => setTab('sessions')}>
|
||||||
|
{t('agent.session.label_other')}
|
||||||
|
</TabItem>
|
||||||
<TabItem active={tab === 'settings'} onClick={() => setTab('settings')}>
|
<TabItem active={tab === 'settings'} onClick={() => setTab('settings')}>
|
||||||
{t('settings.title')}
|
{t('settings.title')}
|
||||||
</TabItem>
|
</TabItem>
|
||||||
@ -140,7 +144,6 @@ const HomeTabs: FC<Props> = ({
|
|||||||
onCreateDefaultAssistant={onCreateDefaultAssistant}
|
onCreateDefaultAssistant={onCreateDefaultAssistant}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{tab === 'agents' && <Agents />}
|
|
||||||
{tab === 'topic' && (
|
{tab === 'topic' && (
|
||||||
<Topics
|
<Topics
|
||||||
assistant={activeAssistant}
|
assistant={activeAssistant}
|
||||||
@ -149,6 +152,8 @@ const HomeTabs: FC<Props> = ({
|
|||||||
position={position}
|
position={position}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{tab === 'agents' && <Agents />}
|
||||||
|
{tab === 'sessions' && <Sessions />}
|
||||||
{tab === 'settings' && <Settings assistant={activeAssistant} />}
|
{tab === 'settings' && <Settings assistant={activeAssistant} />}
|
||||||
</TabContent>
|
</TabContent>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user