import { useState, useEffect } from 'react'; import { Activity, Clock, Cpu, Zap, CheckCircle } from 'lucide-react'; interface CurrentTrialProps { studyId: string | null; totalTrials: number; completedTrials: number; isRunning: boolean; lastTrialTime?: number; // ms for last trial } type TrialPhase = 'idle' | 'sampling' | 'evaluating' | 'extracting' | 'complete'; export function CurrentTrialPanel({ studyId, totalTrials, completedTrials, isRunning, lastTrialTime }: CurrentTrialProps) { const [elapsedTime, setElapsedTime] = useState(0); const [phase, setPhase] = useState('idle'); // Simulate phase progression when running useEffect(() => { if (!isRunning) { setPhase('idle'); setElapsedTime(0); return; } setPhase('sampling'); const interval = setInterval(() => { setElapsedTime(prev => { const newTime = prev + 1; // Simulate phase transitions based on typical timing if (newTime < 2) setPhase('sampling'); else if (newTime < 5) setPhase('evaluating'); else setPhase('extracting'); return newTime; }); }, 1000); return () => clearInterval(interval); }, [isRunning, completedTrials]); // Reset elapsed time when a new trial completes useEffect(() => { if (isRunning) { setElapsedTime(0); setPhase('sampling'); } }, [completedTrials, isRunning]); // Calculate ETA const calculateETA = () => { if (!isRunning || completedTrials === 0 || !lastTrialTime) return null; const remainingTrials = totalTrials - completedTrials; const avgTimePerTrial = lastTrialTime / 1000; // convert to seconds const etaSeconds = remainingTrials * avgTimePerTrial; if (etaSeconds < 60) return `~${Math.round(etaSeconds)}s`; if (etaSeconds < 3600) return `~${Math.round(etaSeconds / 60)}m`; return `~${(etaSeconds / 3600).toFixed(1)}h`; }; const progressPercent = totalTrials > 0 ? (completedTrials / totalTrials) * 100 : 0; const eta = calculateETA(); const getPhaseInfo = () => { switch (phase) { case 'sampling': return { label: 'Sampling', color: 'text-blue-400', bgColor: 'bg-blue-500/20', icon: Zap }; case 'evaluating': return { label: 'FEA Solving', color: 'text-yellow-400', bgColor: 'bg-yellow-500/20', icon: Cpu }; case 'extracting': return { label: 'Extracting', color: 'text-purple-400', bgColor: 'bg-purple-500/20', icon: Activity }; case 'complete': return { label: 'Complete', color: 'text-green-400', bgColor: 'bg-green-500/20', icon: CheckCircle }; default: return { label: 'Idle', color: 'text-dark-400', bgColor: 'bg-dark-600', icon: Clock }; } }; const phaseInfo = getPhaseInfo(); const PhaseIcon = phaseInfo.icon; if (!studyId) return null; return (
{/* Header Row */}
{isRunning ? `Trial #${completedTrials + 1}` : 'Optimization Status'}
{isRunning && ( {phaseInfo.label} )}
{/* Progress Bar */}
Progress {completedTrials} / {totalTrials} trials
{/* Stats Row */}
{/* Elapsed Time */}
{isRunning ? `${elapsedTime}s` : '--'}
Elapsed
{/* Completion */}
{progressPercent.toFixed(1)}%
Complete
{/* ETA */}
{eta || '--'}
ETA
{/* Running indicator */} {isRunning && (
Optimization in progress...
)} {/* Paused/Stopped indicator */} {!isRunning && completedTrials > 0 && completedTrials < totalTrials && (
Optimization paused
)} {/* Completed indicator */} {!isRunning && completedTrials >= totalTrials && totalTrials > 0 && (
Optimization complete
)}
); }