@@ -56,7 +56,7 @@ async function reload() {
5656 }
5757 // Load thresholds for this suite
5858 const tRes = await fetch ( `/api/thresholds?suite=${ enc ( suite ) } ` ) ;
59- const thresholdRules = await tRes . json ( ) ;
59+ const thresholdRules = tRes . ok ? await tRes . json ( ) : [ ] ;
6060 // Only include suite if it has any images
6161 if ( gold . length > 0 || Object . values ( srcImgs ) . some ( imgs => imgs . length > 0 ) )
6262 suiteData [ suite ] = { gold, sourceImages : srcImgs , thresholdRules } ;
@@ -274,7 +274,8 @@ function renderTable() {
274274 } else if ( ! img . hasGold ) {
275275 cellHtml = '<span class="cell new">○ new</span>' ;
276276 } else if ( stats ) {
277- const cls = stats . diffPixels === 0 ? 'pass' : 'fail' ;
277+ const result = checkCellThreshold ( img . suite , img . name , stats ) ;
278+ const cls = result . passed ? 'pass' : 'fail' ;
278279 cellHtml = `<span class="cell ${ cls } ">${ cls === 'pass' ? '✓' : '✗' } d=${ stats . maxDiff } </span>` ;
279280 } else {
280281 cellHtml = `<span class="cell" data-stats-key="${ esc ( statsKey ) } " style="color:#666">...</span>` ;
@@ -296,7 +297,11 @@ function renderTable() {
296297 }
297298
298299 tr . innerHTML = cells ;
299- tr . onclick = ( ) => toggleExpand ( key ) ;
300+ tr . onmousedown = ( e ) => { tr . _clickX = e . clientX ; tr . _clickY = e . clientY ; } ;
301+ tr . onclick = ( e ) => {
302+ if ( Math . abs ( e . clientX - tr . _clickX ) > 3 || Math . abs ( e . clientY - tr . _clickY ) > 3 ) return ;
303+ toggleExpand ( key ) ;
304+ } ;
300305 tbody . appendChild ( tr ) ;
301306
302307 if ( isExp ) {
@@ -526,10 +531,27 @@ async function runStatsQueue() {
526531 statsRunning = false ;
527532}
528533
534+ function checkCellThreshold ( suite , name , stats ) {
535+ const data = suiteData [ suite ] ;
536+ const rules = data ?. thresholdRules || [ ] ;
537+ const [ platApi , device ] = currentPlatform . split ( '/' ) ;
538+ const dotIdx = platApi ?. indexOf ( '.' ) ?? - 1 ;
539+ const plat = dotIdx >= 0 ? platApi . substring ( 0 , dotIdx ) : platApi ;
540+ const api = dotIdx >= 0 ? platApi . substring ( dotIdx + 1 ) : null ;
541+ const allow = resolveThreshold ( rules , name , plat , api , device ) ;
542+ if ( stats . pixelDiffs ) return checkThreshold ( stats . pixelDiffs , allow ) ;
543+ // Fallback for stats without pixelDiffs
544+ return { passed : stats . diffPixels === 0 , details : [ ] } ;
545+ }
546+
529547function updateCellInline ( key , stats ) {
530548 const el = document . querySelector ( `[data-stats-key="${ CSS . escape ( key ) } "]` ) ;
531549 if ( ! el ) return ;
532- const cls = stats . diffPixels === 0 ? 'pass' : 'fail' ;
550+ const parts = key . split ( ':' ) ;
551+ const suite = parts [ 1 ] ;
552+ const name = parts . slice ( 2 ) . join ( ':' ) ;
553+ const result = checkCellThreshold ( suite , name , stats ) ;
554+ const cls = result . passed ? 'pass' : 'fail' ;
533555 el . className = `cell ${ cls } ` ;
534556 el . removeAttribute ( 'style' ) ;
535557 el . removeAttribute ( 'data-stats-key' ) ;
0 commit comments