/* ═══════════════════════════════════════════════════════════════
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 */}
{/* 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) => (
))}
{/* Completion Banner */}
{isComplete && (
✅
Analysis Complete
Found {summary?.totalFindings || findings.length} issues across {summary?.filesAnalyzed || '24'} files
in {formatTime(elapsedTime)}. {fixes.length} automated fixes generated.
)}
);
}