Skip to content

Commit 7a793be

Browse files
klieretCopilot
andauthored
Ref: Lazy loading of tables (#22)
* Ref: Lazy loading of tables * Nit: add aria-label Co-authored-by: Copilot <[email protected]> * Ref: Reuse isAllTagsSelected * Ref: Use css classes for better visibility management --------- Co-authored-by: Copilot <[email protected]>
1 parent 0d1e29f commit 7a793be

File tree

4 files changed

+185
-171
lines changed

4 files changed

+185
-171
lines changed

css/pages.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,15 @@
139139
border-radius: 2px;
140140
}
141141

142+
/* Tab content visibility */
143+
.tabcontent {
144+
display: none;
145+
}
146+
147+
.tabcontent.active {
148+
display: block;
149+
}
150+
142151
/* Features section */
143152
.features {
144153
display: grid;

js/leaderboardFilters.js

Lines changed: 48 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,63 @@
11
// Global active filters set
22
const activeFilters = new Set(['os_system']);
33

4-
// Table Update Logic
4+
// Table Update Logic - Optimized for lazy loading
55
function updateTable() {
6-
// Get all leaderboard tables
7-
const leaderboards = document.querySelectorAll('.tabcontent');
8-
const noResultsMessage = document.querySelector('#no-results');
6+
// Only process the currently visible leaderboard table
7+
const container = document.getElementById('leaderboard-container');
8+
if (!container) return;
99

10-
leaderboards.forEach(leaderboard => {
11-
// Only process visible leaderboard
12-
if (leaderboard.style.display !== 'block') return;
10+
const visibleLeaderboard = container.querySelector('.tabcontent.active');
11+
if (!visibleLeaderboard) return;
12+
13+
const tableRows = visibleLeaderboard.querySelectorAll('.data-table tbody tr:not(.no-results)');
14+
let visibleRowCount = 0;
15+
16+
tableRows.forEach(row => {
17+
// Show row by default
18+
let showRow = true;
1319

14-
const tableRows = leaderboard.querySelectorAll('.data-table tbody tr');
15-
let visibleRowCount = 0;
20+
// Check filters
21+
for (const filter of activeFilters) {
22+
if (row.getAttribute(`data-${filter}`) !== 'true') {
23+
showRow = false;
24+
break;
25+
}
26+
}
1627

17-
tableRows.forEach(row => {
18-
// Show row by default
19-
let showRow = true;
28+
// Check tag filter
29+
if (showRow) {
30+
const selectedTags = getSelectedTags();
31+
const allTagsSelected = isAllTagsSelected();
2032

21-
// Check filters
22-
for (const filter of activeFilters) {
23-
if (row.getAttribute(`data-${filter}`) !== 'true') {
33+
if (!allTagsSelected) {
34+
const rowTags = (row.getAttribute('data-tags') || '').split(',').map(t => t.trim()).filter(Boolean);
35+
if (!rowTags.some(tag => selectedTags.includes(tag))) {
2436
showRow = false;
25-
break;
2637
}
2738
}
28-
29-
// Toggle row visibility
30-
row.style.display = showRow ? '' : 'none';
31-
if (showRow) visibleRowCount++;
32-
});
33-
34-
const noResultsMessage = leaderboard.querySelector('.no-results');
35-
// Show/hide no results message
36-
if (visibleRowCount === 0 && activeFilters.size > 0) {
37-
noResultsMessage.style.display = 'table-row';
38-
} else {
39-
noResultsMessage.style.display = 'none';
4039
}
40+
41+
// Toggle row visibility
42+
row.style.display = showRow ? '' : 'none';
43+
if (showRow) visibleRowCount++;
4144
});
45+
46+
const noResultsMessage = visibleLeaderboard.querySelector('.no-results');
47+
// Show/hide no results message
48+
if (visibleRowCount === 0 && (activeFilters.size > 0 || !isAllTagsSelected())) {
49+
noResultsMessage.style.display = 'table-row';
50+
} else {
51+
noResultsMessage.style.display = 'none';
52+
}
53+
}
54+
55+
function isAllTagsSelected() {
56+
const multiselect = document.getElementById('tag-multiselect');
57+
if (!multiselect) return true;
58+
const selectedTags = getSelectedTags();
59+
const allCheckboxes = multiselect.querySelectorAll('.tag-checkbox:not([value="All"])');
60+
return selectedTags.length === allCheckboxes.length;
4261
}
4362

4463
// Updated Filter Button Logic
@@ -67,17 +86,6 @@ document.addEventListener('DOMContentLoaded', function() {
6786
});
6887
});
6988

70-
// Apply filters when switching tabs
71-
document.querySelectorAll('.tablinks').forEach(tab => {
72-
tab.addEventListener('click', function() {
73-
// Wait for the tab content to be shown
74-
setTimeout(updateTable, 0);
75-
});
76-
});
77-
78-
// Initial application of filters
79-
setTimeout(updateTable, 0);
80-
8189
// Multi-select dropdown logic
8290
const multiselect = document.getElementById('tag-multiselect');
8391
if (multiselect) {
@@ -169,60 +177,4 @@ function getSelectedTags() {
169177
if (!multiselect) return [];
170178
const checkboxes = multiselect.querySelectorAll('.tag-checkbox:not([value="All"])');
171179
return Array.from(checkboxes).filter(cb => cb.checked).map(cb => cb.value);
172-
}
173-
174-
// Patch the table update logic to include tag filtering
175-
const originalUpdateTable = updateTable;
176-
updateTable = function() {
177-
// Get selected tags
178-
const selectedTags = getSelectedTags();
179-
const multiselect = document.getElementById('tag-multiselect');
180-
const allTagsSelected = multiselect ? (selectedTags.length === multiselect.querySelectorAll('.tag-checkbox:not([value="All"])').length) : true;
181-
182-
// Get all leaderboard tables
183-
const leaderboards = document.querySelectorAll('.tabcontent');
184-
const noResultsMessage = document.querySelector('#no-results');
185-
let anyVisible = false;
186-
187-
leaderboards.forEach(leaderboard => {
188-
// Only process visible leaderboard
189-
if (leaderboard.style.display !== 'block') return;
190-
191-
const tableRows = leaderboard.querySelectorAll('.data-table tbody tr');
192-
let visibleRowCount = 0;
193-
194-
tableRows.forEach(row => {
195-
// Show row by default
196-
let showRow = true;
197-
198-
// Check existing filters
199-
for (const filter of activeFilters) {
200-
if (row.getAttribute(`data-${filter}`) !== 'true') {
201-
showRow = false;
202-
break;
203-
}
204-
}
205-
206-
// Check tag filter
207-
if (showRow && !allTagsSelected) {
208-
const rowTags = (row.getAttribute('data-tags') || '').split(',').map(t => t.trim()).filter(Boolean);
209-
if (!rowTags.some(tag => selectedTags.includes(tag))) {
210-
showRow = false;
211-
}
212-
}
213-
214-
// Toggle row visibility
215-
row.style.display = showRow ? '' : 'none';
216-
if (showRow) visibleRowCount++;
217-
});
218-
219-
const noResultsMessage = leaderboard.querySelector('.no-results');
220-
// Show/hide no results message
221-
if (visibleRowCount === 0 && (activeFilters.size > 0 || !allTagsSelected)) {
222-
noResultsMessage.style.display = 'table-row';
223-
} else {
224-
noResultsMessage.style.display = 'none';
225-
if (visibleRowCount > 0) anyVisible = true;
226-
}
227-
});
228-
};
180+
}

js/mainResults.js

Lines changed: 120 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,94 @@ const statusToNaturalLanguage = {
1212
'resolved': 'Resolved'
1313
}
1414

15+
// Store loaded leaderboards to avoid re-rendering
16+
const loadedLeaderboards = new Set();
17+
let leaderboardData = null;
18+
19+
function loadLeaderboardData() {
20+
if (!leaderboardData) {
21+
const dataScript = document.getElementById('leaderboard-data');
22+
if (dataScript) {
23+
leaderboardData = JSON.parse(dataScript.textContent);
24+
}
25+
}
26+
return leaderboardData;
27+
}
28+
29+
function renderLeaderboardTable(leaderboard) {
30+
const container = document.getElementById('leaderboard-container');
31+
32+
// Create table content
33+
const tableHtml = `
34+
<div class="tabcontent active" id="leaderboard-${leaderboard.name}">
35+
<div class="table-responsive">
36+
<table class="table scrollable data-table">
37+
<thead>
38+
<tr>
39+
<th>Model</th>
40+
<th>% Resolved</th>
41+
<th>Org</th>
42+
<th>Date</th>
43+
<th>Logs</th>
44+
<th>Trajs</th>
45+
<th>Site</th>
46+
</tr>
47+
</thead>
48+
<tbody>
49+
${leaderboard.results
50+
.filter(item => !item.warning)
51+
.map(item => `
52+
<tr
53+
data-os_model="${item.os_model ? 'true' : 'false'}"
54+
data-os_system="${item.os_system ? 'true' : 'false'}"
55+
data-checked="${item.checked ? 'true' : 'false'}"
56+
data-tags="${item.tags ? item.tags.join(',') : ''}"
57+
>
58+
<td>
59+
<div class="flex items-center gap-1">
60+
<div class="model-badges">
61+
${item.date >= "2025-04-25" ? '<span>🆕</span>' : ''}
62+
${item.oss ? '<span>🤠</span>' : ''}
63+
${item.checked ? '<span title="The agent run was performed by or directly verified by the SWE-bench team">✅</span>' : ''}
64+
</div>
65+
<span class="model-name font-mono fw-medium">${item.name}</span>
66+
</div>
67+
</td>
68+
<td><span class="number fw-medium text-primary">${parseFloat(item.resolved).toFixed(2)}</span></td>
69+
<td>
70+
${item.logo && item.logo.length > 0 ? `
71+
<div style="display: flex; align-items: center;">
72+
${item.logo.map(logoUrl => `<img src="${logoUrl}" style="height: 1.5em;" />`).join('')}
73+
</div>
74+
` : '-'}
75+
</td>
76+
<td><span class="label-date text-muted">${item.date}</span></td>
77+
<td class="centered-text text-center">
78+
${item.logs ? '<span class="text-success">✓</span>' : '<span class="text-muted">-</span>'}
79+
</td>
80+
<td class="centered-text text-center">
81+
${item.trajs ? '<span class="text-success">✓</span>' : '<span class="text-muted">-</span>'}
82+
</td>
83+
<td class="centered-text text-center">
84+
${item.site ? `<a href="${item.site}" target="_blank" rel="noopener noreferrer"><i class="fas fa-external-link-alt"></i></a>` : '<span class="text-muted">-</span>'}
85+
</td>
86+
</tr>
87+
`).join('')}
88+
<tr class="no-results" style="display: none;">
89+
<td colspan="7" class="text-center">
90+
No entries match the selected filters. Try adjusting your filters.
91+
</td>
92+
</tr>
93+
</tbody>
94+
</table>
95+
</div>
96+
</div>
97+
`;
98+
99+
container.innerHTML = tableHtml;
100+
loadedLeaderboards.add(leaderboard.name);
101+
}
102+
15103
function updateLogViewer(inst_id, split, model) {
16104
if (inst_id == 'No Instance Selected') {
17105
const logViewer = document.querySelector('#log-viewer');
@@ -116,21 +204,45 @@ function updateMainResults(split, model) {
116204
}
117205

118206
function openLeaderboard(leaderboardName) {
119-
const tabcontent = document.querySelectorAll('.tabcontent');
120-
tabcontent.forEach(content => content.style.display = 'none');
207+
const data = loadLeaderboardData();
208+
if (!data) return;
121209

122-
const tablinks = document.querySelectorAll('.tablinks');
123-
tablinks.forEach(link => link.classList.remove('active'));
210+
// Find the leaderboard data
211+
const leaderboard = data.find(lb => lb.name === leaderboardName);
212+
if (!leaderboard) return;
124213

125-
const currentTab = document.getElementById(`leaderboard-${leaderboardName}`);
126-
if (currentTab) {
127-
currentTab.style.display = 'block';
214+
// Render the table if not already loaded
215+
if (!loadedLeaderboards.has(leaderboardName)) {
216+
renderLeaderboardTable(leaderboard);
217+
} else {
218+
// Just show the existing table
219+
const container = document.getElementById('leaderboard-container');
220+
const existingTable = container.querySelector(`#leaderboard-${leaderboardName}`);
221+
if (existingTable) {
222+
// Hide all other tables and show this one
223+
container.querySelectorAll('.tabcontent').forEach(content => {
224+
content.classList.remove('active');
225+
});
226+
existingTable.classList.add('active');
227+
} else {
228+
// Re-render if somehow missing
229+
renderLeaderboardTable(leaderboard);
230+
}
128231
}
129232

233+
// Update tab button states
234+
const tablinks = document.querySelectorAll('.tablinks');
235+
tablinks.forEach(link => link.classList.remove('active'));
236+
130237
const activeButton = document.querySelector(`.tablinks[data-leaderboard="${leaderboardName}"]`);
131238
if (activeButton) {
132239
activeButton.classList.add('active');
133240
}
241+
242+
// Apply current filters to the newly displayed table
243+
if (typeof updateTable === 'function') {
244+
setTimeout(updateTable, 0);
245+
}
134246
}
135247

136248
document.addEventListener('DOMContentLoaded', function() {
@@ -164,6 +276,7 @@ document.addEventListener('DOMContentLoaded', function() {
164276
});
165277
});
166278

279+
// Load initial tab based on hash or default to Lite
167280
const hash = window.location.hash.slice(1).toLowerCase();
168281
const validTabs = ['lite', 'verified', 'test', 'multimodal'];
169282

0 commit comments

Comments
 (0)