Skip to content

search functionality implemented plus UI enhancements #1019

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions report/trends_report_web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
<body>
<h1>Trends Report</h1>
<section>
<div class="search-container">
<input id="search-input" type="text" placeholder="🔍 Search by name, date or config…" />
<button id="search-clear" title="Clear search">✕</button>
</div>
<button id="filters-toggle" class="filters-toggle">
<span class="material-symbols-outlined">filter_alt</span>
Filters
Expand Down
74 changes: 55 additions & 19 deletions report/trends_report_web/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@ class Page {
Array.from(tags).toSorted(),
document.querySelector('#tag-filter'),
new Proxy(this.filters.tags, filtersProxyHandler));

const searchInput = document.querySelector('#search-input');
searchInput.addEventListener('input', (e) => {
// store a lowercase version for case‐insensitive matching
this.filters.searchText = e.target.value.trim().toLowerCase();
this.fetchAndUpdate();
});
}

// fetchAndUpdate is called whenever filters change and it's responsible for
Expand All @@ -225,34 +232,56 @@ class Page {
async fetchAndUpdate() {
document.querySelector('#loading').style.display = '';

// Filter the list of reports
let startDate = (new Date('1970-01-01')).getTime();
let startDate = new Date('1970-01-01').getTime();
if (this.filters.dateRange !== 'all') {
const durationMillis = Number(this.filters.dateRange) * 3600 * 24 * 1000;
const durationMillis = Number(this.filters.dateRange) * 24 * 3600 * 1000;
startDate = Date.now() - durationMillis;
}
this.filteredNames = this.sortedNames.filter((name) => {

const search = (this.filters.searchText || '').trim().toLowerCase();

const prelim = this.sortedNames.filter((name) => {
const r = this.index[name];
let tagsMatch = this.filters.tags.size == 0;
for (let tag of r.tags) {
if (this.filters.tags.has(tag)) {
tagsMatch = true;
break;
}
if (new Date(r.date).getTime() < startDate) return false;

if (this.filters.tags.size > 0) {
if (!r.tags.some(t => this.filters.tags.has(t))) return false;
}

if (this.filters.llmModels.size > 0 &&
!this.filters.llmModels.has(r.llm_model)) {
return false;
}
return (
startDate < (new Date(r.date)).getTime() &&
tagsMatch &&
(this.filters.llmModels.size == 0 || this.filters.llmModels.has(r.llm_model)) &&
(this.filters.benchmarkSets.size == 0 || this.filters.benchmarkSets.has(r.benchmark_set)));

if (this.filters.benchmarkSets.size > 0 &&
!this.filters.benchmarkSets.has(r.benchmark_set)) {
return false;
}

return true;
});

// Update the rest of the page. If no reports match, we'll just clear all
// the children in each area. They do the same thing when the update methods
// are called.
// fetch only JSONs once
this.filteredNames = prelim;
await this.fetchReports();

if (search) {
this.filteredNames = this.filteredNames.filter((name) => {
const report = this.reports.get(name);
if (report.name.toLowerCase().includes(search)) return true;
if (report.date.toLowerCase().includes(search)) return true;
if (Array.isArray(report.experiments) &&
report.experiments.some(e => e.name.toLowerCase().includes(search)))
return true;
if (Array.isArray(report.fuzzers) &&
report.fuzzers.some(f => f.name.toLowerCase().includes(search)))
return true;
return JSON.stringify(report).toLowerCase().includes(search);
});
}

if (this.filteredNames.length > 0) {
this.updateReportLinks();
await this.fetchReports();
this.updateOverviewChart();
this.updateOverviewTable();
this.updateOverviewCoverageChart();
Expand Down Expand Up @@ -684,8 +713,15 @@ async function main() {
llmModels: new Set(),
benchmarkSets: new Set(),
tags: new Set(['daily']),
searchText: '',
};
const page = new Page(index, filters);

document.querySelector('#search-clear').addEventListener('click', () => {
document.querySelector('#search-input').value = '';
filters.searchText = '';
page.fetchAndUpdate();
});
await page.fetchAndUpdate();
}

Expand Down
85 changes: 69 additions & 16 deletions report/trends_report_web/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,46 @@ button {
}

@keyframes spin {
0% {
transform: rotate(0deg);
}
0% { transform: rotate(0deg); }
50% { transform: rotate(180deg); }
100% { transform: rotate(360deg); }
}

/*
* Search + Filters Container
*/
.search-container {
display: flex;
align-items: center;
gap: 8px;
margin: 20px 0;
}

#search-input {
flex: 1;
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 999px;
outline: none;
font-size: 1em;
transition: border-color 0.2s ease;
}

#search-input:focus {
border-color: #888;
}

50% {
transform: rotate(180deg);
}
#search-clear {
background: none;
border: none;
cursor: pointer;
font-size: 1.2em;
color: #666;
line-height: 1;
}

100% {
transform: rotate(360deg);
}
#search-clear:hover {
color: #333;
}

/*
Expand All @@ -83,25 +112,31 @@ button {
border-radius: 5px;
max-height: 70vh;
overflow-y: auto;
z-index: 10;
}

.filter-autocomplete > div {
padding: 3px;
padding: 5px 8px;
cursor: pointer;
}

.filter-autocomplete > div.hovered {
background: #ddd;
background: #f0f0f0;
}

.selected-values {
margin-top: 10px;
display: flex;
flex-wrap: wrap;
gap: 5px;
}

.selected-values .chip {
display: inline-flex;
align-items: center;
padding: 5px 10px;
background: #dedede;
border-radius: 99px;
border-radius: 999px;
}

.selected-values .chip > button {
Expand All @@ -111,6 +146,7 @@ button {
border: none;
padding: 0;
margin-left: 5px;
font-size: 0.9em;
}

/*
Expand All @@ -120,19 +156,26 @@ button {
display: flex;
flex-flow: row wrap;
gap: 10px 5px;
margin: 20px 0;
}

.projects button {
cursor: pointer;
appearance: none;
background: inherit;
border: 1px #ccc solid;
border-radius: 99px;
padding: 10px;
border-radius: 999px;
padding: 10px 15px;
transition: background 0.2s ease, border-color 0.2s ease;
}

.projects button:hover {
border-color: #888;
}

.projects button.selected {
background: #eee;
border-color: #888;
}

/*
Expand All @@ -141,26 +184,36 @@ button {
table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
margin: 20px 0;
}

td, th {
border-right: 1px #dedede solid;
border-bottom: 1px #dedede solid;
padding: 5px;
padding: 8px;
text-align: left;
font-size: 0.95em;
}

td:first-child, th:first-child {
border-left: 1px #dedede solid;
}

th {
border-top: 1px #dedede solid;
font-weight: 500;
font-weight: 600;
background: #f9f9f9;
}

tbody tr:nth-child(odd) {
background-color: #f4f5ff;
}

tbody tr:hover {
background-color: #eef;
}

/*
* Chart
*/
Expand Down