The Alembic migration alone doesn't run automatically. Add the
saved_searches table creation to _run_schema_migrations() in
database.py so existing databases are upgraded at startup.
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Add date range (date_from/date_to), storage provider, and tags filters to GET /api/files
- Add SavedSearch model and migration (005_add_saved_searches)
- Add CRUD API endpoints for saved searches at /api/saved-searches
- Update files.html template with new filter controls and saved searches UI
- Update files view to pass new filter parameters to template
- Add comprehensive tests for all new functionality (26 tests)
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Change default `version` param from 'original' to 'processed' so
GET /api/files/{id}/download (no param) returns the processed file
- Update docstring to reflect new default
- Add tests: ?version=processed, default→processed, invalid→400
- Fix test_file_download_missing_mime_type to use explicit ?version=original
- Add File Download section to docs/API.md
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
Also updates UserGuide.md with documentation for pdf.js viewer,
image zoom/pan, text preview, and the file-list preview modal.
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Replace iframe in file_view.html with pdf.js for PDF files
- Add image viewer with zoom/pan controls to file_view.html
- Add text file viewer with line numbers to file_view.html
- Add preview side-panel modal to files.html (file list)
- Fix file_detail.html bottom preview section variable names
- Add aria-labels and WCAG compliance to all new elements
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Add html-lint job to CI that runs djlint on all PRs
- Configure djlint in pyproject.toml with Jinja2 profile and accessibility rules
- Add djlint to requirements-dev.txt
- Expand accessibility section in frontend Copilot instructions (WCAG 2.1 AA)
- Wire html-lint into CI dependency chain (test/mypy/build depend on it)
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
Add aria-hidden="true" to decorative Font Awesome icons across templates,
aria-label to icon-only buttons, aria-live to dynamic content regions,
aria-labelledby to modals, aria-expanded to toggle buttons, scope="col"
to table headers, and aria-label to tables. Also improve alt text on
500.html error image and add aria-label to password toggle buttons.
Templates updated: settings.html, credentials.html, status_dashboard.html,
file_view.html, file_detail.html, index.html, queue_dashboard.html,
audit_log.html, 500.html
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- upload.html: Add role/tabindex/aria-label to drop zone, aria-live to status messages, aria-label to file inputs
- search.html: Add role="search", sr-only label, aria-live for results, input type="search"
- files.html: Add table aria-label, scope="col" to headers, aria-sort on sortable columns, aria-labels to action buttons, dialog roles to modals, aria-live to status areas, pagination nav with aria-labels
- login.html: Wrap form in main landmark, aria-hidden on decorative icons
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Add skip-to-content link for keyboard navigation (WCAG 2.4.1)
- Add ARIA landmarks: nav aria-label, footer role=contentinfo
- Add aria-current="page" on active nav links
- Add aria-label to admin dropdown button and mobile menu toggle
- Add role="menu" and role="menuitem" to admin dropdown
- Add aria-hidden="true" to all decorative Font Awesome icons
- Add footer nav element with aria-label for footer links
- Add focus-visible outline styles for keyboard navigation (WCAG 2.4.7)
- Add sr-only utility class
- Add dark mode support for skip-link and focus indicators
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
The upload retry logic now checks file_record.processed_file_path first
(the GPT-suggested filename stored during finalization), before falling
back to legacy hash-based and original-filename-based path patterns.
This fixes the case where the processed file has a different name than
the original (e.g., '2023-10-01_Unknown.pdf' vs 'cable_graphic.pdf')
and the retry couldn't find the file on disk.
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
The status calculation required ALL steps to be explicitly marked as
success/skipped before a file could be "completed". This failed for
dynamic pipelines where:
1. check_for_duplicates was logged before the file record existed (no
file_id), so its FileProcessingStep was never updated from "pending"
2. extract_text was not marked as "skipped" for non-PDF files that go
through PDF conversion first
Fix:
- Move check_for_duplicates success log to after initialize_file_steps()
with the correct file_id so the step actually gets updated
- Mark extract_text as "skipped" for non-PDF files
- Add terminal-step fallback: if send_to_all_destinations is "success",
the file is "completed" even if intermediate steps remain "pending"
(handles any other dynamic pipeline edge cases)
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
The terminal-step guard requires send_to_all_destinations: success before
a file is considered "completed". Update test_status_filter_completed to
include this step so it matches the new semantics.
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
The previous fix (requiring send_to_all_destinations to be present
before marking a file as completed) broke 3 tests that used only
partial step sets and expected "completed":
- test_coverage_polish.py::TestFileQueriesDeduplicationEnabled::
test_deduplication_enabled_adds_check_for_duplicates
- test_file_listing.py::TestFileListingPagination::
test_processing_status_included
- test_file_listing.py::TestFileDetailEndpoint::
test_file_detail_status_determination
Add send_to_all_destinations: success to each test's dataset so
"completed" status is reached correctly under the new semantics.
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>