feat(frontend): view failed document and link to details

This commit is contained in:
aaldebs99 2025-06-28 05:10:38 +00:00
parent 07f62fb2e0
commit 869204e1e6
1 changed files with 122 additions and 58 deletions

View File

@ -1,4 +1,5 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { import {
Box, Box,
Typography, Typography,
@ -30,6 +31,7 @@ import {
Tab, Tab,
TextField, TextField,
useTheme, useTheme,
Divider,
} from '@mui/material'; } from '@mui/material';
import Grid from '@mui/material/GridLegacy'; import Grid from '@mui/material/GridLegacy';
import { import {
@ -44,9 +46,11 @@ import {
FileCopy as FileCopyIcon, FileCopy as FileCopyIcon,
Delete as DeleteIcon, Delete as DeleteIcon,
FindInPage as FindInPageIcon, FindInPage as FindInPageIcon,
OpenInNew as OpenInNewIcon,
} from '@mui/icons-material'; } from '@mui/icons-material';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { api, documentService } from '../services/api'; import { api, documentService } from '../services/api';
import DocumentViewer from '../components/DocumentViewer';
interface FailedDocument { interface FailedDocument {
id: string; id: string;
@ -127,6 +131,7 @@ interface DuplicatesResponse {
const FailedOcrPage: React.FC = () => { const FailedOcrPage: React.FC = () => {
const theme = useTheme(); const theme = useTheme();
const navigate = useNavigate();
const [currentTab, setCurrentTab] = useState(0); const [currentTab, setCurrentTab] = useState(0);
const [documents, setDocuments] = useState<FailedDocument[]>([]); const [documents, setDocuments] = useState<FailedDocument[]>([]);
const [duplicates, setDuplicates] = useState<DuplicateGroup[]>([]); const [duplicates, setDuplicates] = useState<DuplicateGroup[]>([]);
@ -1028,7 +1033,7 @@ const FailedOcrPage: React.FC = () => {
<Dialog <Dialog
open={detailsOpen} open={detailsOpen}
onClose={() => setDetailsOpen(false)} onClose={() => setDetailsOpen(false)}
maxWidth="md" maxWidth="lg"
fullWidth fullWidth
> >
<DialogTitle> <DialogTitle>
@ -1036,74 +1041,122 @@ const FailedOcrPage: React.FC = () => {
</DialogTitle> </DialogTitle>
<DialogContent> <DialogContent>
{selectedDocument && ( {selectedDocument && (
<Grid container spacing={2}> <Grid container spacing={3}>
{/* File Preview Section */}
<Grid item xs={12} md={6}> <Grid item xs={12} md={6}>
<Typography variant="body2" color="text.secondary"> <Typography variant="h6" sx={{ mb: 2 }}>
<strong>Original Filename:</strong> File Preview
</Typography> </Typography>
<Typography variant="body2" sx={{ mb: 2 }}> <Box
{selectedDocument.original_filename} onClick={() => {
</Typography> if (selectedDocument) {
navigate(`/documents/${selectedDocument.id}`);
<Typography variant="body2" color="text.secondary"> }
<strong>File Size:</strong> }}
</Typography> sx={{
<Typography variant="body2" sx={{ mb: 2 }}> cursor: 'pointer',
{formatFileSize(selectedDocument.file_size)} border: '2px dashed',
</Typography> borderColor: 'primary.main',
borderRadius: 2,
<Typography variant="body2" color="text.secondary"> p: 1,
<strong>MIME Type:</strong> transition: 'all 0.2s ease-in-out',
</Typography> '&:hover': {
<Typography variant="body2" sx={{ mb: 2 }}> borderColor: 'primary.dark',
{selectedDocument.mime_type} boxShadow: 2,
</Typography> },
}}
<Typography variant="body2" color="text.secondary"> >
<strong>Tags:</strong> <DocumentViewer
</Typography> documentId={selectedDocument.id}
<Box sx={{ mb: 2 }}> filename={selectedDocument.original_filename}
{selectedDocument.tags.length > 0 ? ( mimeType={selectedDocument.mime_type}
selectedDocument.tags.map((tag) => ( />
<Chip key={tag} label={tag} size="small" sx={{ mr: 1, mb: 1 }} /> <Box sx={{ mt: 1, textAlign: 'center' }}>
)) <Typography variant="caption" color="primary.main">
) : ( Click to open full document details page
<Typography variant="body2" color="text.secondary">No tags</Typography> </Typography>
)} </Box>
</Box> </Box>
</Grid> </Grid>
{/* Document Information Section */}
<Grid item xs={12} md={6}> <Grid item xs={12} md={6}>
<Typography variant="body2" color="text.secondary"> <Typography variant="h6" sx={{ mb: 2 }}>
<strong>Failure Category:</strong> Document Information
</Typography> </Typography>
<Chip <Box>
label={selectedDocument.failure_category} <Typography variant="body2" color="text.secondary">
color={getFailureCategoryColor(selectedDocument.failure_category)} <strong>Original Filename:</strong>
sx={{ mb: 2 }} </Typography>
/> <Typography variant="body2" sx={{ mb: 2 }}>
{selectedDocument.original_filename}
</Typography>
<Typography variant="body2" color="text.secondary"> <Typography variant="body2" color="text.secondary">
<strong>Retry Count:</strong> <strong>File Size:</strong>
</Typography> </Typography>
<Typography variant="body2" sx={{ mb: 2 }}> <Typography variant="body2" sx={{ mb: 2 }}>
{selectedDocument.retry_count} attempts {formatFileSize(selectedDocument.file_size)}
</Typography> </Typography>
<Typography variant="body2" color="text.secondary"> <Typography variant="body2" color="text.secondary">
<strong>Created:</strong> <strong>MIME Type:</strong>
</Typography> </Typography>
<Typography variant="body2" sx={{ mb: 2 }}> <Typography variant="body2" sx={{ mb: 2 }}>
{format(new Date(selectedDocument.created_at), 'PPpp')} {selectedDocument.mime_type}
</Typography> </Typography>
<Typography variant="body2" color="text.secondary"> <Typography variant="body2" color="text.secondary">
<strong>Last Updated:</strong> <strong>Failure Category:</strong>
</Typography> </Typography>
<Typography variant="body2"> <Chip
{format(new Date(selectedDocument.updated_at), 'PPpp')} label={selectedDocument.failure_category}
</Typography> color={getFailureCategoryColor(selectedDocument.failure_category)}
sx={{ mb: 2 }}
/>
<Typography variant="body2" color="text.secondary" sx={{ mt: 2 }}>
<strong>Retry Count:</strong>
</Typography>
<Typography variant="body2" sx={{ mb: 2 }}>
{selectedDocument.retry_count} attempts
</Typography>
<Typography variant="body2" color="text.secondary">
<strong>Created:</strong>
</Typography>
<Typography variant="body2" sx={{ mb: 2 }}>
{format(new Date(selectedDocument.created_at), 'PPpp')}
</Typography>
<Typography variant="body2" color="text.secondary">
<strong>Last Updated:</strong>
</Typography>
<Typography variant="body2">
{format(new Date(selectedDocument.updated_at), 'PPpp')}
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mt: 2 }}>
<strong>Tags:</strong>
</Typography>
<Box sx={{ mb: 2 }}>
{selectedDocument.tags.length > 0 ? (
selectedDocument.tags.map((tag) => (
<Chip key={tag} label={tag} size="small" sx={{ mr: 1, mb: 1 }} />
))
) : (
<Typography variant="body2" color="text.secondary">No tags</Typography>
)}
</Box>
</Box>
</Grid> </Grid>
{/* Error Details Section */}
<Grid item xs={12}> <Grid item xs={12}>
<Divider sx={{ my: 2 }} />
<Typography variant="h6" sx={{ mb: 2 }}>
Error Details
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}> <Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
<strong>Full Error Message:</strong> <strong>Full Error Message:</strong>
</Typography> </Typography>
@ -1125,6 +1178,17 @@ const FailedOcrPage: React.FC = () => {
)} )}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button
onClick={() => {
if (selectedDocument) {
navigate(`/documents/${selectedDocument.id}`);
}
}}
startIcon={<OpenInNewIcon />}
color="primary"
>
Open Document Details
</Button>
{selectedDocument?.can_retry && ( {selectedDocument?.can_retry && (
<Button <Button
onClick={() => { onClick={() => {