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>
This commit is contained in:
copilot-swe-agent[bot]
2026-02-08 16:16:31 +00:00
parent 98fe5ab864
commit 334714423e
2 changed files with 76 additions and 4 deletions
+72
View File
@@ -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(...)):
+4 -4
View File
@@ -871,14 +871,14 @@
<iframe src="/api/files/{{ file.id }}/preview?version=original" style="width: 100%; height: 600px; border: none;"></iframe>
{% else %}
<!-- PDF and other documents -->
<iframe src="/api/files/{{ file.id }}/preview?version=original" type="application/pdf" style="width: 100%; height: 600px; border: none;"></iframe>
<iframe src="/api/files/{{ file.id }}/preview?version=original" style="width: 100%; height: 600px; border: none;"></iframe>
{% endif %}
</div>
<div style="margin-top: 0.5rem; text-align: center; display: flex; gap: 1rem; justify-content: center;">
<a href="/api/files/{{ file.id }}/preview?version=original" target="_blank" style="color: #3182ce; text-decoration: none; font-size: 0.875rem;">
<i class="fas fa-external-link-alt"></i> Open in new tab
</a>
<a href="/api/files/{{ file.id }}/preview?version=original" download="{{ file.original_filename }}" style="color: #3182ce; text-decoration: none; font-size: 0.875rem;">
<a href="/api/files/{{ file.id }}/download?version=original" style="color: #3182ce; text-decoration: none; font-size: 0.875rem;">
<i class="fas fa-download"></i> Download
</a>
</div>
@@ -890,13 +890,13 @@
<h4 style="font-weight: 600; color: #2d3748; margin-bottom: 1rem;">Processed File</h4>
<div style="border: 2px solid #e2e8f0; border-radius: 0.5rem; overflow: hidden; background-color: #f7fafc;">
<!-- Processed files are typically PDFs -->
<iframe src="/api/files/{{ file.id }}/preview?version=processed" type="application/pdf" style="width: 100%; height: 600px; border: none;"></iframe>
<iframe src="/api/files/{{ file.id }}/preview?version=processed" style="width: 100%; height: 600px; border: none;"></iframe>
</div>
<div style="margin-top: 0.5rem; text-align: center; display: flex; gap: 1rem; justify-content: center;">
<a href="/api/files/{{ file.id }}/preview?version=processed" target="_blank" style="color: #3182ce; text-decoration: none; font-size: 0.875rem;">
<i class="fas fa-external-link-alt"></i> Open in new tab
</a>
<a href="/api/files/{{ file.id }}/preview?version=processed" download="{{ file.original_filename }}" style="color: #3182ce; text-decoration: none; font-size: 0.875rem;">
<a href="/api/files/{{ file.id }}/download?version=processed" style="color: #3182ce; text-decoration: none; font-size: 0.875rem;">
<i class="fas fa-download"></i> Download
</a>
</div>