@@ -33,13 +33,18 @@ import {
3333 useRunList ,
3434 useStudioConfig ,
3535} from '~/lib/api' ;
36- import { shouldShowSuiteLabels } from '~/lib/run-detail-context' ;
36+ import {
37+ evalResultIdentityKey ,
38+ evalResultSearchParams ,
39+ matchesEvalResultIdentity ,
40+ } from '~/lib/navigation' ;
41+ import { shouldShowEvalSourceLabels } from '~/lib/run-detail-context' ;
3742import { formatRunDisplay } from '~/lib/run-label' ;
3843import { useSidebarContext } from '~/lib/sidebar-context' ;
3944import type { EvalResult } from '~/lib/types' ;
4045
4146import { BrandName } from './BrandName' ;
42- import { EvalSuiteLabel } from './EvalSuiteLabel ' ;
47+ import { EvalSourceLabel } from './EvalSourceLabel ' ;
4348
4449/** Responsive <aside> wrapper. Handles mobile overlay and desktop static placement. */
4550function SidebarShell ( { children } : { children : ReactNode } ) {
@@ -104,11 +109,11 @@ function SidebarRunText({ display }: { display: ReturnType<typeof formatRunDispl
104109function EvalSidebarItemContent ( {
105110 result,
106111 passThreshold,
107- showSuiteLabel ,
112+ showEvalSourceLabel ,
108113} : {
109114 result : EvalResult ;
110115 passThreshold : number ;
111- showSuiteLabel : boolean ;
116+ showEvalSourceLabel : boolean ;
112117} ) {
113118 const passed = isPassing ( result . score , passThreshold ) ;
114119
@@ -119,14 +124,23 @@ function EvalSidebarItemContent({
119124 </ span >
120125 < span className = "min-w-0 flex-1" >
121126 < span className = "block truncate" > { result . testId } </ span >
122- { showSuiteLabel ? (
123- < EvalSuiteLabel suite = { result . suite } className = "mt-1 max-w-full text-[11px] leading-4" />
127+ { showEvalSourceLabel ? (
128+ < EvalSourceLabel result = { result } className = "mt-1 max-w-full text-[11px] leading-4" />
124129 ) : null }
125130 </ span >
126131 </ >
127132 ) ;
128133}
129134
135+ function useCurrentEvalIdentitySearch ( ) {
136+ const location = useLocation ( ) ;
137+ const search = location . search as Record < string , string | undefined > ;
138+ return {
139+ resultDir : search . result_dir ,
140+ evalPath : search . eval_path ,
141+ } ;
142+ }
143+
130144type ProjectTabId = 'runs' | 'experiments' | 'analytics' | 'targets' ;
131145
132146const projectNavItems : { id : ProjectTabId ; label : string ; description : string } [ ] = [
@@ -409,8 +423,9 @@ function RunDetailSidebar({ currentRunId }: { currentRunId: string }) {
409423function EvalSidebar ( { runId, currentEvalId } : { runId : string ; currentEvalId : string } ) {
410424 const { data } = useRunDetail ( runId ) ;
411425 const { data : config } = useStudioConfig ( ) ;
426+ const currentIdentity = useCurrentEvalIdentitySearch ( ) ;
412427 const passThreshold = config ?. threshold ?? config ?. pass_threshold ?? 0.8 ;
413- const showSuiteLabels = shouldShowSuiteLabels ( data ?. results ?? [ ] ) ;
428+ const showEvalSourceLabels = shouldShowEvalSourceLabels ( data ?. results ?? [ ] ) ;
414429
415430 return (
416431 < SidebarShell >
@@ -434,13 +449,18 @@ function EvalSidebar({ runId, currentEvalId }: { runId: string; currentEvalId: s
434449 </ div >
435450
436451 { data ?. results . map ( ( result ) => {
437- const isActive = result . testId === currentEvalId ;
452+ const search = evalResultSearchParams ( {
453+ resultDir : result . result_dir ,
454+ evalPath : result . eval_path ,
455+ } ) ;
456+ const isActive = matchesEvalResultIdentity ( result , currentEvalId , currentIdentity ) ;
438457
439458 return (
440459 < Link
441- key = { result . testId }
460+ key = { evalResultIdentityKey ( result ) }
442461 to = "/evals/$runId/$evalId"
443462 params = { { runId, evalId : result . testId } }
463+ search = { search }
444464 className = { `mb-0.5 flex items-start gap-2 rounded-md px-2 py-1.5 text-sm transition-colors ${
445465 isActive
446466 ? 'bg-gray-800 text-cyan-400'
@@ -450,7 +470,7 @@ function EvalSidebar({ runId, currentEvalId }: { runId: string; currentEvalId: s
450470 < EvalSidebarItemContent
451471 result = { result }
452472 passThreshold = { passThreshold }
453- showSuiteLabel = { showSuiteLabels }
473+ showEvalSourceLabel = { showEvalSourceLabels }
454474 />
455475 </ Link >
456476 ) ;
@@ -490,12 +510,17 @@ function SuiteSidebar({ runId, suite }: { runId: string; suite: string }) {
490510
491511 { suiteResults . map ( ( result ) => {
492512 const passed = isPassing ( result . score , passThreshold ) ;
513+ const search = evalResultSearchParams ( {
514+ resultDir : result . result_dir ,
515+ evalPath : result . eval_path ,
516+ } ) ;
493517
494518 return (
495519 < Link
496- key = { result . testId }
520+ key = { evalResultIdentityKey ( result ) }
497521 to = "/evals/$runId/$evalId"
498522 params = { { runId, evalId : result . testId } }
523+ search = { search }
499524 className = "mb-0.5 flex items-center gap-2 rounded-md px-2 py-1.5 text-sm text-gray-400 transition-colors hover:bg-gray-800/50 hover:text-gray-200"
500525 >
501526 < span className = { `text-xs ${ passed ? 'text-emerald-400' : 'text-red-400' } ` } >
@@ -609,8 +634,9 @@ function ProjectEvalSidebar({
609634} ) {
610635 const { data } = useProjectRunDetail ( projectId , runId ) ;
611636 const { data : config } = useStudioConfig ( projectId ) ;
637+ const currentIdentity = useCurrentEvalIdentitySearch ( ) ;
612638 const passThreshold = config ?. threshold ?? config ?. pass_threshold ?? 0.8 ;
613- const showSuiteLabels = shouldShowSuiteLabels ( data ?. results ?? [ ] ) ;
639+ const showEvalSourceLabels = shouldShowEvalSourceLabels ( data ?. results ?? [ ] ) ;
614640
615641 return (
616642 < SidebarShell >
@@ -632,12 +658,17 @@ function ProjectEvalSidebar({
632658 Evaluations
633659 </ div >
634660 { data ?. results . map ( ( result ) => {
635- const isActive = result . testId === currentEvalId ;
661+ const search = evalResultSearchParams ( {
662+ resultDir : result . result_dir ,
663+ evalPath : result . eval_path ,
664+ } ) ;
665+ const isActive = matchesEvalResultIdentity ( result , currentEvalId , currentIdentity ) ;
636666 return (
637667 < Link
638- key = { result . testId }
668+ key = { evalResultIdentityKey ( result ) }
639669 to = "/projects/$projectId/evals/$runId/$evalId"
640670 params = { { projectId, runId, evalId : result . testId } }
671+ search = { search }
641672 className = { `mb-0.5 flex items-start gap-2 rounded-md px-2 py-1.5 text-sm transition-colors ${
642673 isActive
643674 ? 'bg-gray-800 text-cyan-400'
@@ -647,7 +678,7 @@ function ProjectEvalSidebar({
647678 < EvalSidebarItemContent
648679 result = { result }
649680 passThreshold = { passThreshold }
650- showSuiteLabel = { showSuiteLabels }
681+ showEvalSourceLabel = { showEvalSourceLabels }
651682 />
652683 </ Link >
653684 ) ;
@@ -693,11 +724,16 @@ function ProjectSuiteSidebar({
693724 </ div >
694725 { suiteResults . map ( ( result ) => {
695726 const passed = isPassing ( result . score , passThreshold ) ;
727+ const search = evalResultSearchParams ( {
728+ resultDir : result . result_dir ,
729+ evalPath : result . eval_path ,
730+ } ) ;
696731 return (
697732 < Link
698- key = { result . testId }
733+ key = { evalResultIdentityKey ( result ) }
699734 to = "/projects/$projectId/evals/$runId/$evalId"
700735 params = { { projectId, runId, evalId : result . testId } }
736+ search = { search }
701737 className = "mb-0.5 flex items-center gap-2 rounded-md px-2 py-1.5 text-sm text-gray-400 transition-colors hover:bg-gray-800/50 hover:text-gray-200"
702738 >
703739 < span className = { `text-xs ${ passed ? 'text-emerald-400' : 'text-red-400' } ` } >
0 commit comments