208 lines
6.5 KiB
TypeScript
208 lines
6.5 KiB
TypeScript
import React from 'react';
|
||
|
||
interface SessionProgress {
|
||
sessionId: string;
|
||
currentStep: number;
|
||
state: string;
|
||
completedSteps: number[];
|
||
hasError: boolean;
|
||
errorMessage: string | null;
|
||
}
|
||
|
||
interface SessionProgressMonitorProps {
|
||
sessionId: string | null;
|
||
progress: SessionProgress | null;
|
||
isRunning: boolean;
|
||
}
|
||
|
||
const STEP_NAMES: { [key: number]: string } = {
|
||
1: 'Navigate to Hosted Racing',
|
||
2: 'Click Create a Race',
|
||
3: 'Fill Race Information',
|
||
4: 'Configure Server Details',
|
||
5: 'Set Admins',
|
||
6: 'Add Admin',
|
||
7: 'Set Time Limits',
|
||
8: 'Set Cars',
|
||
9: 'Add Car',
|
||
10: 'Set Car Classes',
|
||
11: 'Set Track',
|
||
12: 'Add Track',
|
||
13: 'Configure Track Options',
|
||
14: 'Set Time of Day',
|
||
15: 'Configure Weather',
|
||
16: 'Set Race Options',
|
||
17: 'Configure Team Driving',
|
||
18: 'Set Track Conditions'
|
||
};
|
||
|
||
export function SessionProgressMonitor({ sessionId, progress, isRunning }: SessionProgressMonitorProps) {
|
||
const getStateColor = (state: string) => {
|
||
switch (state) {
|
||
case 'IN_PROGRESS': return '#0066cc';
|
||
case 'COMPLETED': return '#28a745';
|
||
case 'FAILED': return '#dc3545';
|
||
case 'STOPPED_AT_STEP_18': return '#ffc107';
|
||
default: return '#6c757d';
|
||
}
|
||
};
|
||
|
||
const getStateLabel = (state: string) => {
|
||
switch (state) {
|
||
case 'IN_PROGRESS': return 'Running';
|
||
case 'COMPLETED': return 'Completed';
|
||
case 'FAILED': return 'Failed';
|
||
case 'STOPPED_AT_STEP_18': return 'Stopped at Step 18';
|
||
default: return state;
|
||
}
|
||
};
|
||
|
||
if (!sessionId && !isRunning) {
|
||
return (
|
||
<div style={{ textAlign: 'center', color: '#666', paddingTop: '4rem' }}>
|
||
<h2 style={{ marginBottom: '1rem' }}>Session Progress</h2>
|
||
<p>Configure and start an automation session to see progress here.</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div>
|
||
<h2 style={{ marginBottom: '1.5rem', color: '#fff' }}>Session Progress</h2>
|
||
|
||
{sessionId && (
|
||
<div style={{
|
||
marginBottom: '2rem',
|
||
padding: '1rem',
|
||
backgroundColor: '#1a1a1a',
|
||
borderRadius: '4px',
|
||
border: '1px solid #333'
|
||
}}>
|
||
<div style={{ marginBottom: '0.5rem', color: '#aaa', fontSize: '14px' }}>
|
||
Session ID
|
||
</div>
|
||
<div style={{ fontFamily: 'monospace', fontSize: '12px', color: '#fff' }}>
|
||
{sessionId}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{progress && (
|
||
<>
|
||
<div style={{
|
||
marginBottom: '2rem',
|
||
padding: '1rem',
|
||
backgroundColor: '#1a1a1a',
|
||
borderRadius: '4px',
|
||
border: '1px solid #333'
|
||
}}>
|
||
<div style={{ marginBottom: '0.5rem', color: '#aaa', fontSize: '14px' }}>
|
||
Status
|
||
</div>
|
||
<div style={{
|
||
fontSize: '18px',
|
||
fontWeight: 'bold',
|
||
color: getStateColor(progress.state)
|
||
}}>
|
||
{getStateLabel(progress.state)}
|
||
</div>
|
||
</div>
|
||
|
||
{progress.state === 'STOPPED_AT_STEP_18' && (
|
||
<div style={{
|
||
marginBottom: '2rem',
|
||
padding: '1rem',
|
||
backgroundColor: '#332b00',
|
||
border: '1px solid #ffc107',
|
||
borderRadius: '4px',
|
||
color: '#ffc107'
|
||
}}>
|
||
<strong>⚠️ Safety Stop</strong>
|
||
<p style={{ marginTop: '0.5rem', fontSize: '14px', lineHeight: '1.5' }}>
|
||
Automation stopped at step 18 (Track Conditions) as configured.
|
||
This prevents accidental session creation during POC demonstration.
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{progress.hasError && progress.errorMessage && (
|
||
<div style={{
|
||
marginBottom: '2rem',
|
||
padding: '1rem',
|
||
backgroundColor: '#2d0a0a',
|
||
border: '1px solid #dc3545',
|
||
borderRadius: '4px',
|
||
color: '#dc3545'
|
||
}}>
|
||
<strong>Error</strong>
|
||
<p style={{ marginTop: '0.5rem', fontSize: '14px' }}>
|
||
{progress.errorMessage}
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
<div style={{ marginBottom: '1rem', color: '#aaa', fontSize: '14px' }}>
|
||
Progress: {progress.completedSteps.length} / 18 steps
|
||
</div>
|
||
|
||
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
|
||
{Object.entries(STEP_NAMES).map(([stepNum, stepName]) => {
|
||
const step = parseInt(stepNum);
|
||
const isCompleted = progress.completedSteps.includes(step);
|
||
const isCurrent = progress.currentStep === step;
|
||
|
||
return (
|
||
<div
|
||
key={step}
|
||
style={{
|
||
padding: '0.75rem',
|
||
backgroundColor: isCurrent ? '#1a3a1a' : isCompleted ? '#0d2b0d' : '#1a1a1a',
|
||
border: `1px solid ${isCurrent ? '#28a745' : isCompleted ? '#1d4d1d' : '#333'}`,
|
||
borderRadius: '4px',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: '1rem'
|
||
}}
|
||
>
|
||
<div style={{
|
||
width: '30px',
|
||
height: '30px',
|
||
borderRadius: '50%',
|
||
backgroundColor: isCompleted ? '#28a745' : isCurrent ? '#0066cc' : '#333',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
color: '#fff',
|
||
fontSize: '14px',
|
||
fontWeight: 'bold',
|
||
flexShrink: 0
|
||
}}>
|
||
{isCompleted ? '✓' : step}
|
||
</div>
|
||
<div style={{ flex: 1 }}>
|
||
<div style={{
|
||
color: isCurrent ? '#28a745' : isCompleted ? '#aaa' : '#666',
|
||
fontSize: '14px',
|
||
fontWeight: isCurrent ? 'bold' : 'normal'
|
||
}}>
|
||
{stepName}
|
||
</div>
|
||
</div>
|
||
{isCurrent && (
|
||
<div style={{
|
||
fontSize: '12px',
|
||
color: '#0066cc',
|
||
fontWeight: 'bold'
|
||
}}>
|
||
IN PROGRESS
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
</>
|
||
)}
|
||
</div>
|
||
);
|
||
} |