@@ -5,6 +5,7 @@ import type {
55 FailureAnalysisData ,
66 ParetoData ,
77 ModelStats ,
8+ LeaderboardEntry ,
89} from './merbench-types' ;
910
1011// Calculate cost per run (simplified pricing model) - DEPRECATED
@@ -269,6 +270,60 @@ const calculateParetoFrontier = (data: Array<{ cost: number; Success_Rate: numbe
269270 return paretoPoints ;
270271} ;
271272
273+ // Sorting utilities
274+ let currentSortKey = 'Success_Rate' ;
275+ let currentSortDirection : 'asc' | 'desc' = 'desc' ;
276+
277+ export const sortLeaderboard = (
278+ data : LeaderboardEntry [ ] ,
279+ sortKey : string ,
280+ direction : 'asc' | 'desc'
281+ ) : LeaderboardEntry [ ] => {
282+ const sorted = [ ...data ] . sort ( ( a , b ) => {
283+ let aVal : any ;
284+ let bVal : any ;
285+
286+ // Handle special cases for cost calculation
287+ if ( sortKey === 'Avg_Cost' ) {
288+ aVal = a . Avg_Cost || calculateCost ( a . Avg_Tokens ) ;
289+ bVal = b . Avg_Cost || calculateCost ( b . Avg_Tokens ) ;
290+ } else {
291+ aVal = a [ sortKey as keyof LeaderboardEntry ] ;
292+ bVal = b [ sortKey as keyof LeaderboardEntry ] ;
293+ }
294+
295+ // Handle null/undefined values
296+ if ( aVal == null && bVal == null ) return 0 ;
297+ if ( aVal == null ) return direction === 'asc' ? - 1 : 1 ;
298+ if ( bVal == null ) return direction === 'asc' ? 1 : - 1 ;
299+
300+ // Numeric comparison
301+ if ( typeof aVal === 'number' && typeof bVal === 'number' ) {
302+ return direction === 'asc' ? aVal - bVal : bVal - aVal ;
303+ }
304+
305+ // String comparison
306+ const aStr = String ( aVal ) . toLowerCase ( ) ;
307+ const bStr = String ( bVal ) . toLowerCase ( ) ;
308+
309+ if ( aStr < bStr ) return direction === 'asc' ? - 1 : 1 ;
310+ if ( aStr > bStr ) return direction === 'asc' ? 1 : - 1 ;
311+ return 0 ;
312+ } ) ;
313+
314+ return sorted ;
315+ } ;
316+
317+ export const setSortState = ( sortKey : string , direction : 'asc' | 'desc' ) : void => {
318+ currentSortKey = sortKey ;
319+ currentSortDirection = direction ;
320+ } ;
321+
322+ export const getSortState = ( ) => ( {
323+ key : currentSortKey ,
324+ direction : currentSortDirection ,
325+ } ) ;
326+
272327// DOM manipulation utilities
273328export const updateSummaryStats = ( filteredData : FilteredData ) : void => {
274329 const totalRuns = filteredData . rawData . length ;
@@ -303,9 +358,20 @@ export const updateLeaderboard = (filteredData: FilteredData): void => {
303358 const tbody = document . querySelector ( '.leaderboard-table tbody' ) ;
304359 if ( ! tbody ) return ;
305360
361+ // Calculate cost range for progress bar normalization
362+ const costs = filteredData . leaderboard . map (
363+ ( entry ) => entry . Avg_Cost || calculateCost ( entry . Avg_Tokens )
364+ ) ;
365+ const minCost = Math . min ( ...costs ) ;
366+ const maxCost = Math . max ( ...costs ) ;
367+ const costRange = maxCost - minCost ;
368+
306369 tbody . innerHTML = filteredData . leaderboard
307- . map (
308- ( entry , index ) => `
370+ . map ( ( entry , index ) => {
371+ const currentCost = entry . Avg_Cost || calculateCost ( entry . Avg_Tokens ) ;
372+ const costWidth = costRange > 0 ? ( currentCost / maxCost ) * 100 : 0 ;
373+
374+ return `
309375 <tr>
310376 <td class="rank">${ index + 1 } </td>
311377 <td class="model-name">${ entry . Model } </td>
@@ -317,14 +383,19 @@ export const updateLeaderboard = (filteredData: FilteredData): void => {
317383 <span class="progress-text">${ entry . Success_Rate . toFixed ( 1 ) } %</span>
318384 </div>
319385 </td>
320- <td class="cost">$${ ( entry . Avg_Cost || calculateCost ( entry . Avg_Tokens ) ) . toFixed ( 4 ) } </td>
386+ <td class="cost">
387+ <div class="progress-bar">
388+ <div class="progress-fill progress-fill--cost" style="width: ${ costWidth } %; background-color: #9ca3af;"></div>
389+ <span class="progress-text">$${ currentCost . toFixed ( 4 ) } </span>
390+ </div>
391+ </td>
321392 <td class="duration">${ entry . Avg_Duration . toFixed ( 2 ) } s</td>
322393 <td class="tokens">${ entry . Avg_Tokens . toLocaleString ( ) } </td>
323394 <td class="runs">${ entry . Runs } </td>
324395 <td class="provider">${ entry . Provider } </td>
325396 </tr>
326- `
327- )
397+ ` ;
398+ } )
328399 . join ( '' ) ;
329400} ;
330401
0 commit comments