diff --git a/frontend/src/components/pageEditor/FileThumbnail.tsx b/frontend/src/components/pageEditor/FileThumbnail.tsx
index 7d450104d..7aca80565 100644
--- a/frontend/src/components/pageEditor/FileThumbnail.tsx
+++ b/frontend/src/components/pageEditor/FileThumbnail.tsx
@@ -201,6 +201,11 @@ const FileThumbnail = ({
src={file.thumbnail}
alt={file.name}
draggable={false}
+ onError={(e) => {
+ // Hide broken image if blob URL was revoked
+ const img = e.target as HTMLImageElement;
+ img.style.display = 'none';
+ }}
style={{
maxWidth: '100%',
maxHeight: '100%',
@@ -210,20 +215,22 @@ const FileThumbnail = ({
/>
- {/* Page count badge */}
-
- {file.pageCount} {file.pageCount === 1 ? 'page' : 'pages'}
-
+ {/* Page count badge - only show for PDFs */}
+ {file.pageCount > 0 && (
+
+ {file.pageCount} {file.pageCount === 1 ? 'page' : 'pages'}
+
+ )}
{/* Unsupported badge */}
{!isSupported && (
diff --git a/frontend/src/contexts/file/fileActions.ts b/frontend/src/contexts/file/fileActions.ts
index 8f32fa521..1a678fa76 100644
--- a/frontend/src/contexts/file/fileActions.ts
+++ b/frontend/src/contexts/file/fileActions.ts
@@ -92,14 +92,28 @@ export async function addFiles(
let thumbnail: string | undefined;
let pageCount: number = 1;
- try {
- if (DEBUG) console.log(`📄 Generating immediate thumbnail and metadata for ${file.name}`);
- const result = await generateThumbnailWithMetadata(file);
- thumbnail = result.thumbnail;
- pageCount = result.pageCount;
- if (DEBUG) console.log(`📄 Generated immediate metadata for ${file.name}: ${pageCount} pages, thumbnail: ${!!thumbnail}`);
- } catch (error) {
- if (DEBUG) console.warn(`📄 Failed to generate immediate metadata for ${file.name}:`, error);
+ // Route based on file type - PDFs through full metadata pipeline, non-PDFs through simple path
+ if (file.type.startsWith('application/pdf')) {
+ try {
+ if (DEBUG) console.log(`📄 Generating PDF metadata for ${file.name}`);
+ const result = await generateThumbnailWithMetadata(file);
+ thumbnail = result.thumbnail;
+ pageCount = result.pageCount;
+ 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
@@ -198,22 +212,28 @@ export async function addFiles(
}
}
- // Generate processedFile metadata for stored files using PDF worker manager
- // This ensures stored files have proper page information and avoids cancellation conflicts
+ // Generate processedFile metadata for stored files
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)
- const arrayBuffer = await file.arrayBuffer();
- 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 stored file ${file.name}`);
- } catch (error) {
- if (DEBUG) console.warn(`📄 addFiles(stored): Failed to generate metadata for ${file.name}:`, error);
+
+ // Only process PDFs through PDF worker manager, non-PDFs have no page count
+ if (file.type.startsWith('application/pdf')) {
+ try {
+ if (DEBUG) console.log(`📄 addFiles(stored): Generating PDF metadata for stored file ${file.name}`);
+
+ // Use PDF worker manager directly for page count (avoids fileProcessingService conflicts)
+ const arrayBuffer = await file.arrayBuffer();
+ 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
diff --git a/frontend/src/contexts/file/lifecycle.ts b/frontend/src/contexts/file/lifecycle.ts
index 1879896a2..a984d48cd 100644
--- a/frontend/src/contexts/file/lifecycle.ts
+++ b/frontend/src/contexts/file/lifecycle.ts
@@ -144,11 +144,14 @@ export class FileLifecycleManager {
if (stateRef) {
const record = stateRef.current.files.byId[fileId];
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:')) {
try {
- URL.revokeObjectURL(record.thumbnailUrl);
- if (DEBUG) console.log(`🗂️ Revoked thumbnail blob URL for file: ${fileId}`);
+ // Add a small delay to ensure images have time to load
+ setTimeout(() => {
+ URL.revokeObjectURL(record.thumbnailUrl);
+ if (DEBUG) console.log(`🗂️ Revoked thumbnail blob URL for file: ${fileId}`);
+ }, 1000); // 1 second delay
} catch (error) {
if (DEBUG) console.warn('Error revoking thumbnail URL:', error);
}
@@ -156,20 +159,27 @@ export class FileLifecycleManager {
if (record.blobUrl && record.blobUrl.startsWith('blob:')) {
try {
- URL.revokeObjectURL(record.blobUrl);
- if (DEBUG) console.log(`🗂️ Revoked file blob URL for file: ${fileId}`);
+ // Add a small delay to ensure any pending operations complete
+ setTimeout(() => {
+ URL.revokeObjectURL(record.blobUrl);
+ if (DEBUG) console.log(`🗂️ Revoked file blob URL for file: ${fileId}`);
+ }, 1000); // 1 second delay
} catch (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) {
record.processedFile.pages.forEach((page: ProcessedFilePage, index: number) => {
if (page.thumbnail && page.thumbnail.startsWith('blob:')) {
try {
- URL.revokeObjectURL(page.thumbnail);
- if (DEBUG) console.log(`🗂️ Revoked page ${index} thumbnail for file: ${fileId}`);
+ const thumbnailUrl = page.thumbnail;
+ // 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) {
if (DEBUG) console.warn('Error revoking page thumbnail URL:', error);
}
diff --git a/frontend/src/utils/thumbnailUtils.ts b/frontend/src/utils/thumbnailUtils.ts
index 3335e2bb6..adccead4f 100644
--- a/frontend/src/utils/thumbnailUtils.ts
+++ b/frontend/src/utils/thumbnailUtils.ts
@@ -368,10 +368,10 @@ export async function generateThumbnailForFile(file: File): Promise {
- // Non-PDF files default to 1 page
+ // Non-PDF files have no page count
if (!file.type.startsWith('application/pdf')) {
const thumbnail = await generateThumbnailForFile(file);
- return { thumbnail, pageCount: 1 };
+ return { thumbnail, pageCount: 0 };
}
// Skip very large files