fix(client): resolve broken Debug page
This commit is contained in:
parent
ccc3bc2ce4
commit
66f6e73f77
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue