feat: Add session management and global Claude terminal
Phase 1 - Accurate study status detection: - Add is_optimization_running() to check for active processes - Add get_accurate_study_status() with proper status logic - Status now: not_started, running, paused, completed - Add "paused" status styling (orange) to Home page Phase 2 - Global Claude terminal: - Create ClaudeTerminalContext for app-level state - Create GlobalClaudeTerminal floating component - Terminal persists across page navigation - Shows green indicator when connected - Remove inline terminal from Dashboard 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,9 +4,9 @@ import { Terminal } from 'lucide-react';
|
||||
import { useOptimizationWebSocket } from '../hooks/useWebSocket';
|
||||
import { apiClient } from '../api/client';
|
||||
import { useStudy } from '../context/StudyContext';
|
||||
import { useClaudeTerminal } from '../context/ClaudeTerminalContext';
|
||||
import { Card } from '../components/common/Card';
|
||||
import { ControlPanel } from '../components/dashboard/ControlPanel';
|
||||
import { ClaudeTerminal } from '../components/ClaudeTerminal';
|
||||
import { ParetoPlot } from '../components/ParetoPlot';
|
||||
import { ParallelCoordinatesPlot } from '../components/ParallelCoordinatesPlot';
|
||||
import { ParameterImportanceChart } from '../components/ParameterImportanceChart';
|
||||
@@ -64,9 +64,8 @@ export default function Dashboard() {
|
||||
// Chart library toggle: 'recharts' (faster) or 'plotly' (more interactive but slower)
|
||||
const [chartLibrary, setChartLibrary] = useState<'plotly' | 'recharts'>('recharts');
|
||||
|
||||
// Claude chat panel state
|
||||
const [chatOpen, setChatOpen] = useState(false);
|
||||
const [chatExpanded, setChatExpanded] = useState(false);
|
||||
// Claude terminal from global context
|
||||
const { isOpen: claudeTerminalOpen, setIsOpen: setClaudeTerminalOpen, isConnected: claudeConnected } = useClaudeTerminal();
|
||||
|
||||
const showAlert = (type: 'success' | 'warning', message: string) => {
|
||||
const id = alertIdCounter;
|
||||
@@ -353,16 +352,21 @@ export default function Dashboard() {
|
||||
<div className="flex gap-2">
|
||||
{/* Claude Code Terminal Toggle Button */}
|
||||
<button
|
||||
onClick={() => setChatOpen(!chatOpen)}
|
||||
onClick={() => setClaudeTerminalOpen(!claudeTerminalOpen)}
|
||||
className={`flex items-center gap-2 px-4 py-2 rounded-lg transition-colors ${
|
||||
chatOpen
|
||||
claudeTerminalOpen
|
||||
? 'bg-primary-600 text-white'
|
||||
: 'bg-dark-700 text-dark-200 hover:bg-dark-600 hover:text-white border border-dark-600'
|
||||
: claudeConnected
|
||||
? 'bg-green-700 text-white border border-green-600'
|
||||
: 'bg-dark-700 text-dark-200 hover:bg-dark-600 hover:text-white border border-dark-600'
|
||||
}`}
|
||||
title="Open Claude Code terminal"
|
||||
title={claudeConnected ? 'Claude Terminal (Connected)' : 'Open Claude Code terminal'}
|
||||
>
|
||||
<Terminal className="w-4 h-4" />
|
||||
<span className="hidden sm:inline">Claude Code</span>
|
||||
{claudeConnected && !claudeTerminalOpen && (
|
||||
<span className="w-2 h-2 bg-green-400 rounded-full animate-pulse" />
|
||||
)}
|
||||
</button>
|
||||
{selectedStudyId && (
|
||||
<StudyReportViewer studyId={selectedStudyId} />
|
||||
@@ -417,10 +421,10 @@ export default function Dashboard() {
|
||||
<ControlPanel onStatusChange={refreshStudies} horizontal />
|
||||
</div>
|
||||
|
||||
{/* Main Layout: Charts + Claude Terminal */}
|
||||
<div className={`grid gap-4 ${chatOpen ? 'grid-cols-12' : 'grid-cols-1'}`}>
|
||||
{/* Main Layout: Charts (Claude Terminal is now global/floating) */}
|
||||
<div className="grid gap-4 grid-cols-1">
|
||||
{/* Main Content - Charts stacked vertically */}
|
||||
<main className={chatOpen ? 'col-span-7' : 'col-span-1'}>
|
||||
<main>
|
||||
{/* Study Name Header + Metrics in one row */}
|
||||
<div className="mb-4 pb-3 border-b border-dark-600 flex items-center justify-between">
|
||||
<div>
|
||||
@@ -790,17 +794,6 @@ export default function Dashboard() {
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Claude Code Terminal - Right Sidebar (wider for better visibility) */}
|
||||
{chatOpen && (
|
||||
<aside className="col-span-5 h-[calc(100vh-12rem)] sticky top-4">
|
||||
<ClaudeTerminal
|
||||
isExpanded={chatExpanded}
|
||||
onToggleExpand={() => setChatExpanded(!chatExpanded)}
|
||||
onClose={() => setChatOpen(false)}
|
||||
/>
|
||||
</aside>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
FolderOpen,
|
||||
Play,
|
||||
Pause,
|
||||
CheckCircle,
|
||||
Clock,
|
||||
AlertCircle,
|
||||
@@ -64,6 +65,8 @@ const Home: React.FC = () => {
|
||||
switch (status) {
|
||||
case 'running':
|
||||
return <Play className="w-3.5 h-3.5" />;
|
||||
case 'paused':
|
||||
return <Pause className="w-3.5 h-3.5" />;
|
||||
case 'completed':
|
||||
return <CheckCircle className="w-3.5 h-3.5" />;
|
||||
case 'not_started':
|
||||
@@ -81,6 +84,12 @@ const Home: React.FC = () => {
|
||||
card: 'border-green-500/30 hover:border-green-500/50',
|
||||
glow: 'shadow-green-500/10'
|
||||
};
|
||||
case 'paused':
|
||||
return {
|
||||
badge: 'bg-orange-500/20 text-orange-400 border-orange-500/30',
|
||||
card: 'border-orange-500/30 hover:border-orange-500/50',
|
||||
glow: 'shadow-orange-500/10'
|
||||
};
|
||||
case 'completed':
|
||||
return {
|
||||
badge: 'bg-blue-500/20 text-blue-400 border-blue-500/30',
|
||||
|
||||
Reference in New Issue
Block a user