import { useState, useEffect, useCallback } from 'react'; import { useAuth } from '../components/AuthContext'; import { Shield, Activity, Users, Globe, Lock, ShieldAlert, ArrowLeft, BarChart3, PieChart as PieChartIcon } from 'lucide-react'; import { useNavigate } from 'react-router-dom'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip as RechartsTooltip, ResponsiveContainer, LineChart, Line, PieChart, Pie, Cell, Legend, LabelList, ComposedChart } from 'recharts'; const SEVERITY_COLORS = ['#EF4444', '#F97316', '#EAB308', '#3B82F6']; // Critical, High, Medium, Low const SCAN_TYPE_COLORS = ['#3B82F6', '#8B5CF6', '#10B981', '#F59E0B']; const CustomChartTooltip = ({ active, payload, label }) => { if (active && payload && payload.length) { return (
{label &&
{label}
} {payload.map((item, index) => (
{item.name || item.dataKey} : {item.value}
))}
); } return null; }; export const OrganizationPage = () => { const { user, token, loading: authLoading } = useAuth(); const navigate = useNavigate(); const [loading, setLoading] = useState(true); const [summaryData, setSummaryData] = useState(null); const [scanHistory, setScanHistory] = useState([]); const [filterOrg, setFilterOrg] = useState('All'); const [filterWebsite, setFilterWebsite] = useState('All'); const getToken = useCallback(() => localStorage.getItem('wss_token') || localStorage.getItem('wss_token') || token, [token]); const fetchData = useCallback(async () => { try { const activeToken = getToken(); if (!activeToken) { setLoading(false); return; } const [summaryRes, historyRes] = await Promise.all([ fetch('/api/vulnerabilities/summary?global=true', { headers: { 'Authorization': `Bearer ${activeToken}` } }), fetch('/api/scans/history?global=true&limit=100', { headers: { 'Authorization': `Bearer ${activeToken}` } }) ]); if (!summaryRes.ok || !historyRes.ok) return; const summaryJson = await summaryRes.json(); const historyJson = await historyRes.json(); setSummaryData(summaryJson.summary); setScanHistory(historyJson.scans || []); } catch (err) { console.error("Failed to fetch organization data:", err); } finally { setLoading(false); } }, [getToken]); useEffect(() => { fetchData(); const interval = setInterval(fetchData, 5000); // Polling real-time data every 5s return () => clearInterval(interval); }, [fetchData]); if (loading || authLoading) { return (
); } // Extract Unique Orgs & Websites for filters const uniqueOrgs = [...new Set(scanHistory.map(s => s.org_name).filter(Boolean))]; const uniqueWebsites = [...new Set(scanHistory.map(s => s.target_url).filter(Boolean))]; // Apply Filters const filteredScans = scanHistory .filter(scan => filterOrg === 'All' || scan.org_name === filterOrg) .filter(scan => filterWebsite === 'All' || scan.target_url === filterWebsite); // Derive metrics dynamically from filteredScans const completedScans = filteredScans.filter(s => s.status === 'completed' && s.security_score !== null); const score = completedScans.length > 0 ? Math.round(completedScans.reduce((sum, s) => sum + s.security_score, 0) / completedScans.length) : null; const totalVulnerabilities = filteredScans.reduce((sum, s) => { const vc = s.vulnerabilities_count; return sum + (vc ? (vc.critical + vc.high + vc.medium + vc.low) : (s.total_vulnerabilities || 0)); }, 0); // Active Assets (unique target URLs) const activeAssets = new Set(filteredScans.map(s => s.target_url).filter(Boolean)).size; // Vulnerability Distribution Pie Chart Data const vulnCounts = filteredScans.reduce((acc, s) => { if (s.vulnerabilities_count) { acc.critical += s.vulnerabilities_count.critical || 0; acc.high += s.vulnerabilities_count.high || 0; acc.medium += s.vulnerabilities_count.medium || 0; acc.low += s.vulnerabilities_count.low || 0; } return acc; }, { critical: 0, high: 0, medium: 0, low: 0 }); const vulnerabilityTypes = [ { name: 'Critical', value: vulnCounts.critical }, { name: 'High', value: vulnCounts.high }, { name: 'Medium', value: vulnCounts.medium }, { name: 'Low', value: vulnCounts.low }, ].filter(v => v.value > 0); if (vulnerabilityTypes.length === 0) { vulnerabilityTypes.push({ name: 'Clean / No Risks', value: 1 }); } // Risk Score Trend (Last 10 Scans) const riskTrendData = [...filteredScans] .filter(s => s.started_at) .sort((a, b) => new Date(a.started_at) - new Date(b.started_at)) .slice(-10) .map((scan, index) => { const totalVulns = scan.vulnerabilities_count ? (scan.vulnerabilities_count.critical + scan.vulnerabilities_count.high + scan.vulnerabilities_count.medium + scan.vulnerabilities_count.low) : (scan.total_vulnerabilities || 0); return { name: scan.target_url ? scan.target_url.replace('https://', '').replace('http://', '').replace(/\/$/, '') : `Scan ${index + 1}`, securityScore: Math.round(scan.security_score ?? 100), vulnerabilities: totalVulns }; }); // Group Scans by Month for Bar Chart const monthsData = {}; filteredScans.forEach(scan => { const d = new Date(scan.started_at || scan.created_at); if (isNaN(d.getTime())) return; const month = d.toLocaleString('en-US', { month: 'short', year: 'numeric' }); if (!monthsData[month]) monthsData[month] = { month, scans: 0, issues: 0 }; monthsData[month].scans += 1; const totalVulns = scan.vulnerabilities_count ? (scan.vulnerabilities_count.critical + scan.vulnerabilities_count.high + scan.vulnerabilities_count.medium + scan.vulnerabilities_count.low) : (scan.total_vulnerabilities || 0); monthsData[month].issues += totalVulns; }); const scanHistoryChartData = Object.values(monthsData); // Top Vulnerability Categories Chart Data const categoriesData = Object.entries(summaryData?.by_category || {}) .map(([cat, count]) => ({ category: cat || 'General Security', count })) .sort((a, b) => b.count - a.count) .slice(0, 6); // Extract Unique Orgs & Websites for filters is moved up. // Scan Types Breakdown Chart Data (Filtered) const scanTypeCounts = {}; filteredScans.forEach(scan => { const type = scan.scan_type ? (scan.scan_type.charAt(0).toUpperCase() + scan.scan_type.slice(1)) + ' Scan' : 'Advanced Scan'; scanTypeCounts[type] = (scanTypeCounts[type] || 0) + 1; }); const scanTypeChartData = Object.entries(scanTypeCounts).map(([name, value]) => ({ name, value })); return (

{user?.role === 'support_engineer' ? ( <>Support Engineer Operations ) : ( <>LarShield Global Management )}

{user?.role === 'support_engineer' ? 'Client environment inspection, troubleshooting assistance, and system logs.' : 'Centralized oversight for all client organizations, scans, and security nodes.'}

{/* Top Metrics Grid */}
{[ { title: 'SECURITY SCORE', value: score !== null ? `${score}/100` : 'N/A', icon: Shield, color: score === null ? 'text-slate-400' : score > 80 ? 'text-green-500' : score > 50 ? 'text-orange-500' : 'text-error', bg: score === null ? 'bg-slate-500/10 border-slate-500/20' : score > 80 ? 'bg-green-500/10 border-green-500/20' : score > 50 ? 'bg-orange-500/10 border-orange-500/20' : 'bg-error/10 border-error/20' }, { title: 'ACTIVE ASSETS', value: activeAssets.toString(), icon: Globe, color: 'text-blue-500', bg: 'bg-blue-500/10 border-blue-500/20' }, { title: 'TOTAL SCANS', value: filteredScans.length.toString(), icon: Activity, color: 'text-purple-500', bg: 'bg-purple-500/10 border-purple-500/20' }, { title: 'OPEN RISKS', value: totalVulnerabilities.toString(), icon: ShieldAlert, color: totalVulnerabilities > 0 ? 'text-orange-500' : 'text-green-500', bg: totalVulnerabilities > 0 ? 'bg-orange-500/10 border-orange-500/20' : 'bg-green-500/10 border-green-500/20' } ].map((metric, i) => (

{metric.title}

{metric.value}

))}
{/* Scan Engine Distribution */} {scanTypeChartData.length > 0 && (

Scan Mode Distribution

`${name} ${(percent * 100).toFixed(0)}%`} > {scanTypeChartData.map((entry, index) => ( ))} } />
)} {/* Row 1: Charts Grid */}
{/* Risk Trend Line Chart */}

Security Score Trend (Recent {riskTrendData.length} Scans)

{riskTrendData.length > 0 ? ( } /> ) : (
No scan history available.
)}
{/* Vulnerability Distribution Bar Chart */}

Severity Level Breakdown

} /> {vulnerabilityTypes.map((entry, index) => ( ))}
{/* Row 2: Secondary Charts Grid */}
{/* Scan Frequency vs Issues Found */}

Monthly Scans vs Issues Found

{scanHistoryChartData.length > 0 ? ( } /> ) : (
No scan history available.
)}
{/* Top Vulnerability Categories */}

Top Vulnerability Categories (OWASP)

{categoriesData.length > 0 ? ( } /> ) : (
No category breakdown available.
)}
); };