/* ============================================================
FLOWSHIELD — Dashboard
============================================================ */
function TeamLaunch({ theme, icon, kicker, title, desc, stat, statLabel, onClick }) {
const ref = useRefL(null);
const onMove = (e) => {
const el = ref.current; if (!el) return; const b = el.getBoundingClientRect();
el.style.setProperty('--mx', ((e.clientX-b.left)/b.width)*100+'%');
el.style.setProperty('--my', ((e.clientY-b.top)/b.height)*100+'%');
};
return (
{kicker}
{title}
{desc}
{stat}
{statLabel}
);
}
function Dashboard({ onNav }) {
const [ov, setOv] = useStateL(null);
const [demo, setDemo] = useStateL(false);
const load = () => {
window.fsApi('/api/results/overview', { method:'GET' })
.then(d => { setOv(d); setDemo(!d || !d.scans || d.scans.total === 0); })
.catch(() => { setDemo(true); });
};
useEffectL(() => { load(); }, []);
const F = ov && ov.findings;
const sevData = F ? F.sev : { crit:2, high:4, med:3, low:2 };
const openN = F ? F.status.open : 9;
const recentScans = (ov && ov.scans && ov.scans.recent && ov.scans.recent.length)
? ov.scans.recent.slice(0,4) : window.SEED_SCANS.slice(0,4);
const btScore = ov && ov.blueteam_score != null ? ov.blueteam_score : null;
const surf = (ov && ov.surface) || null;
const compN = ov && ov.compliance_scans != null ? ov.compliance_scans : null;
const maxSev = Math.max(1, sevData.crit||0, sevData.high||0, sevData.med||0, sevData.low||0);
return (
ActualizaronNav('redteam')} className="theme-fs">Nuevo escaneo>} />
{demo && }
{/* three teams */}
Operaciones
onNav('redteam')} />
onNav('blueteam')} />
onNav('normativa')} />
{/* posture row */}
Resumen de vulnerabilidades
últimos 14 días
{[['crit','Críticos'],['high','Altos'],['med','Medios'],['low','Bajos']].map(([k,l])=>{
const n = sevData[k]||0;
return (
);})}
Postura defensiva
s.team==='blue').length || '—') : '—'} />
{/* scan activity */}
Actividad de escaneo
{/* recent scans */}
Escaneos recientes
| ID | Herramienta | Objetivo | Estado | Hallazgos | Fecha |
{recentScans.map(s => (
onNav('scans')}>
| {s.code||s.id} |
{s.tool} |
{s.target} |
|
{s.status==='running' ? {s.progress}% : (
(s.found && (s.found.crit||s.found.high||s.found.med||s.found.low)) ?
{['crit','high','med','low'].map(k => s.found[k] ? {s.found[k]} : null)}
: —
)} |
{window.rptDate?window.rptDate(s.date):s.date} |
))}
);
}
function Row({ k, v, c }) {
return (
{k}
{v}
);
}
Object.assign(window, { Dashboard });