@@ -310,7 +310,7 @@ const MissionResultViewer = ({ onBack }) => {
310310 ) : (
311311 < >
312312 { /* 3D Canvas */ }
313- < div className = "flex-1 relative min-h-0" style = { { flexBasis : results . length > 0 ? '55 %' : '100%' } } >
313+ < div className = "flex-1 relative min-h-0" style = { { flexBasis : results . length > 0 ? '35 %' : '100%' } } >
314314 < Canvas camera = { { position : [ 5 , 5 , 5 ] , fov : 50 } } >
315315 < color attach = "background" args = { [ '#0a0a0f' ] } />
316316 < fog attach = "fog" args = { [ '#0a0a0f' , 40 , 120 ] } />
@@ -356,70 +356,66 @@ const MissionResultViewer = ({ onBack }) => {
356356 </ div >
357357 </ div >
358358
359- { /* Results table */ }
359+ { /* Results list */ }
360360 { results . length > 0 && (
361- < div className = "border-t border-white/5 overflow-auto" style = { { flexBasis : '45%' , flexShrink : 0 } } >
362- < table className = "w-full text-xs" >
363- < thead className = "sticky top-0 bg-[#0a0a0f]/95 backdrop-blur-sm" >
364- < tr className = "text-left text-zinc-600 uppercase tracking-wider border-b border-white/5 text-[9px]" >
365- < th className = "px-4 py-2.5 font-bold" > #</ th >
366- < th className = "px-4 py-2.5 font-bold" > Waypoint</ th >
367- < th className = "px-4 py-2.5 font-bold" > Purpose</ th >
368- < th className = "px-4 py-2.5 font-bold" > Result</ th >
369- < th className = "px-4 py-2.5 font-bold" > Confidence</ th >
370- < th className = "px-4 py-2.5 font-bold" > Analysis</ th >
371- < th className = "px-4 py-2.5 font-bold" > Image</ th >
372- </ tr >
373- </ thead >
374- < tbody >
375- { waypoints . map ( ( wp , idx ) => {
376- const r = resultMap [ wp . ID ] ;
377- const isSuccess = r ?. success === 'yes' ;
378- const isActive = selectedWp ?. ID === wp . ID ;
379- return (
380- < tr key = { wp . ID } onClick = { ( ) => handleWpSelect ( wp , r ) }
381- className = { `border-b border-white/[0.03] transition-colors cursor-pointer ${ isActive ? 'bg-sky-600/10' : 'hover:bg-white/[0.02]' } ` } >
382- < td className = "px-4 py-2.5 text-zinc-600 font-mono" > { idx + 1 } </ td >
383- < td className = "px-4 py-2.5 font-bold text-zinc-200" > { wp . name } </ td >
384- < td className = "px-4 py-2.5" >
385- < span className = "px-1.5 py-0.5 rounded-full bg-zinc-800 text-zinc-400 text-[8px] font-bold uppercase" > { wp . purpose || 'none' } </ span >
386- </ td >
387- < td className = "px-4 py-2.5" >
388- { r ? (
389- < span className = { `inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[8px] font-black uppercase ${ isSuccess ? 'bg-emerald-500/20 text-emerald-400' : 'bg-red-500/20 text-red-400' } ` } >
390- { isSuccess ? < CheckCircle size = { 8 } /> : < XCircle size = { 8 } /> } { isSuccess ? 'PASS' : 'FAIL' }
391- </ span >
392- ) : < span className = "text-zinc-700 text-[9px]" > —</ span > }
393- </ td >
394- < td className = "px-4 py-2.5" >
395- { r ? (
396- < div className = "flex items-center gap-2" >
397- < div className = "w-14 h-1 rounded-full bg-zinc-800 overflow-hidden" >
361+ < div className = "border-t border-white/5 overflow-auto p-4 space-y-4 bg-[#050508]" style = { { flexBasis : '65%' , flexShrink : 0 } } >
362+ { waypoints . map ( ( wp , idx ) => {
363+ const r = resultMap [ wp . ID ] ;
364+ const isSuccess = r ?. success === 'yes' ;
365+ const isActive = selectedWp ?. ID === wp . ID ;
366+ return (
367+ < div key = { wp . ID } onClick = { ( ) => handleWpSelect ( wp , r ) }
368+ className = { `flex flex-col md:flex-row gap-4 p-4 rounded-xl border transition-colors cursor-pointer shadow-lg ${ isActive ? 'bg-sky-900/10 border-sky-500/30' : 'bg-[#0a0a0f] border-white/5 hover:border-white/10' } ` } >
369+
370+ { /* Left Column: Image */ }
371+ < div className = "shrink-0" >
372+ { r ?. image ? (
373+ < img src = { r . image } alt = "" className = "h-40 w-56 rounded-lg border border-zinc-800 object-cover shadow-xl"
374+ onError = { e => e . target . style . display = 'none' } />
375+ ) : (
376+ < div className = "h-40 w-56 rounded-lg border border-zinc-800 bg-zinc-900/50 flex items-center justify-center text-zinc-700 text-xs font-mono shadow-inner" > NO IMAGE</ div >
377+ ) }
378+ </ div >
379+
380+ { /* Right Column: Info */ }
381+ < div className = "flex-1 flex flex-col min-w-0" >
382+ < div className = "flex items-start justify-between mb-3 border-b border-white/5 pb-2" >
383+ < div className = "flex items-center gap-3" >
384+ < span className = "text-zinc-600 font-mono text-xs font-bold" > #{ idx + 1 } </ span >
385+ < h3 className = "font-bold text-zinc-200 text-sm" > { wp . name } </ h3 >
386+ < span className = "px-2 py-0.5 rounded-full bg-zinc-800 text-zinc-400 text-[9px] font-bold uppercase" > { wp . purpose || 'none' } </ span >
387+ </ div >
388+ < div className = "flex items-center gap-4" >
389+ { r && (
390+ < div className = "flex items-center gap-2" title = "Confidence Score" >
391+ < div className = "w-20 h-1.5 rounded-full bg-zinc-800 overflow-hidden" >
398392 < div className = { `h-full rounded-full ${ ( r . confidence || 0 ) > 0.7 ? 'bg-emerald-500' : ( r . confidence || 0 ) > 0.4 ? 'bg-amber-500' : 'bg-red-500' } ` }
399393 style = { { width : `${ ( r . confidence || 0 ) * 100 } %` } } />
400394 </ div >
401- < span className = "text-zinc-400 font-mono text-[9px ]" > { Math . round ( ( r . confidence || 0 ) * 100 ) } %</ span >
395+ < span className = "text-zinc-400 font-mono text-[10px ]" > { Math . round ( ( r . confidence || 0 ) * 100 ) } %</ span >
402396 </ div >
403- ) : < span className = "text-zinc-700" > —</ span > }
404- </ td >
405- < td className = "px-4 py-2.5 text-zinc-500 max-w-[160px] truncate text-[9px]" >
406- { ( ( ) => {
407- const parsed = safeParseJson ( r ?. analysis ) ;
408- if ( ! parsed ) return '—' ;
409- return typeof parsed === 'object' ? ( parsed . summary || JSON . stringify ( parsed ) ) : parsed ;
410- } ) ( ) }
411- </ td >
412- < td className = "px-4 py-2.5" >
413- { r ?. image ? (
414- < img src = { r . image } alt = "" className = "h-7 w-10 rounded border border-zinc-800 object-cover"
415- onError = { e => e . target . style . display = 'none' } />
416- ) : < span className = "text-zinc-700" > —</ span > }
417- </ td >
418- </ tr >
419- ) ;
420- } ) }
421- </ tbody >
422- </ table >
397+ ) }
398+ { r ? (
399+ < span className = { `inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-black uppercase shadow-md ${ isSuccess ? 'bg-emerald-500/20 text-emerald-400 shadow-emerald-500/10' : 'bg-red-500/20 text-red-400 shadow-red-500/10' } ` } >
400+ { isSuccess ? < CheckCircle size = { 12 } /> : < XCircle size = { 12 } /> } { isSuccess ? 'PASS' : 'FAIL' }
401+ </ span >
402+ ) : < span className = "text-zinc-700 text-[10px] uppercase font-bold" > — pending</ span > }
403+ </ div >
404+ </ div >
405+
406+ < div className = "flex-1" >
407+ { r ? (
408+ < div className = "rounded-lg h-full overflow-hidden" >
409+ < AnalysisRenderer analysisData = { r . analysis } />
410+ </ div >
411+ ) : (
412+ < div className = "h-full flex items-center text-zinc-600 text-xs italic" > No analysis data available.</ div >
413+ ) }
414+ </ div >
415+ </ div >
416+ </ div >
417+ ) ;
418+ } ) }
423419 </ div >
424420 ) }
425421
0 commit comments