feat(frontend): view failed document and link to details
This commit is contained in:
parent
07f62fb2e0
commit
869204e1e6
|
|
@ -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={() => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue