Evals UI: Filter text eval jobs for eval jobs page#52
Evals UI: Filter text eval jobs for eval jobs page#52
Conversation
📝 WalkthroughWalkthroughRefactors evaluation handling: API routes now filter and log only relevant item types (text or stt), and the evaluations UI renames and re-schemas tabs/components (Upload→Datasets, Results→Evaluations) and updates navigation/labels accordingly. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/api/evaluations/stt/datasets/route.ts (1)
12-19:⚠️ Potential issue | 🟠 MajorFail fast on missing
X-API-KEYin GET.GET currently forwards an empty API key instead of returning 401, unlike POST. This creates inconsistent auth behavior and avoidable backend traffic.
Proposed fix
const apiKey = request.headers.get('X-API-KEY'); + if (!apiKey) { + return NextResponse.json( + { error: 'Missing X-API-KEY header' }, + { status: 401 } + ); + } try { const response = await fetch(`${backendUrl}/api/v1/evaluations/stt/datasets`, { headers: { - 'X-API-KEY': apiKey || '', + 'X-API-KEY': apiKey, }, });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/api/evaluations/stt/datasets/route.ts` around lines 12 - 19, The GET handler currently reads const apiKey = request.headers.get('X-API-KEY') then forwards an empty string to fetch; instead, fail fast when apiKey is missing by returning a 401 response immediately. Update the logic around the apiKey constant (before the fetch to `${backendUrl}/api/v1/evaluations/stt/datasets`) to check if apiKey is falsy and return an appropriate 401 response (matching the POST behavior) rather than calling fetch with an empty 'X-API-KEY' header.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/api/evaluations/datasets/route.ts`:
- Around line 43-45: The code assumes data.data is an array before calling
.filter; update the conditional in the datasets response assignment to guard
with Array.isArray(data.data) so you only call data.data.filter when
Array.isArray(data.data) is true (otherwise leave data unchanged); locate the
expression that builds the final result (the ternary using data.data ? {
...data, data: data.data.filter(...) } : data) and add the Array.isArray check
to prevent runtime errors.
- Around line 40-47: The endpoint in route.ts is hard-filtering datasets to type
=== 'text' (see the filteredData construction using data.filter and
data.data.filter), which hides non-text datasets for other consumers; revert
this global filter and instead implement conditional filtering based on a query
parameter (e.g. check req.nextUrl.searchParams.get('type') === 'text' before
applying the filter) or create a separate text-only endpoint used by
app/evaluations/page.tsx; update the logic that builds filteredData to only
filter when the type query is set (leave the default behavior to return all
dataset types) and ensure the variable names filteredData and data are reused
accordingly.
In `@app/api/evaluations/route.ts`:
- Around line 27-32: The handler currently filters evaluations into the local
variable items but still returns the original data, so clients receive
unfiltered mixed types; update the response in the route handler (where data is
returned) to use the filtered items variable (or construct a response object
that replaces data with items) so the API returns text-only evaluations; ensure
you reference the items variable and the same data structure shape used
elsewhere in this file (e.g., where items is populated) so pagination/metadata
(if any) is preserved or reattached when returning the filtered payload.
In `@app/api/evaluations/stt/datasets/route.ts`:
- Around line 27-32: The STT filtering logic in the route uses filteredData and
currently only handles top-level arrays and data.data, which misses the
data.datasets shape and calls .filter without array guards; update the
filteredData computation to check for Array.isArray on data, data.data, and
data.datasets and apply dataset => dataset.type === 'stt' only when each is an
array (preserve non-array branches unchanged), referencing the filteredData
variable and the dataset.type predicate so all response shapes (data, data.data,
data.datasets) are safely filtered for 'stt'.
---
Outside diff comments:
In `@app/api/evaluations/stt/datasets/route.ts`:
- Around line 12-19: The GET handler currently reads const apiKey =
request.headers.get('X-API-KEY') then forwards an empty string to fetch;
instead, fail fast when apiKey is missing by returning a 401 response
immediately. Update the logic around the apiKey constant (before the fetch to
`${backendUrl}/api/v1/evaluations/stt/datasets`) to check if apiKey is falsy and
return an appropriate 401 response (matching the POST behavior) rather than
calling fetch with an empty 'X-API-KEY' header.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d9cbe595-7fb4-40d1-b4aa-afcca5517f6f
📒 Files selected for processing (4)
app/api/evaluations/datasets/route.tsapp/api/evaluations/route.tsapp/api/evaluations/stt/datasets/route.tsapp/evaluations/page.tsx
| // Filter to only return text datasets | ||
| const filteredData = Array.isArray(data) | ||
| ? data.filter((dataset: any) => dataset.type === 'text') | ||
| : data.data | ||
| ? { ...data, data: data.data.filter((dataset: any) => dataset.type === 'text') } | ||
| : data; | ||
|
|
||
| return NextResponse.json(filteredData, { status: 200 }); |
There was a problem hiding this comment.
Avoid hard-filtering this shared datasets endpoint.
This route is consumed by both app/evaluations/page.tsx (text eval flow) and app/datasets/page.tsx (datasets management). Applying type === 'text' here makes non-text datasets silently disappear in other pages. Prefer a dedicated text-only endpoint (or a ?type=text query) instead of changing the default behavior globally.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/api/evaluations/datasets/route.ts` around lines 40 - 47, The endpoint in
route.ts is hard-filtering datasets to type === 'text' (see the filteredData
construction using data.filter and data.data.filter), which hides non-text
datasets for other consumers; revert this global filter and instead implement
conditional filtering based on a query parameter (e.g. check
req.nextUrl.searchParams.get('type') === 'text' before applying the filter) or
create a separate text-only endpoint used by app/evaluations/page.tsx; update
the logic that builds filteredData to only filter when the type query is set
(leave the default behavior to return all dataset types) and ensure the variable
names filteredData and data are reused accordingly.
| : data.data | ||
| ? { ...data, data: data.data.filter((dataset: any) => dataset.type === 'text') } | ||
| : data; |
There was a problem hiding this comment.
Guard nested payload shape before calling .filter().
If data.data is present but not an array, Line 44 throws at runtime. Add an Array.isArray(data.data) check before filtering.
Proposed fix
-const filteredData = Array.isArray(data)
- ? data.filter((dataset: any) => dataset.type === 'text')
- : data.data
- ? { ...data, data: data.data.filter((dataset: any) => dataset.type === 'text') }
- : data;
+const filteredData = Array.isArray(data)
+ ? data.filter((dataset: any) => dataset.type === 'text')
+ : Array.isArray(data?.data)
+ ? { ...data, data: data.data.filter((dataset: any) => dataset.type === 'text') }
+ : data;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| : data.data | |
| ? { ...data, data: data.data.filter((dataset: any) => dataset.type === 'text') } | |
| : data; | |
| const filteredData = Array.isArray(data) | |
| ? data.filter((dataset: any) => dataset.type === 'text') | |
| : Array.isArray(data?.data) | |
| ? { ...data, data: data.data.filter((dataset: any) => dataset.type === 'text') } | |
| : data; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/api/evaluations/datasets/route.ts` around lines 43 - 45, The code assumes
data.data is an array before calling .filter; update the conditional in the
datasets response assignment to guard with Array.isArray(data.data) so you only
call data.data.filter when Array.isArray(data.data) is true (otherwise leave
data unchanged); locate the expression that builds the final result (the ternary
using data.data ? { ...data, data: data.data.filter(...) } : data) and add the
Array.isArray check to prevent runtime errors.
| let items = []; | ||
| if (data && Array.isArray(data)) { | ||
| console.log('[GET /api/evaluations] Sample evaluation structure:', { | ||
| firstItem: data[0] ? { | ||
| id: data[0].id, | ||
| hasScore: !!data[0].score, | ||
| hasScores: !!data[0].scores, | ||
| scoreKeys: data[0].score ? Object.keys(data[0].score) : [], | ||
| scoresKeys: data[0].scores ? Object.keys(data[0].scores) : [] | ||
| } : 'No items' | ||
| }); | ||
| items = data.filter((item: any) => item.type === 'text'); | ||
| } else if (data && data.data && Array.isArray(data.data)) { | ||
| console.log('[GET /api/evaluations] Sample evaluation structure (nested):', { | ||
| firstItem: data.data[0] ? { | ||
| id: data.data[0].id, | ||
| hasScore: !!data.data[0].score, | ||
| hasScores: !!data.data[0].scores, | ||
| scoreKeys: data.data[0].score ? Object.keys(data.data[0].score) : [], | ||
| scoresKeys: data.data[0].scores ? Object.keys(data.data[0].scores) : [] | ||
| } : 'No items' | ||
| items = data.data.filter((item: any) => item.type === 'text'); | ||
| } |
There was a problem hiding this comment.
Text filtering currently impacts logs only, not the API response.
items is filtered to text types, but Line 47 still returns raw data. Consumers will continue receiving mixed evaluation types. If this endpoint is intended to serve text-only jobs, the returned payload must be filtered too.
Proposed fix
- return NextResponse.json(data, { status: response.status });
+ const filteredData = Array.isArray(data)
+ ? data.filter((item: any) => item.type === 'text')
+ : Array.isArray(data?.data)
+ ? { ...data, data: data.data.filter((item: any) => item.type === 'text') }
+ : data;
+
+ return NextResponse.json(filteredData, { status: response.status });Also applies to: 47-47
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/api/evaluations/route.ts` around lines 27 - 32, The handler currently
filters evaluations into the local variable items but still returns the original
data, so clients receive unfiltered mixed types; update the response in the
route handler (where data is returned) to use the filtered items variable (or
construct a response object that replaces data with items) so the API returns
text-only evaluations; ensure you reference the items variable and the same data
structure shape used elsewhere in this file (e.g., where items is populated) so
pagination/metadata (if any) is preserved or reattached when returning the
filtered payload.
| // Filter to only return STT datasets (additional safety check) | ||
| const filteredData = Array.isArray(data) | ||
| ? data.filter((dataset: any) => dataset.type === 'stt') | ||
| : data.data | ||
| ? { ...data, data: data.data.filter((dataset: any) => dataset.type === 'stt') } | ||
| : data; |
There was a problem hiding this comment.
STT filtering misses the data.datasets shape and lacks array guards.
This code only filters top-level arrays and data.data. But the STT page also handles data.datasets; in that response shape, filtering is skipped entirely. Also, calling .filter without Array.isArray checks risks runtime errors.
Proposed fix
- const filteredData = Array.isArray(data)
- ? data.filter((dataset: any) => dataset.type === 'stt')
- : data.data
- ? { ...data, data: data.data.filter((dataset: any) => dataset.type === 'stt') }
- : data;
+ const filteredData = Array.isArray(data)
+ ? data.filter((dataset: any) => dataset.type === 'stt')
+ : Array.isArray(data?.datasets)
+ ? { ...data, datasets: data.datasets.filter((dataset: any) => dataset.type === 'stt') }
+ : Array.isArray(data?.data)
+ ? { ...data, data: data.data.filter((dataset: any) => dataset.type === 'stt') }
+ : data;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Filter to only return STT datasets (additional safety check) | |
| const filteredData = Array.isArray(data) | |
| ? data.filter((dataset: any) => dataset.type === 'stt') | |
| : data.data | |
| ? { ...data, data: data.data.filter((dataset: any) => dataset.type === 'stt') } | |
| : data; | |
| // Filter to only return STT datasets (additional safety check) | |
| const filteredData = Array.isArray(data) | |
| ? data.filter((dataset: any) => dataset.type === 'stt') | |
| : Array.isArray(data?.datasets) | |
| ? { ...data, datasets: data.datasets.filter((dataset: any) => dataset.type === 'stt') } | |
| : Array.isArray(data?.data) | |
| ? { ...data, data: data.data.filter((dataset: any) => dataset.type === 'stt') } | |
| : data; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/api/evaluations/stt/datasets/route.ts` around lines 27 - 32, The STT
filtering logic in the route uses filteredData and currently only handles
top-level arrays and data.data, which misses the data.datasets shape and calls
.filter without array guards; update the filteredData computation to check for
Array.isArray on data, data.data, and data.datasets and apply dataset =>
dataset.type === 'stt' only when each is an array (preserve non-array branches
unchanged), referencing the filteredData variable and the dataset.type predicate
so all response shapes (data, data.data, data.datasets) are safely filtered for
'stt'.

Target issue is #53
Summary by CodeRabbit
Bug Fixes
Refactor
Summary by CodeRabbit
New Features
Bug Fixes