Skip to content

Add filtered CSV exports for Jobs and Documents - #684

Merged
hedhoud merged 11 commits into
developfrom
fix/546-admin-ui-filters-export
Jul 22, 2026
Merged

Add filtered CSV exports for Jobs and Documents#684
hedhoud merged 11 commits into
developfrom
fix/546-admin-ui-filters-export

Conversation

@hedhoud

@hedhoud hedhoud commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Context

Investigating benchmark runs or failed files currently requires paging through the Admin UI or falling back to scripts.

Change

Extend the existing Jobs and Documents controls without changing the table layout:

  • Jobs: add a partition filter and CSV export for the currently filtered loaded rows.
  • Documents: add filename search, indexed-since filtering, filtered result count, and CSV export for the current partition's filtered rows.
  • CSV output includes identifiers, state, filename, partition, and timestamps where already exposed. It does not include tracebacks or secrets.

Partially addresses #546.

Limitation

Job date filtering remains outside this PR. Job creation time and duration are available and included in the CSV export, but adding another UI filter should be scoped separately.

Validation

  • npm test -- jobs/list.test.tsx documents/list.test.tsx
  • npm run lint
  • npm run build

Summary by CodeRabbit

  • New Features
    • Added client-side filtering and an “Export CSV” option on the documents admin list (filename/text search and “indexed since” date), exporting only the filtered rows.
    • Added partition-based filtering and “Export CSV” on the jobs admin list, exporting only tasks from the selected partition/status/search view.
  • Bug Fixes
    • Improved CSV export by escaping/quoting values and neutralizing spreadsheet formula-like cell contents (including whitespace-prefixed variants); Excel-friendly CSV formatting is used for downloads.
  • Tests
    • Expanded CSV and admin list test coverage, including export success/failure and browser download behavior.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a reusable CSV utility with formula-value sanitization and browser downloads. The documents admin list gains text/date filtering and filtered CSV export, while the jobs admin list gains partition filtering and filtered CSV export with accompanying tests.

Changes

Admin CSV exports

Layer / File(s) Summary
CSV serialization and download utility
ui/src/lib/csv.ts, ui/src/lib/csv.test.ts
Defines CSV metadata, escaping and formula-prefix handling, Excel formatting, browser downloads, and unit coverage.
Document filtering and export
ui/src/pages/admin/documents/list.tsx, ui/src/pages/admin/documents/list.test.tsx
Adds text and indexed-date filters, displays filtered rows, exports filtered documents, and tests success and failure paths.
Job partition filtering and export
ui/src/pages/admin/jobs/list.tsx, ui/src/pages/admin/jobs/list.test.tsx
Adds partition filtering, exports filtered task metadata, resets related state on status changes, and tests the export flow.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AdminList
  participant downloadCsv
  participant toExcelCsv
  participant Browser
  AdminList->>downloadCsv: pass filtered rows and export filename
  downloadCsv->>toExcelCsv: serialize columns and rows
  toExcelCsv-->>downloadCsv: return sanitized CSV text
  downloadCsv->>Browser: create Blob and trigger file download
Loading

Possibly related PRs

  • linagora/openrag#631: Refactors DataTable selection and bulk-action wiring used by the documents list changes.

Suggested labels: admin-ui

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: filtered CSV exports for the Jobs and Documents admin pages.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/546-admin-ui-filters-export

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: da366a65b5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/src/lib/csv.ts Outdated
@hedhoud hedhoud added this to the v2.0.1 milestone Jul 16, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ac691dbc4b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/src/lib/csv.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
ui/src/lib/csv.ts (1)

21-29: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add a Byte Order Mark (BOM) to ensure correct UTF-8 decoding in Excel.

When downloading CSVs, Microsoft Excel typically ignores the charset=utf-8 MIME parameter and defaults to the system's local codepage, which can mangle non-ASCII characters (e.g., accents, emojis, and non-Latin text). Prepending the UTF-8 BOM (\uFEFF) to the Blob content explicitly instructs Excel to parse the file as UTF-8.

