Files
gridpilot.gg/apps/companion/renderer/components/SessionProgressMonitor.tsx

208 lines
6.5 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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>
);
}