File size: 3,746 Bytes
a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 bbe4eea a8aec61 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
import { useQueryState } from 'nuqs'
import { SessionEntry } from '@/types/os'
import { Button } from '../../../ui/button'
import useSessionLoader from '@/hooks/useSessionLoader'
import { deleteSessionAPI } from '@/api/os'
import { useStore } from '@/store'
import { toast } from 'sonner'
import Icon from '@/components/ui/icon'
import { useState } from 'react'
import DeleteSessionModal from './DeleteSessionModal'
import useChatActions from '@/hooks/useChatActions'
import { truncateText, cn } from '@/lib/utils'
type SessionItemProps = SessionEntry & {
isSelected: boolean
currentSessionId: string | null
onSessionClick: () => void
}
const SessionItem = ({
session_name: title,
session_id,
isSelected,
currentSessionId,
onSessionClick
}: SessionItemProps) => {
const [agentId] = useQueryState('agent')
const [teamId] = useQueryState('team')
const [dbId] = useQueryState('db_id')
const [, setSessionId] = useQueryState('session')
const { getSession } = useSessionLoader()
const { selectedEndpoint, sessionsData, setSessionsData, mode } = useStore()
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false)
const [isDeleting, setIsDeleting] = useState(false)
const { clearChat } = useChatActions()
const handleGetSession = async () => {
if (!(agentId || teamId || dbId)) return
onSessionClick()
await getSession(
{
entityType: mode,
agentId,
teamId,
dbId: dbId ?? ''
},
session_id
)
setSessionId(session_id)
}
const handleDeleteSession = async () => {
if (!(agentId || teamId || dbId)) return
setIsDeleting(true)
try {
const response = await deleteSessionAPI(
selectedEndpoint,
dbId ?? '',
session_id
)
if (response?.ok && sessionsData) {
setSessionsData(sessionsData.filter((s) => s.session_id !== session_id))
// If the deleted session was the active one, clear the chat
if (currentSessionId === session_id) {
setSessionId(null)
clearChat()
}
toast.success('Session deleted')
} else {
const errorMsg = await response?.text()
toast.error(
`Failed to delete session: ${response?.statusText || 'Unknown error'} ${errorMsg || ''}`
)
}
} catch (error) {
toast.error(
`Failed to delete session: ${error instanceof Error ? error.message : String(error)}`
)
} finally {
setIsDeleteModalOpen(false)
setIsDeleting(false)
}
}
return (
<>
<div
className={cn(
'group flex h-11 w-full items-center justify-between rounded-lg px-3 py-2 transition-colors duration-200',
isSelected
? 'cursor-default bg-primary/10'
: 'cursor-pointer bg-background-secondary hover:bg-background-secondary/80'
)}
onClick={handleGetSession}
>
<div className="flex flex-col gap-1">
<h4
className={cn('text-sm font-medium', isSelected && 'text-primary')}
>
{truncateText(title, 20)}
</h4>
</div>
<Button
variant="ghost"
size="icon"
className="transform opacity-0 transition-all duration-200 ease-in-out group-hover:opacity-100"
onClick={(e) => {
e.stopPropagation()
setIsDeleteModalOpen(true)
}}
>
<Icon type="trash" size="xs" />
</Button>
</div>
<DeleteSessionModal
isOpen={isDeleteModalOpen}
onClose={() => setIsDeleteModalOpen(false)}
onDelete={handleDeleteSession}
isDeleting={isDeleting}
/>
</>
)
}
export default SessionItem
|