Skip to content

Commit f07c013

Browse files
crisbetodevversion
authored andcommitted
feat: add support for filtering by labels
Adds a multi-select dropdown that allows users to filter reports by specific labels.
1 parent 1f0a9ba commit f07c013

File tree

3 files changed

+43
-4
lines changed

3 files changed

+43
-4
lines changed

report-app/src/app/app.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@
5454
.report-body {
5555
display: flex;
5656
flex-grow: 1;
57-
overflow: hidden;
5857
max-width: var(--main-container-width);
5958
margin: auto;
60-
padding: 0 1rem 2rem;
59+
// Add some padding on the bottom so there's some space for dropdowns to open.
60+
padding: 0 1rem 10rem;
6161
}
6262

6363
.reports-link.active {

report-app/src/app/pages/report-list/report-list.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@
2828
}
2929
</select>
3030
}
31+
@if (allLabels().length > 0) {
32+
<multi-select
33+
[options]="allLabels()"
34+
[(selected)]="selectedLabels"
35+
[label]="selectedLabels().length === 0 ? 'Filter by labels' : `Showing reports with ${selectedLabels().length} label(s)`"/>
36+
}
3137
</div>
3238
<div class="button-group">
3339
@if (isCompareMode()) {

report-app/src/app/pages/report-list/report-list.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,19 @@ import {MessageSpinner} from '../../shared/message-spinner';
1111
import {Score} from '../../shared/score/score';
1212
import {ProviderLabel} from '../../shared/provider-label';
1313
import {bucketToScoreVariable} from '../../shared/scoring';
14+
import {MultiSelect} from '../../shared/multi-select/multi-select';
1415

1516
@Component({
1617
selector: 'app-report-list',
17-
imports: [RouterLink, DatePipe, StackedBarChart, MessageSpinner, Score, ProviderLabel],
18+
imports: [
19+
RouterLink,
20+
DatePipe,
21+
StackedBarChart,
22+
MessageSpinner,
23+
Score,
24+
ProviderLabel,
25+
MultiSelect,
26+
],
1827
templateUrl: './report-list.html',
1928
styleUrls: ['./report-list.scss'],
2029
})
@@ -30,6 +39,7 @@ export class ReportListComponent {
3039
protected selectedFramework = signal<string | null>(null);
3140
protected selectedModel = signal<string | null>(null);
3241
protected selectedRunner = signal<string | null>(null);
42+
protected selectedLabels = signal<string[]>([]);
3343

3444
protected allFrameworks = computed(() => {
3545
const frameworks = new Map<string, string>();
@@ -67,17 +77,40 @@ export class ReportListComponent {
6777
}));
6878
});
6979

80+
protected allLabels = computed(() => {
81+
const labels = new Set<string>();
82+
83+
for (const group of this.allGroups()) {
84+
for (const label of group.labels) {
85+
const trimmed = label.trim();
86+
87+
if (trimmed) {
88+
labels.add(trimmed);
89+
}
90+
}
91+
}
92+
93+
return Array.from(labels)
94+
.sort()
95+
.map(label => ({
96+
label,
97+
value: label,
98+
}));
99+
});
100+
70101
protected reportGroups = computed(() => {
71102
const framework = this.selectedFramework();
72103
const model = this.selectedModel();
73104
const runner = this.selectedRunner();
105+
const labels = this.selectedLabels();
74106
const groups = this.allGroups();
75107

76108
return groups.filter(group => {
77109
const frameworkMatch = !framework || group.framework.fullStackFramework.id === framework;
78110
const modelMatch = !model || group.model === model;
79111
const runnerMatch = !runner || group.runner?.id === runner;
80-
return frameworkMatch && modelMatch && runnerMatch;
112+
const labelsMatch = labels.length === 0 || group.labels.some(l => labels.includes(l.trim()));
113+
return frameworkMatch && modelMatch && runnerMatch && labelsMatch;
81114
});
82115
});
83116

0 commit comments

Comments
 (0)