import { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { Plus, Trash2, MessageSquare, Workflow as WorkflowIcon, Pencil, Check, Box } from 'lucide-react'; import apiClient from '../../api/client'; import type { Workflow } from '../../types'; import { useChatStore } from '../../store/useChatStore'; import { useAppStore } from '../../store/useAppStore'; interface LeftPanelProps { activeTab: string; } export function LeftPanel({ activeTab }: LeftPanelProps) { const { t } = useTranslation(); const [workflows, setWorkflows] = useState([]); const [loadingWorkflows, setLoadingWorkflows] = useState(false); const [renamingId, setRenamingId] = useState(null); const [renameValue, setRenameValue] = useState(''); const { sessions, activeSessionId, setActiveSessionId, removeSession, selectedWorkflow, setSelectedWorkflow, updateSessionTitle, } = useChatStore(); const installedHeavyPlugins = useAppStore((s) => s.installedHeavyPlugins); const activeHeavyPlugin = useAppStore((s) => s.activeHeavyPlugin); const setActiveHeavyPlugin = useAppStore((s) => s.setActiveHeavyPlugin); const heavyPluginsWithUi = installedHeavyPlugins.filter((p) => p.has_ui); useEffect(() => { let intervalId: ReturnType; const fetchWorkflows = async (isInitial = false) => { if (isInitial) setLoadingWorkflows(true); try { const response = await apiClient.get('/api/v1/workflow/list'); const data = response.data; let parsedWorkflows: Workflow[] = []; if (Array.isArray(data)) { parsedWorkflows = data; } else if (data && typeof data === 'object') { parsedWorkflows = data.workflows || Object.values(data); } setWorkflows(parsedWorkflows); } catch (error) { console.error('Failed to fetch workflows', error); setWorkflows([]); } finally { if (isInitial) setLoadingWorkflows(false); } }; if (activeTab === 'workflows') { fetchWorkflows(true); intervalId = setInterval(() => fetchWorkflows(false), 2000); } return () => { if (intervalId) clearInterval(intervalId); }; }, [activeTab]); const handleNewChat = () => { setActiveSessionId(null); setActiveHeavyPlugin(null); }; const handleDeleteChat = (e: React.MouseEvent, id: string) => { e.stopPropagation(); removeSession(id); }; const handleStartRename = (e: React.MouseEvent, id: string, title: string) => { e.stopPropagation(); setRenamingId(id); setRenameValue(title); }; const handleConfirmRename = (e: React.MouseEvent) => { e.stopPropagation(); if (renamingId && renameValue.trim()) { updateSessionTitle(renamingId, renameValue.trim()); } setRenamingId(null); }; const isChats = activeTab === 'chats'; return (
{isChats ? t('chat.chatHistory') : t('nav.workflow')}
{isChats ? ( sessions.length === 0 ? (
{t('chat.noHistory')}
) : ( sessions.map((session) => { const isActive = activeSessionId === session.id; const isRenaming = renamingId === session.id; return (
{ setActiveSessionId(session.id); setActiveHeavyPlugin(null); }} className={`group flex items-center gap-2.5 px-2.5 py-2 rounded-lg cursor-pointer transition-all mb-px ${ isActive ? 'bg-bg-card shadow-[0_1px_3px_rgba(0,0,0,0.04)]' : 'hover:bg-white/60 dark:hover:bg-white/[0.04]' }`} >
{isRenaming ? ( setRenameValue(e.target.value)} onClick={(e) => e.stopPropagation()} onKeyDown={(e) => { if (e.key === 'Enter') handleConfirmRename(e as any); if (e.key === 'Escape') setRenamingId(null); }} className="w-full text-xs bg-bg-input border border-border-primary rounded px-1.5 py-0.5 text-text-primary focus:outline-none focus:border-accent" /> ) : (

{session.title}

)}
{isRenaming ? ( ) : (
)}
); }) ) ) : ( <> {loadingWorkflows ? (
{t('workflow.loading')}
) : workflows.length === 0 ? (
{t('workflow.noWorkflows')}
) : ( workflows.map((wf) => { const isActive = selectedWorkflow === wf.trace_id; return (
setSelectedWorkflow(wf.trace_id)} className={`group flex items-center gap-2.5 px-2.5 py-2 rounded-lg cursor-pointer transition-all mb-px ${ isActive ? 'bg-bg-card shadow-[0_1px_3px_rgba(0,0,0,0.04)]' : 'hover:bg-white/60 dark:hover:bg-white/[0.04]' }`} >

{wf.title || t('common.unnamed')}

); }) )} )}
{isChats && heavyPluginsWithUi.length > 0 && (
{t('chat.plugins.title')}
{heavyPluginsWithUi.map((p) => { const isActive = activeHeavyPlugin === p.name; return ( ); })}
)}
); }