/* ═══════════════════════════════════════════════════════════════ AnalysisView — Live analysis split-panel dashboard Left: Agent status cards | Right: Live findings feed ═══════════════════════════════════════════════════════════════ */ import { useEffect, useRef, useMemo } from 'react'; import { useScan, SCAN_STATUS, VIEWS } from '../context/ScanContext'; import AgentCard from './AgentCard'; import FindingCard from './FindingCard'; import AMDMetricsCard from './AMDMetricsCard'; import './AnalysisView.css'; function formatTime(ms) { const seconds = Math.floor(ms / 1000); const minutes = Math.floor(seconds / 60); const secs = seconds % 60; return `${minutes}:${secs.toString().padStart(2, '0')}`; } export default function AnalysisView() { const { scanStatus, agents, findings, fixes, elapsedTime, summary, setView, resetScan, amdMetrics, error } = useScan(); const feedRef = useRef(null); // Auto-scroll findings feed useEffect(() => { if (feedRef.current) { feedRef.current.scrollTop = feedRef.current.scrollHeight; } }, [findings, fixes]); // Build fix map for quick lookup const fixMap = useMemo(() => { const map = {}; fixes.forEach(fix => { map[fix.findingId] = fix; }); return map; }, [fixes]); // Severity counts const severityCounts = useMemo(() => { const counts = { critical: 0, high: 0, medium: 0, low: 0 }; findings.forEach(f => { if (counts[f.severity] !== undefined) counts[f.severity]++; }); return counts; }, [findings]); const isComplete = scanStatus === SCAN_STATUS.COMPLETE; return (
{/* Header Bar */}
🛡️ CodeSentry
{isComplete ? 'SCAN COMPLETE' : 'SCANNING...'}
{formatTime(elapsedTime)}
{isComplete && ( )}
{/* Main Split Panel */}
{/* Left Panel — Agent Status */} {/* Right Panel — Live Findings Feed */}

Live Findings

{findings.length} findings
{findings.length === 0 && scanStatus !== SCAN_STATUS.ERROR && (
🔍

Waiting for agents to report findings...

)} {scanStatus === SCAN_STATUS.ERROR && (

Analysis Failed

{error || "An unknown error occurred during the analysis stream."}

)}
{findings.map((finding, index) => ( ))} {/* Fix events shown as special cards */} {fixes.filter(fix => !findings.find(f => f.id === fix.findingId)).map((fix, index) => (
🔧 {fix.title}
))}
{/* Completion Banner */} {isComplete && (

Analysis Complete

Found {summary?.totalFindings || findings.length} issues across {summary?.filesAnalyzed || '24'} files in {formatTime(elapsedTime)}. {fixes.length} automated fixes generated.

)}
); }