Fix file handling for none pdfs

This commit is contained in:
Reece Browne 2025-08-20 17:13:06 +01:00
parent bc350e145f
commit 9c49f329e2
4 changed files with 84 additions and 47 deletions

View File

@ -201,6 +201,11 @@ const FileThumbnail = ({
src={file.thumbnail} src={file.thumbnail}
alt={file.name} alt={file.name}
draggable={false} draggable={false}
onError={(e) => {
// Hide broken image if blob URL was revoked
const img = e.target as HTMLImageElement;
img.style.display = 'none';
}}
style={{ style={{
maxWidth: '100%', maxWidth: '100%',
maxHeight: '100%', maxHeight: '100%',
@ -210,20 +215,22 @@ const FileThumbnail = ({
/> />
</div> </div>
{/* Page count badge */} {/* Page count badge - only show for PDFs */}
<Badge {file.pageCount > 0 && (
size="sm" <Badge
variant="filled" size="sm"
color="blue" variant="filled"
style={{ color="blue"
position: 'absolute', style={{
top: 8, position: 'absolute',
left: 8, top: 8,
zIndex: 3, left: 8,
}} zIndex: 3,
> }}
{file.pageCount} {file.pageCount === 1 ? 'page' : 'pages'} >
</Badge> {file.pageCount} {file.pageCount === 1 ? 'page' : 'pages'}
</Badge>
)}
{/* Unsupported badge */} {/* Unsupported badge */}
{!isSupported && ( {!isSupported && (

View File

@ -92,14 +92,28 @@ export async function addFiles(
let thumbnail: string | undefined; let thumbnail: string | undefined;
let pageCount: number = 1; let pageCount: number = 1;
try { // Route based on file type - PDFs through full metadata pipeline, non-PDFs through simple path
if (DEBUG) console.log(`📄 Generating immediate thumbnail and metadata for ${file.name}`); if (file.type.startsWith('application/pdf')) {
const result = await generateThumbnailWithMetadata(file); try {
thumbnail = result.thumbnail; if (DEBUG) console.log(`📄 Generating PDF metadata for ${file.name}`);
pageCount = result.pageCount; const result = await generateThumbnailWithMetadata(file);
if (DEBUG) console.log(`📄 Generated immediate metadata for ${file.name}: ${pageCount} pages, thumbnail: ${!!thumbnail}`); thumbnail = result.thumbnail;
} catch (error) { pageCount = result.pageCount;
if (DEBUG) console.warn(`📄 Failed to generate immediate metadata for ${file.name}:`, error); if (DEBUG) console.log(`📄 Generated PDF metadata for ${file.name}: ${pageCount} pages, thumbnail: ${!!thumbnail}`);
} catch (error) {
if (DEBUG) console.warn(`📄 Failed to generate PDF metadata for ${file.name}:`, error);
}
} else {
// Non-PDF files: simple thumbnail generation, no page count
try {
if (DEBUG) console.log(`📄 Generating simple thumbnail for non-PDF file ${file.name}`);
const { generateThumbnailForFile } = await import('../../utils/thumbnailUtils');
thumbnail = await generateThumbnailForFile(file);
pageCount = 0; // Non-PDFs have no page count
if (DEBUG) console.log(`📄 Generated simple thumbnail for ${file.name}: no page count, thumbnail: ${!!thumbnail}`);
} catch (error) {
if (DEBUG) console.warn(`📄 Failed to generate simple thumbnail for ${file.name}:`, error);
}
} }
// Create record with immediate thumbnail and page metadata // Create record with immediate thumbnail and page metadata
@ -198,22 +212,28 @@ export async function addFiles(
} }
} }
// Generate processedFile metadata for stored files using PDF worker manager // Generate processedFile metadata for stored files
// This ensures stored files have proper page information and avoids cancellation conflicts
let pageCount: number = 1; let pageCount: number = 1;
try {
if (DEBUG) console.log(`📄 addFiles(stored): Generating metadata for stored file ${file.name}`);
// Use PDF worker manager directly for page count (avoids fileProcessingService conflicts) // Only process PDFs through PDF worker manager, non-PDFs have no page count
const arrayBuffer = await file.arrayBuffer(); if (file.type.startsWith('application/pdf')) {
const { pdfWorkerManager } = await import('../../services/pdfWorkerManager'); try {
const pdf = await pdfWorkerManager.createDocument(arrayBuffer); if (DEBUG) console.log(`📄 addFiles(stored): Generating PDF metadata for stored file ${file.name}`);
pageCount = pdf.numPages;
pdfWorkerManager.destroyDocument(pdf);
if (DEBUG) console.log(`📄 addFiles(stored): Found ${pageCount} pages in stored file ${file.name}`); // Use PDF worker manager directly for page count (avoids fileProcessingService conflicts)
} catch (error) { const arrayBuffer = await file.arrayBuffer();
if (DEBUG) console.warn(`📄 addFiles(stored): Failed to generate metadata for ${file.name}:`, error); const { pdfWorkerManager } = await import('../../services/pdfWorkerManager');
const pdf = await pdfWorkerManager.createDocument(arrayBuffer);
pageCount = pdf.numPages;
pdfWorkerManager.destroyDocument(pdf);
if (DEBUG) console.log(`📄 addFiles(stored): Found ${pageCount} pages in PDF ${file.name}`);
} catch (error) {
if (DEBUG) console.warn(`📄 addFiles(stored): Failed to generate PDF metadata for ${file.name}:`, error);
}
} else {
pageCount = 0; // Non-PDFs have no page count
if (DEBUG) console.log(`📄 addFiles(stored): Non-PDF file ${file.name}, no page count`);
} }
// Create processedFile metadata with correct page count // Create processedFile metadata with correct page count

View File

@ -144,11 +144,14 @@ export class FileLifecycleManager {
if (stateRef) { if (stateRef) {
const record = stateRef.current.files.byId[fileId]; const record = stateRef.current.files.byId[fileId];
if (record) { if (record) {
// Revoke blob URLs from file record // Defer revocation of thumbnail blob URLs to prevent image loading race conditions
if (record.thumbnailUrl && record.thumbnailUrl.startsWith('blob:')) { if (record.thumbnailUrl && record.thumbnailUrl.startsWith('blob:')) {
try { try {
URL.revokeObjectURL(record.thumbnailUrl); // Add a small delay to ensure images have time to load
if (DEBUG) console.log(`🗂️ Revoked thumbnail blob URL for file: ${fileId}`); setTimeout(() => {
URL.revokeObjectURL(record.thumbnailUrl);
if (DEBUG) console.log(`🗂️ Revoked thumbnail blob URL for file: ${fileId}`);
}, 1000); // 1 second delay
} catch (error) { } catch (error) {
if (DEBUG) console.warn('Error revoking thumbnail URL:', error); if (DEBUG) console.warn('Error revoking thumbnail URL:', error);
} }
@ -156,20 +159,27 @@ export class FileLifecycleManager {
if (record.blobUrl && record.blobUrl.startsWith('blob:')) { if (record.blobUrl && record.blobUrl.startsWith('blob:')) {
try { try {
URL.revokeObjectURL(record.blobUrl); // Add a small delay to ensure any pending operations complete
if (DEBUG) console.log(`🗂️ Revoked file blob URL for file: ${fileId}`); setTimeout(() => {
URL.revokeObjectURL(record.blobUrl);
if (DEBUG) console.log(`🗂️ Revoked file blob URL for file: ${fileId}`);
}, 1000); // 1 second delay
} catch (error) { } catch (error) {
if (DEBUG) console.warn('Error revoking file URL:', error); if (DEBUG) console.warn('Error revoking file URL:', error);
} }
} }
// Clean up processed file thumbnails // Clean up processed file thumbnails with delay
if (record.processedFile?.pages) { if (record.processedFile?.pages) {
record.processedFile.pages.forEach((page: ProcessedFilePage, index: number) => { record.processedFile.pages.forEach((page: ProcessedFilePage, index: number) => {
if (page.thumbnail && page.thumbnail.startsWith('blob:')) { if (page.thumbnail && page.thumbnail.startsWith('blob:')) {
try { try {
URL.revokeObjectURL(page.thumbnail); const thumbnailUrl = page.thumbnail;
if (DEBUG) console.log(`🗂️ Revoked page ${index} thumbnail for file: ${fileId}`); // Add delay for page thumbnails too
setTimeout(() => {
URL.revokeObjectURL(thumbnailUrl);
if (DEBUG) console.log(`🗂️ Revoked page ${index} thumbnail for file: ${fileId}`);
}, 1000); // 1 second delay
} catch (error) { } catch (error) {
if (DEBUG) console.warn('Error revoking page thumbnail URL:', error); if (DEBUG) console.warn('Error revoking page thumbnail URL:', error);
} }

View File

@ -368,10 +368,10 @@ export async function generateThumbnailForFile(file: File): Promise<string | und
* Generate thumbnail and extract page count for a PDF file * Generate thumbnail and extract page count for a PDF file
*/ */
export async function generateThumbnailWithMetadata(file: File): Promise<ThumbnailWithMetadata> { export async function generateThumbnailWithMetadata(file: File): Promise<ThumbnailWithMetadata> {
// Non-PDF files default to 1 page // Non-PDF files have no page count
if (!file.type.startsWith('application/pdf')) { if (!file.type.startsWith('application/pdf')) {
const thumbnail = await generateThumbnailForFile(file); const thumbnail = await generateThumbnailForFile(file);
return { thumbnail, pageCount: 1 }; return { thumbnail, pageCount: 0 };
} }
// Skip very large files // Skip very large files