Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
File size: 5,579 Bytes
d543fc1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | import { useWebSocket } from '../hooks/useWebSocket';
export const RealTimeScanProgress = ({ scanId }) => {
const { isConnected, logs, vulnerabilities, scanProgress } = useWebSocket(scanId);
const getSeverityColor = (severity) => {
switch (severity?.toLowerCase()) {
case 'critical': return 'text-red-600 bg-red-50 border-red-200';
case 'high': return 'text-orange-600 bg-orange-50 border-orange-200';
case 'medium': return 'text-yellow-600 bg-yellow-50 border-yellow-200';
case 'low': return 'text-blue-600 bg-blue-50 border-blue-200';
default: return 'text-gray-600 bg-gray-50 border-gray-200';
}
};
const getLevelColor = (level) => {
switch (level?.toUpperCase()) {
case 'CRITICAL': return 'text-red-600';
case 'WARNING': return 'text-yellow-600';
case 'ERROR': return 'text-red-600';
case 'SUCCESS': return 'text-green-600';
case 'INFO': return 'text-blue-600';
default: return 'text-gray-600';
}
};
if (!scanId) {
return (
<div className="border border-outline-variant rounded-lg p-md text-center text-on-surface-variant">
No scan ID provided
</div>
);
}
return (
<div className="flex flex-col gap-md">
{/* Connection Status */}
<div className="flex items-center gap-sm text-sm">
<span className={`w-2 h-2 rounded-full ${isConnected ? 'bg-green-500' : 'bg-red-500'}`}></span>
<span className="text-on-surface-variant">
{isConnected ? 'Connected' : 'Disconnected'}
</span>
</div>
{/* Vulnerability Feed */}
{vulnerabilities.length > 0 && (
<div className="border border-outline-variant rounded-lg p-md bg-surface-container-lowest">
<h3 className="font-label-md text-label-md text-on-surface uppercase tracking-wider mb-sm">
Vulnerabilities Found ({vulnerabilities.length})
</h3>
<div className="flex flex-col gap-sm max-h-96 overflow-y-auto">
{vulnerabilities.map((vuln, index) => (
<div
key={index}
className={`border rounded p-sm ${getSeverityColor(vuln.severity)}`}
>
<div className="flex justify-between items-start gap-sm">
<div className="flex-1">
<div className="font-label-sm text-label-sm font-semibold">
{vuln.title}
</div>
<div className="font-body-sm text-body-sm text-on-surface-variant mt-xs">
{vuln.category} • CVSS: {vuln.cvss_score}
</div>
<div className="font-body-sm text-body-sm text-on-surface-variant mt-xs">
Scanner: {vuln.scanner_key}
</div>
</div>
<span className={`text-xs font-bold uppercase px-2 py-1 rounded ${getSeverityColor(vuln.severity)}`}>
{vuln.severity}
</span>
</div>
</div>
))}
</div>
</div>
)}
{/* Live Logs */}
{logs.length > 0 && (
<div className="border border-outline-variant rounded-lg p-md bg-surface-container-lowest">
<h3 className="font-label-md text-label-md text-on-surface uppercase tracking-wider mb-sm">
Live Logs
</h3>
<div className="font-body-sm text-body-sm max-h-96 overflow-y-auto bg-surface-container p-sm rounded">
{logs.map((log, index) => (
<div key={index} className="mb-xs">
<span className={`font-bold ${getLevelColor(log.level)}`}>
[{log.level}]
</span>
<span className="ml-sm text-on-surface-variant">
{log.message}
</span>
<span className="ml-sm text-outline text-xs">
{new Date(log.timestamp).toLocaleTimeString()}
</span>
</div>
))}
</div>
</div>
)}
{/* Scan Progress */}
{Object.keys(scanProgress).length > 0 && (
<div className="border border-outline-variant rounded-lg p-md bg-surface-container-lowest">
<h3 className="font-label-md text-label-md text-on-surface uppercase tracking-wider mb-sm">
Scan Progress
</h3>
<div className="grid grid-cols-2 gap-sm">
{Object.entries(scanProgress).map(([key, value]) => (
<div key={key} className="flex flex-col">
<span className="font-body-sm text-body-sm text-on-surface-variant capitalize">
{key.replace(/_/g, ' ')}
</span>
<span className="font-label-md text-label-md text-on-surface font-semibold">
{typeof value === 'number' ? value.toFixed(2) : value}
</span>
</div>
))}
</div>
</div>
)}
{/* Empty State */}
{vulnerabilities.length === 0 && logs.length === 0 && Object.keys(scanProgress).length === 0 && (
<div className="border border-dashed border-outline-variant rounded-lg p-xl text-center">
<div className="text-on-surface-variant font-body-md text-body-md">
Waiting for scan data...
</div>
<div className="text-outline text-sm mt-sm">
Vulnerabilities and logs will appear here as the scan progresses
</div>
</div>
)}
</div>
);
};
|