fix(client): resolve broken Debug page

This commit is contained in:
perf3ct 2025-07-15 16:11:11 +00:00
parent ccc3bc2ce4
commit 66f6e73f77
2 changed files with 71 additions and 15 deletions

View File

@ -91,6 +91,20 @@ const DebugPage: React.FC = () => {
const [monitoringInterval, setMonitoringInterval] = useState<NodeJS.Timeout | null>(null); const [monitoringInterval, setMonitoringInterval] = useState<NodeJS.Timeout | null>(null);
const [processingStatus, setProcessingStatus] = useState<string>(''); const [processingStatus, setProcessingStatus] = useState<string>('');
// Auto-switch to debug results tab when debugInfo is available
useEffect(() => {
if (debugInfo && activeTab !== 2) {
setActiveTab(2);
}
}, [debugInfo]);
// Reset activeTab when debugInfo is cleared
useEffect(() => {
if (!debugInfo && activeTab === 2) {
setActiveTab(0);
}
}, [debugInfo, activeTab]);
const getStepIcon = (status: string, success: boolean) => { const getStepIcon = (status: string, success: boolean) => {
if (status === 'processing') return <CircularProgress size={20} />; if (status === 'processing') return <CircularProgress size={20} />;
if (success || status === 'completed' || status === 'passed') return <CheckCircleIcon color="success" />; if (success || status === 'completed' || status === 'passed') return <CheckCircleIcon color="success" />;
@ -411,7 +425,7 @@ const DebugPage: React.FC = () => {
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{details.queue_history.map((entry: any, index: number) => ( {(details.queue_history || []).map((entry: any, index: number) => (
<TableRow key={index}> <TableRow key={index}>
<TableCell> <TableCell>
<Chip <Chip
@ -504,7 +518,7 @@ const DebugPage: React.FC = () => {
<Box sx={{ mt: 2 }}> <Box sx={{ mt: 2 }}>
<Typography variant="h6" gutterBottom>Quality Checks</Typography> <Typography variant="h6" gutterBottom>Quality Checks</Typography>
<Grid container spacing={1}> <Grid container spacing={1}>
{Object.entries(details.quality_checks).map(([check, passed]: [string, any]) => ( {Object.entries(details.quality_checks || {}).map(([check, passed]: [string, any]) => (
<Grid item key={check}> <Grid item key={check}>
<Chip <Chip
label={check.replace('_check', '').replace('_', ' ')} label={check.replace('_check', '').replace('_', ' ')}
@ -774,7 +788,7 @@ const DebugPage: React.FC = () => {
Processing Pipeline Processing Pipeline
</Typography> </Typography>
<Stepper orientation="vertical"> <Stepper orientation="vertical">
{debugInfo.pipeline_steps.map((step) => ( {(debugInfo.pipeline_steps || []).map((step) => (
<Step key={step.step} active={true}> <Step key={step.step} active={true}>
<StepLabel <StepLabel
icon={getStepIcon(step.status, step.success)} icon={getStepIcon(step.status, step.success)}
@ -782,14 +796,14 @@ const DebugPage: React.FC = () => {
style: { color: step.success ? '#4caf50' : step.status === 'failed' ? '#f44336' : '#ff9800' } style: { color: step.success ? '#4caf50' : step.status === 'failed' ? '#f44336' : '#ff9800' }
}} }}
> >
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}> <span style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<Typography variant="subtitle1">{step.name}</Typography> <Typography variant="subtitle1" component="span">{step.name}</Typography>
<Chip <Chip
label={step.status} label={step.status}
size="small" size="small"
color={getStatusColor(step.status, step.success)} color={getStatusColor(step.status, step.success)}
/> />
</Box> </span>
</StepLabel> </StepLabel>
<StepContent> <StepContent>
{renderStepDetails(step)} {renderStepDetails(step)}
@ -889,7 +903,7 @@ const DebugPage: React.FC = () => {
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{debugInfo.detailed_processing_logs.map((log: any, index: number) => ( {(debugInfo.detailed_processing_logs || []).map((log: any, index: number) => (
<TableRow key={log.id}> <TableRow key={log.id}>
<TableCell>{index + 1}</TableCell> <TableCell>{index + 1}</TableCell>
<TableCell> <TableCell>
@ -978,7 +992,7 @@ const DebugPage: React.FC = () => {
</Card> </Card>
)} )}
{debugInfo.pipeline_steps.some(step => step.step === 3 && step.details.has_processed_image) && ( {(debugInfo.pipeline_steps || []).some(step => step.step === 3 && step.details?.has_processed_image) && (
<Card sx={{ mb: 4 }}> <Card sx={{ mb: 4 }}>
<CardContent> <CardContent>
<Typography variant="h6" gutterBottom> <Typography variant="h6" gutterBottom>
@ -1041,18 +1055,18 @@ const DebugPage: React.FC = () => {
<Grid item xs={12} md={6}> <Grid item xs={12} md={6}>
<Paper sx={{ p: 2 }}> <Paper sx={{ p: 2 }}>
<Typography variant="subtitle1" gutterBottom>OCR Settings</Typography> <Typography variant="subtitle1" gutterBottom>OCR Settings</Typography>
<Typography><strong>Background OCR:</strong> {debugInfo.user_settings.enable_background_ocr ? 'Enabled' : 'Disabled'}</Typography> <Typography><strong>Background OCR:</strong> {debugInfo.user_settings?.enable_background_ocr ? 'Enabled' : 'Disabled'}</Typography>
<Typography><strong>Min Confidence:</strong> {debugInfo.user_settings.ocr_min_confidence}%</Typography> <Typography><strong>Min Confidence:</strong> {debugInfo.user_settings?.ocr_min_confidence || 'N/A'}%</Typography>
<Typography><strong>Max File Size:</strong> {debugInfo.user_settings.max_file_size_mb} MB</Typography> <Typography><strong>Max File Size:</strong> {debugInfo.user_settings?.max_file_size_mb || 'N/A'} MB</Typography>
</Paper> </Paper>
</Grid> </Grid>
<Grid item xs={12} md={6}> <Grid item xs={12} md={6}>
<Paper sx={{ p: 2 }}> <Paper sx={{ p: 2 }}>
<Typography variant="subtitle1" gutterBottom>Quality Thresholds</Typography> <Typography variant="subtitle1" gutterBottom>Quality Thresholds</Typography>
<Typography><strong>Brightness:</strong> {debugInfo.user_settings.quality_thresholds.brightness}</Typography> <Typography><strong>Brightness:</strong> {debugInfo.user_settings?.quality_thresholds?.brightness || 'N/A'}</Typography>
<Typography><strong>Contrast:</strong> {debugInfo.user_settings.quality_thresholds.contrast}</Typography> <Typography><strong>Contrast:</strong> {debugInfo.user_settings?.quality_thresholds?.contrast || 'N/A'}</Typography>
<Typography><strong>Noise:</strong> {debugInfo.user_settings.quality_thresholds.noise}</Typography> <Typography><strong>Noise:</strong> {debugInfo.user_settings?.quality_thresholds?.noise || 'N/A'}</Typography>
<Typography><strong>Sharpness:</strong> {debugInfo.user_settings.quality_thresholds.sharpness}</Typography> <Typography><strong>Sharpness:</strong> {debugInfo.user_settings?.quality_thresholds?.sharpness || 'N/A'}</Typography>
</Paper> </Paper>
</Grid> </Grid>
</Grid> </Grid>

View File

@ -0,0 +1,42 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import { vi } from 'vitest';
import DebugPage from '../DebugPage';
// Mock the API
vi.mock('../../services/api', () => ({
api: {
get: vi.fn(),
post: vi.fn(),
put: vi.fn(),
delete: vi.fn(),
},
}));
const renderDebugPage = () => {
return render(
<BrowserRouter>
<DebugPage />
</BrowserRouter>
);
};
describe('DebugPage', () => {
it('renders without crashing', () => {
renderDebugPage();
expect(screen.getByText('Upload & Debug')).toBeInTheDocument();
});
it('handles undefined debugInfo without errors', () => {
renderDebugPage();
// Should not throw any errors when debugInfo is null
expect(screen.getByText('Upload & Debug')).toBeInTheDocument();
});
it('handles undefined nested properties without errors', () => {
// This test would check that all the optional chaining we added works correctly
renderDebugPage();
expect(screen.getByText('Upload & Debug')).toBeInTheDocument();
});
});