Skip to content

Commit bd5c795

Browse files
committed
feat: add status filter for evaluation runs table
Create StatusFilter component with buttons for All, Pending, Running, Completed, Failed. Add statusFilter state and handleStatusFilterChange handler to EvaluationViewShell. Add getFilteredRuns method to filter runs by selected status. Add getStatusCounts method to show count for each status. Display status filter above runs table with active button highlighting. Show badge with count for each status on filter buttons.
1 parent 6b3cf3a commit bd5c795

File tree

2 files changed

+116
-1
lines changed

2 files changed

+116
-1
lines changed

src/evaluation-view/EvaluationViewShell.tsx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { RunsTable } from './components/RunsTable';
1616
import { ResultsSummary } from './components/ResultsSummary';
1717
import { ResultItem } from './components/ResultItem';
1818
import { FilterControls } from './components/FilterControls';
19+
import { StatusFilter } from './components/StatusFilter';
1920
import { Alert, AlertDescription } from '../components/ui/alert';
2021
import { Button } from '../components/ui/button';
2122
import './EvaluationView.css';
@@ -52,6 +53,7 @@ export class EvaluationViewShell extends React.Component<
5253
detailedResults: DetailedEvaluationResult[];
5354
searchTerm: string;
5455
correctnessFilter: 'all' | 'correct' | 'incorrect';
56+
statusFilter: 'all' | 'pending' | 'running' | 'completed' | 'failed';
5557
expandedResultIds: Set<string>;
5658
showDialog: boolean;
5759
hasInProgressEvaluation: boolean;
@@ -78,6 +80,7 @@ export class EvaluationViewShell extends React.Component<
7880
detailedResults: [],
7981
searchTerm: '',
8082
correctnessFilter: 'all',
83+
statusFilter: 'all',
8184
expandedResultIds: new Set(),
8285
showDialog: false,
8386
hasInProgressEvaluation: false,
@@ -314,6 +317,10 @@ export class EvaluationViewShell extends React.Component<
314317
this.setState({ correctnessFilter: filter });
315318
};
316319

320+
handleStatusFilterChange = (status: 'all' | 'pending' | 'running' | 'completed' | 'failed') => {
321+
this.setState({ statusFilter: status });
322+
};
323+
317324
toggleResultExpanded = (testCaseId: string) => {
318325
this.setState((prev) => {
319326
const newExpanded = new Set(prev.expandedResultIds);
@@ -343,6 +350,28 @@ export class EvaluationViewShell extends React.Component<
343350
});
344351
};
345352

353+
getFilteredRuns = () => {
354+
const { pastRuns, statusFilter } = this.state;
355+
356+
if (statusFilter === 'all') {
357+
return pastRuns;
358+
}
359+
360+
return pastRuns.filter((run) => run.status === statusFilter);
361+
};
362+
363+
getStatusCounts = () => {
364+
const { pastRuns } = this.state;
365+
366+
return {
367+
all: pastRuns.length,
368+
pending: pastRuns.filter((r) => r.status === 'pending').length,
369+
running: pastRuns.filter((r) => r.status === 'running').length,
370+
completed: pastRuns.filter((r) => r.status === 'completed').length,
371+
failed: pastRuns.filter((r) => r.status === 'failed').length,
372+
};
373+
};
374+
346375
render() {
347376
const {
348377
availableModels,
@@ -355,12 +384,15 @@ export class EvaluationViewShell extends React.Component<
355384
expandedResultIds,
356385
searchTerm,
357386
correctnessFilter,
387+
statusFilter,
358388
showDialog,
359389
hasInProgressEvaluation,
360390
remainingQuestionsCount,
361391
} = this.state;
362392

363393
const filteredResults = this.getFilteredResults();
394+
const filteredRuns = this.getFilteredRuns();
395+
const statusCounts = this.getStatusCounts();
364396
const latestRun = pastRuns.length > 0 ? pastRuns[0] : null;
365397

366398
return (
@@ -452,7 +484,12 @@ export class EvaluationViewShell extends React.Component<
452484
: null
453485
}
454486
/>
455-
<RunsTable runs={pastRuns} onSelectRun={this.handleSelectRun} />
487+
<StatusFilter
488+
currentStatus={statusFilter}
489+
onStatusChange={this.handleStatusFilterChange}
490+
counts={statusCounts}
491+
/>
492+
<RunsTable runs={filteredRuns} onSelectRun={this.handleSelectRun} />
456493
</>
457494
)}
458495

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import React from 'react';
2+
3+
type StatusFilterValue = 'all' | 'pending' | 'running' | 'completed' | 'failed';
4+
5+
interface StatusFilterProps {
6+
currentStatus: StatusFilterValue;
7+
onStatusChange: (status: StatusFilterValue) => void;
8+
counts?: {
9+
all: number;
10+
pending: number;
11+
running: number;
12+
completed: number;
13+
failed: number;
14+
};
15+
}
16+
17+
export const StatusFilter: React.FC<StatusFilterProps> = ({
18+
currentStatus,
19+
onStatusChange,
20+
counts,
21+
}) => {
22+
const filters: { value: StatusFilterValue; label: string }[] = [
23+
{ value: 'all', label: 'All' },
24+
{ value: 'pending', label: 'Pending' },
25+
{ value: 'running', label: 'Running' },
26+
{ value: 'completed', label: 'Completed' },
27+
{ value: 'failed', label: 'Failed' },
28+
];
29+
30+
return (
31+
<div className="mb-4 flex items-center gap-2">
32+
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
33+
Filter by status:
34+
</span>
35+
<div className="inline-flex rounded-md shadow-sm" role="group">
36+
{filters.map((filter, index) => {
37+
const isActive = currentStatus === filter.value;
38+
const count = counts?.[filter.value];
39+
40+
return (
41+
<button
42+
key={filter.value}
43+
type="button"
44+
onClick={() => onStatusChange(filter.value)}
45+
className={`
46+
px-4 py-2 text-sm font-medium
47+
${index === 0 ? 'rounded-l-lg' : ''}
48+
${index === filters.length - 1 ? 'rounded-r-lg' : ''}
49+
${
50+
isActive
51+
? 'bg-blue-600 text-white hover:bg-blue-700 dark:bg-blue-700 dark:hover:bg-blue-800'
52+
: 'bg-white text-gray-700 hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700'
53+
}
54+
border border-gray-300 dark:border-gray-600
55+
${index !== 0 ? 'border-l-0' : ''}
56+
focus:z-10 focus:ring-2 focus:ring-blue-500 focus:outline-none
57+
transition-colors duration-200
58+
`}
59+
>
60+
{filter.label}
61+
{count !== undefined && count > 0 && (
62+
<span
63+
className={`ml-2 px-2 py-0.5 text-xs rounded-full ${
64+
isActive
65+
? 'bg-blue-500 text-white'
66+
: 'bg-gray-200 text-gray-700 dark:bg-gray-700 dark:text-gray-300'
67+
}`}
68+
>
69+
{count}
70+
</span>
71+
)}
72+
</button>
73+
);
74+
})}
75+
</div>
76+
</div>
77+
);
78+
};

0 commit comments

Comments
 (0)