'use client' import { useEffect, useMemo, useState, useRef, useCallback } from 'react' import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' import { usePlaygroundStore } from '@/store' import { useQueryState } from 'nuqs' import SessionItem from './SessionItem' import SessionBlankState from './SessionBlankState' import useSessionLoader from '@/hooks/useSessionLoader' import { cn } from '@/lib/utils' import { FC } from 'react' import { Skeleton } from '@/components/ui/skeleton' interface SkeletonListProps { skeletonCount: number } const SkeletonList: FC = ({ skeletonCount }) => { const skeletons = useMemo( () => Array.from({ length: skeletonCount }, (_, i) => i), [skeletonCount] ) return skeletons.map((skeleton, index) => ( 0 && 'bg-background-secondary' )} /> )) } dayjs.extend(utc) const formatDate = ( timestamp: number, format: 'natural' | 'full' = 'full' ): string => { const date = dayjs.unix(timestamp).utc() return format === 'natural' ? date.format('HH:mm') : date.format('YYYY-MM-DD HH:mm:ss') } const Sessions = () => { const [agentId] = useQueryState('agent', { parse: (value) => value || undefined, history: 'push' }) const [sessionId] = useQueryState('session') const { selectedEndpoint, isEndpointActive, isEndpointLoading, sessionsData, hydrated, hasStorage, setSessionsData } = usePlaygroundStore() const [isScrolling, setIsScrolling] = useState(false) const [selectedSessionId, setSelectedSessionId] = useState( null ) const { getSession, getSessions } = useSessionLoader() const scrollTimeoutRef = useRef>(null) const { isSessionsLoading } = usePlaygroundStore() const handleScroll = () => { setIsScrolling(true) if (scrollTimeoutRef.current) { clearTimeout(scrollTimeoutRef.current) } scrollTimeoutRef.current = setTimeout(() => { setIsScrolling(false) }, 1500) } // Cleanup the scroll timeout when component unmounts useEffect(() => { return () => { if (scrollTimeoutRef.current) { clearTimeout(scrollTimeoutRef.current) } } }, []) // Load a session on render if a session id exists in url useEffect(() => { if (sessionId && agentId && selectedEndpoint && hydrated) { getSession(sessionId, agentId) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [hydrated]) useEffect(() => { if (!selectedEndpoint || !agentId || !hasStorage) { setSessionsData(() => null) return } if (!isEndpointLoading) { setSessionsData(() => null) getSessions(agentId) } }, [ selectedEndpoint, agentId, getSessions, isEndpointLoading, hasStorage, setSessionsData ]) useEffect(() => { if (sessionId) { setSelectedSessionId(sessionId) } }, [sessionId]) const formattedSessionsData = useMemo(() => { if (!sessionsData || !Array.isArray(sessionsData)) return [] return sessionsData.map((entry) => ({ ...entry, created_at: entry.created_at, formatted_time: formatDate(entry.created_at, 'natural') })) }, [sessionsData]) const handleSessionClick = useCallback( (id: string) => () => setSelectedSessionId(id), [] ) if (isSessionsLoading || isEndpointLoading) return (
Sessions
) return (
Sessions
setIsScrolling(true)} onMouseLeave={handleScroll} > {!isEndpointActive || !hasStorage || (!isSessionsLoading && (!sessionsData || sessionsData.length === 0)) ? ( ) : (
{formattedSessionsData.map((entry, index) => ( ))}
)}
) } export default Sessions