import { useRef, useEffect, useMemo } from 'react'; import { Box, Typography, IconButton } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked'; import CheckCircleIcon from '@mui/icons-material/CheckCircle'; import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline'; import CodeIcon from '@mui/icons-material/Code'; import TerminalIcon from '@mui/icons-material/Terminal'; import ArticleIcon from '@mui/icons-material/Article'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import { useAgentStore } from '@/store/agentStore'; import { useLayoutStore } from '@/store/layoutStore'; import { processLogs } from '@/utils/logProcessor'; export default function CodePanel() { const { panelContent, panelTabs, activePanelTab, setActivePanelTab, removePanelTab, plan } = useAgentStore(); const { setRightPanelOpen } = useLayoutStore(); const scrollRef = useRef(null); // Get the active tab content, or fall back to panelContent for backwards compatibility const activeTab = panelTabs.find(t => t.id === activePanelTab); const currentContent = activeTab || panelContent; const displayContent = useMemo(() => { if (!currentContent?.content) return ''; // Apply log processing only for text/logs, not for code/json if (!currentContent.language || currentContent.language === 'text') { return processLogs(currentContent.content); } return currentContent.content; }, [currentContent?.content, currentContent?.language]); useEffect(() => { // Auto-scroll only for logs tab if (scrollRef.current && activePanelTab === 'logs') { scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } }, [displayContent, activePanelTab]); const hasTabs = panelTabs.length > 0; return ( {/* Header - Fixed 60px to align */} {hasTabs ? ( {panelTabs.map((tab) => { const isActive = activePanelTab === tab.id; // Choose icon based on tab type let icon = ; if (tab.id === 'script' || tab.language === 'python') { icon = ; } else if (tab.id === 'tool_output' || tab.language === 'markdown' || tab.language === 'json') { icon = ; } return ( setActivePanelTab(tab.id)} sx={{ display: 'flex', alignItems: 'center', gap: 0.5, px: 1.5, py: 0.75, borderRadius: 1, cursor: 'pointer', fontSize: '0.7rem', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.05em', color: isActive ? 'var(--text)' : 'var(--muted-text)', bgcolor: isActive ? 'rgba(255,255,255,0.08)' : 'transparent', border: '1px solid', borderColor: isActive ? 'rgba(255,255,255,0.1)' : 'transparent', transition: 'all 0.15s ease', '&:hover': { bgcolor: 'rgba(255,255,255,0.05)', }, }} > {icon} {tab.title} { e.stopPropagation(); removePanelTab(tab.id); }} sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', ml: 0.5, width: 16, height: 16, borderRadius: '50%', fontSize: '0.65rem', opacity: 0.5, '&:hover': { opacity: 1, bgcolor: 'rgba(255,255,255,0.1)', }, }} > ✕ ); })} ) : ( {currentContent?.title || 'Code Panel'} )} setRightPanelOpen(false)} sx={{ color: 'var(--muted-text)' }}> {/* Main Content Area */} {!currentContent ? ( NO DATA LOADED ) : ( {currentContent.content ? ( currentContent.language === 'python' ? ( {displayContent} ) : currentContent.language === 'json' ? ( {displayContent} ) : currentContent.language === 'markdown' ? ( {displayContent} ) : ( {displayContent} ) ) : ( NO CONTENT TO DISPLAY )} )} {/* Plan Display at Bottom */} {plan && plan.length > 0 && ( CURRENT PLAN {plan.map((item) => ( {item.status === 'completed' && } {item.status === 'in_progress' && } {item.status === 'pending' && } {item.content} ))} )} ); }