Processed File
-
-
{% endif %}
diff --git a/frontend/templates/files.html b/frontend/templates/files.html
index 0d780e16..e27e295b 100644
--- a/frontend/templates/files.html
+++ b/frontend/templates/files.html
@@ -835,27 +835,17 @@
// Process the dropped files
processFiles(e.dataTransfer.files, uploadProgressContainer, uploadStatusMessage);
-
- // Optionally reload page after uploads complete (with a delay)
- setTimeout(() => {
- const fileStatuses = document.querySelectorAll('.file-status');
- let allCompleted = true;
- fileStatuses.forEach(status => {
- if (!status.textContent.includes('Success') && !status.textContent.includes('Error')) {
- allCompleted = false;
- }
- });
-
- if (allCompleted && fileStatuses.length > 0) {
- // Refresh the page after a short delay to show the new files
- setTimeout(() => {
- window.location.reload();
- }, 2000);
- }
- }, 1000);
}
});
+ // Listen for upload completion event and reload the page to show new files
+ window.addEventListener('allUploadsComplete', (e) => {
+ // Wait 2 seconds to let users see the success message
+ setTimeout(() => {
+ window.location.reload();
+ }, 2000);
+ });
+
function closeUploadModal() {
uploadModal.classList.remove('active');
}
From 98fe5ab864f05f63b5012ce9bdcbbf023bf53dc8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 8 Feb 2026 16:14:45 +0000
Subject: [PATCH 3/4] test: add inline preview header verification test
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
---
tests/test_file_detail_endpoints.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tests/test_file_detail_endpoints.py b/tests/test_file_detail_endpoints.py
index 1cdc1f0f..d7b52233 100644
--- a/tests/test_file_detail_endpoints.py
+++ b/tests/test_file_detail_endpoints.py
@@ -150,6 +150,9 @@ class TestFilePreview:
response = client.get(f"/api/files/{file_record.id}/preview?version=original")
assert response.status_code == 200
assert response.headers["content-type"].startswith("application/pdf")
+ # Verify file is set to display inline, not download
+ assert "content-disposition" in response.headers
+ assert "inline" in response.headers["content-disposition"]
def test_preview_processed_file_not_found(self, client: TestClient, db_session, sample_pdf_path):
"""Test getting processed file preview when it doesn't exist."""
From 334714423e4ea25dc0d0d8da33fe9a5badf6be13 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 8 Feb 2026 16:16:31 +0000
Subject: [PATCH 4/4] fix(ui): address code review feedback on inline preview
- Remove invalid type attribute from iframe elements
- Add dedicated download endpoint with attachment disposition
- Update download links to use new endpoint instead of preview
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
---
app/api/files.py | 72 +++++++++++++++++++++++++++++
frontend/templates/file_detail.html | 8 ++--
2 files changed, 76 insertions(+), 4 deletions(-)
diff --git a/app/api/files.py b/app/api/files.py
index ab1ba50a..e642aaab 100644
--- a/app/api/files.py
+++ b/app/api/files.py
@@ -578,6 +578,78 @@ def get_file_preview(
raise HTTPException(status_code=500, detail=f"Error retrieving file preview: {str(e)}")
+@router.get("/files/{file_id}/download")
+@require_login
+def download_file(
+ request: Request,
+ file_id: int,
+ version: str = Query("original", description="original or processed"),
+ db: Session = Depends(get_db),
+):
+ """
+ Download file (original or processed version) as attachment.
+
+ Args:
+ file_id: ID of the file
+ version: "original" for tmp file, "processed" for processed file
+
+ Returns:
+ File content as attachment download
+ """
+ from fastapi.responses import FileResponse
+
+ try:
+ # Find the file record
+ file_record = db.query(FileRecord).filter(FileRecord.id == file_id).first()
+
+ if not file_record:
+ raise HTTPException(status_code=404, detail=f"File with ID {file_id} not found")
+
+ if version == "original":
+ # Return the original file from tmp
+ if not file_record.local_filename or not os.path.exists(file_record.local_filename):
+ raise HTTPException(status_code=404, detail="Original file not found on disk")
+
+ file_path = file_record.local_filename
+
+ elif version == "processed":
+ # Look for processed file in /workdir/processed/
+ workdir = settings.workdir
+ processed_dir = os.path.join(workdir, "processed")
+
+ # Try to find the processed file (same hash or UUID-based naming)
+ base_filename = os.path.splitext(file_record.original_filename)[0]
+ potential_paths = [
+ os.path.join(processed_dir, f"{file_record.filehash}.pdf"),
+ os.path.join(processed_dir, f"{base_filename}_processed.pdf"),
+ os.path.join(processed_dir, file_record.original_filename),
+ ]
+
+ file_path = None
+ for path in potential_paths:
+ if os.path.exists(path):
+ file_path = path
+ break
+
+ if not file_path:
+ raise HTTPException(status_code=404, detail="Processed file not found")
+ else:
+ raise HTTPException(status_code=400, detail="Invalid version parameter. Use 'original' or 'processed'")
+
+ # Return the file with attachment disposition to trigger download
+ return FileResponse(
+ path=file_path,
+ media_type=file_record.mime_type or "application/pdf",
+ headers={"Content-Disposition": f'attachment; filename="{file_record.original_filename}"'},
+ )
+
+ except HTTPException:
+ raise
+ except Exception as e:
+ logger.exception(f"Error downloading file: {str(e)}")
+ raise HTTPException(status_code=500, detail=f"Error downloading file: {str(e)}")
+
+
@router.post("/ui-upload")
@require_login
async def ui_upload(request: Request, file: UploadFile = File(...)):
diff --git a/frontend/templates/file_detail.html b/frontend/templates/file_detail.html
index 93c05010..35203cbf 100644
--- a/frontend/templates/file_detail.html
+++ b/frontend/templates/file_detail.html
@@ -871,14 +871,14 @@
{% else %}
-
+
{% endif %}