♻️ Proposed fix
 export function downloadCsv<T>(filename: string, columns: CsvColumn<T>[], rows: T[]) {
-  const blob = new Blob([toCsv(columns, rows)], { type: "text/csv;charset=utf-8" });
+  const blob = new Blob(["\uFEFF", toCsv(columns, rows)], { type: "text/csv;charset=utf-8" });
   const url = URL.createObjectURL(blob);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/lib/csv.ts` around lines 21 - 29, Update downloadCsv to prepend the
UTF-8 BOM character to the CSV content before constructing the Blob, while
preserving the existing text/csv;charset=utf-8 MIME type and download flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/src/pages/admin/documents/list.tsx`:
- Around line 381-389: Add an explicit accessible name to the search Input in
the file-search control by setting an aria-label that identifies its purpose,
while preserving the existing placeholder, value, and onChange behavior.

In `@ui/src/pages/admin/jobs/list.tsx`:
- Line 63: Update handleStatusTabChange to reset partitionFilter to "__all__"
whenever the status tab changes, matching the existing search-input reset
behavior and ensuring the selected partition remains valid for the new tab.

---

Nitpick comments:
In `@ui/src/lib/csv.ts`:
- Around line 21-29: Update downloadCsv to prepend the UTF-8 BOM character to
the CSV content before constructing the Blob, while preserving the existing
text/csv;charset=utf-8 MIME type and download flow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 852d69b0-9522-4ce0-ae2a-37176fc71d3f

📥 Commits

Reviewing files that changed from the base of the PR and between 41662c7 and ac691db.

📒 Files selected for processing (6)
  • ui/src/lib/csv.test.ts
  • ui/src/lib/csv.ts
  • ui/src/pages/admin/documents/list.test.tsx
  • ui/src/pages/admin/documents/list.tsx
  • ui/src/pages/admin/jobs/list.test.tsx
  • ui/src/pages/admin/jobs/list.tsx

Comment thread ui/src/pages/admin/documents/list.tsx
Comment thread ui/src/pages/admin/jobs/list.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 877bd2a2cb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/src/pages/admin/jobs/list.tsx Outdated
@hedhoud
hedhoud force-pushed the fix/546-admin-ui-filters-export branch from e2322c0 to f010758 Compare July 17, 2026 14:45
@hedhoud
hedhoud force-pushed the fix/546-admin-ui-filters-export branch from f010758 to 8cbd32a Compare July 17, 2026 15:26
@coderabbitai coderabbitai Bot added admin-ui Admin UI fix Fix issue labels Jul 20, 2026
@andyne13 andyne13 self-assigned this Jul 22, 2026
@coderabbitai coderabbitai Bot removed the fix Fix issue label Jul 22, 2026

@andyne13 andyne13 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed end-to-end (csv util + both list pages + tests), and traced the data paths through the backend. CI is green and the tests are well-targeted. Nice, focused change — the CSV formula-injection handling in particular is solid: csvCell prefixes ' for = + - @ \t \r \n leading cells and RFC-4180-quotes anything containing " , \n \r, and csv.test.ts covers the injection vectors. The __openrag/all_partitions__ sentinel is a good fix for the earlier __all__ collision concern, and there's even a test with a real partition literally named __all__.

A few things worth addressing before merge, plus some nits. I verified each against the code.

Should-fix (all hit the French/Excel case)

  1. CSV has no UTF-8 BOM → accented filenames garble in Excel. downloadCsv (ui/src/lib/csv.ts) builds new Blob([...], { type: "text/csv;charset=utf-8" }), but Excel ignores the blob's charset and decodes by system locale, so a file like Rapport_privé.pdf becomes mojibake. One-char fix: prepend  to the content.

  2. Hardcoded , delimiter → single-column open in ;-locale Excel. toCsv joins cells with ,. In a locale whose list separator is ; (French is the common one), Excel drops the whole row into a single column. Worth a configurable delimiter or a leading sep=, hint line.

  3. Jobs CSV omits created_at/duration_ms, which are actually exposed. The PR's "Limitation" note says the queue task API doesn't expose created/updated timestamps, but TaskListItem declares created_at?: string | null and duration_ms?: number | null (ui/src/lib/api/jobs.ts:44-45) and the route returns both (openrag/api/routers/admin/jobs.py:110-111). So a job timestamp column looks feasible in the export, and date-filtering for jobs may be more attainable than the note implies — worth a second look.

Nits / follow-ups

  1. Date filter is timezone-fragile. indexed_at is stored DateTime(timezone=True) and serialized as a UTC ISO string; documents/list.tsx compares str(file.indexed_at ?? file.created_at).slice(0,10) (the UTC calendar date) against <input type="date"> (a local date). Near midnight in UTC+1/+2 this can be off by a day (e.g. a file at …T23:30:00+00:00 is "yesterday" in UTC but "today" locally). Minor, but user-visible for a French deployment.

  2. Unbounded fetch + in-memory CSV. list_partition_files runs SELECT * ... WHERE partition_name = $1 with no LIMIT when the caller passes none (the page does), and listTasks isn't paginated either — so the client fetches every row, filters in memory, and toCsv builds one string. Fine at hundreds; a memory/UI ceiling worth noting for large partitions. Pre-existing; the export just makes it more consequential.

  3. downloadCsv browser robustness. It revokes the object URL synchronously right after link.click() — some browsers cancel the download if the URL is revoked too early (safer inside setTimeout(() => URL.revokeObjectURL(url), 0)), the <a> is never appended to the DOM (historically Firefox required it for a programmatic click), and there's no error handling/toast if it throws — the rest of these pages surface failures via toast.

  4. mimetype column/search is sparse (not wrong, just FYI). mimetype lands in file_metadata only for MCP-ingested files (mcp_service sets metadata["mimetype"] = guessed_mime) or uploads that pass it explicitly; the regular upload path (_build_metadata) doesn't set it. So the mimetype CSV column and the "search by mimetype" branch will be blank for files uploaded through the admin UI. Expected, but worth knowing the column won't populate for the common upload flow.

  5. Trivial: rows are joined with \n (RFC 4180 specifies CRLF; Excel tolerates LF), and the str() helper is duplicated across both list files.

Everything above is verified against the code. Overall this is good work — my main asks are #1#3 (all Excel/French-locale), the rest are optional.

hedhoud commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the careful review. I addressed the three main asks: exported CSVs now open correctly in Excel across UTF-8 and locale-specific separators, and Jobs exports include creation time and duration. I also fixed local-day date filtering and made browser downloads clean up safely while reporting failures.

I left pagination and server-side export for a follow-up because they change the API and loading model beyond this PR. The MIME metadata note is already covered by the current develop, which now includes MIME data for regular admin uploads.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/src/lib/csv.test.ts`:
- Around line 40-44: Remove the duplicated column-definition argument in the
toExcelCsv test and the duplicated function invocation in the downloadCsv test.
Keep one valid call for each test while preserving the existing assertions and
test data.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 823d189e-2775-4088-9025-b9f9e61ba45b

📥 Commits

Reviewing files that changed from the base of the PR and between d85e49c and 61b236e.

📒 Files selected for processing (6)
  • ui/src/lib/csv.test.ts
  • ui/src/lib/csv.ts
  • ui/src/pages/admin/documents/list.test.tsx
  • ui/src/pages/admin/documents/list.tsx
  • ui/src/pages/admin/jobs/list.test.tsx
  • ui/src/pages/admin/jobs/list.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • ui/src/pages/admin/jobs/list.test.tsx
  • ui/src/pages/admin/documents/list.test.tsx
  • ui/src/pages/admin/documents/list.tsx
  • ui/src/pages/admin/jobs/list.tsx

Comment thread ui/src/lib/csv.test.ts

@andyne13 andyne13 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the thorough follow-up — verified 61b236ea against each review point and they're all genuinely addressed in code, with tests:

  • UTF-8 BOM + sep=, line (toExcelCsv) — accented filenames and ;-locale Excel both open correctly; covered by the toExcelCsv test.
  • Jobs export now includes created_at / duration_ms.
  • Date filter — local-midnight epoch comparison fixes the timezone off-by-one.
  • downloadCsv — anchor appended/removed, deferred revokeObjectURL, try/finally cleanup, and both callers report failures via toast; the download test locks the DOM-during-click / no-sync-revoke / post-timer cleanup behaviour.

Pagination/server-side export as a follow-up is reasonable, and the mimetype column is fine (populated for MCP-ingested files). CI is green. LGTM 👍

@hedhoud
hedhoud merged commit 470f951 into develop Jul 22, 2026
6 checks passed
@hedhoud
hedhoud deleted the fix/546-admin-ui-filters-export branch July 22, 2026 15:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

admin-ui Admin UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants