import { useCallback, useEffect, useRef } from 'react' import { Button } from '@janhq/joi' import { AnimatePresence } from 'framer-motion' import { useAtomValue } from 'jotai' import { PenSquareIcon } from 'lucide-react' import { twMerge } from 'tailwind-merge' import LeftPanelContainer from '@/containers/LeftPanelContainer' import { toaster } from '@/containers/Toast' import useAssistantQuery from '@/hooks/useAssistantQuery' import useThreads from '@/hooks/useThreads' import { copyOverInstructionEnabledAtom } from '@/screens/Settings/Advanced/components/CopyOverInstruction' import ThreadItem from './ThreadItem' import { downloadedModelsAtom, getSelectedModelAtom, } from '@/helpers/atoms/Model.atom' import { reduceTransparentAtom } from '@/helpers/atoms/Setting.atom' import { activeThreadAtom, threadsAtom } from '@/helpers/atoms/Thread.atom' const ThreadLeftPanel: React.FC = () => { const { createThread, setActiveThread } = useThreads() const reduceTransparent = useAtomValue(reduceTransparentAtom) const downloadedModels = useAtomValue(downloadedModelsAtom) const selectedModel = useAtomValue(getSelectedModelAtom) const threads = useAtomValue(threadsAtom) const activeThread = useAtomValue(activeThreadAtom) const { data: assistants } = useAssistantQuery() const isCreatingThread = useRef(false) const copyOverInstructionEnabled = useAtomValue( copyOverInstructionEnabledAtom ) useEffect(() => { // if user does not have any threads, we should create one const createThreadIfEmpty = async () => { if (!assistants || assistants.length === 0) return if (downloadedModels.length === 0) return if (threads.length > 0) return if (isCreatingThread.current) return isCreatingThread.current = true // user have models but does not have any thread. Let's create one await createThread(downloadedModels[0].model, assistants[0]) isCreatingThread.current = false } createThreadIfEmpty() }, [threads, assistants, downloadedModels, createThread]) useEffect(() => { if (activeThread?.id) return if (threads.length === 0) return setActiveThread(threads[0].id) }, [activeThread?.id, setActiveThread, threads]) const onCreateThreadClicked = useCallback(async () => { if (!assistants || assistants.length === 0) { toaster({ title: 'No assistant available.', description: `Could not create a new thread. Please add an assistant.`, type: 'error', }) return } if (!selectedModel) return let instructions: string | undefined = undefined if (copyOverInstructionEnabled) { instructions = activeThread?.assistants[0]?.instructions ?? undefined } createThread(selectedModel.model, assistants[0], instructions) }, [ createThread, selectedModel, assistants, activeThread, copyOverInstructionEnabled, ]) return (
{threads.map((thread) => ( ))}
) } export default ThreadLeftPanel