/* ============================================================ FLOWSHIELD — Shell: Sidebar + Topbar ============================================================ */ function Sidebar({ active, onNav, theme }) { usePlan(); // re-render del nav al cambiar de plan const op = window.NAV.filter(n => n.group === 'op'); const cfg = window.NAV.filter(n => n.group === 'cfg'); const [act, setAct] = useStateL(null); // {running, today, total} useEffectL(() => { let alive = true; const load = () => window.fsApi('/api/results/activity', { method:'GET' }) .then(d => { if (alive) setAct(d); }).catch(() => {}); load(); const t = setInterval(load, 20000); return () => { alive = false; clearInterval(t); }; }, [active]); const Item = ({ n }) => { const isActive = active === n.id; const locked = window.fsModuleAllowed && !window.fsModuleAllowed(n.id); return ( ); }; return ( ); } function Topbar({ user, section, onLogout, onCmd }) { const meta = window.NAV.find(n => n.id === section); return (
NODO OPERATIVO
); } /* Command palette */ function CmdPalette({ open, onClose, onNav }) { const [q, setQ] = useStateL(''); useEffectL(() => { if (open) setQ(''); }, [open]); if (!open) return null; const items = [ ...window.NAV.map(n => ({ type:'nav', id:n.id, label:n.label, icon:n.icon })), ...window.REDTEAM_TABS.flatMap(t => (t.sections||[]).flatMap(s => s.tools||[])).map(t => ({ type:'tool', id:'redteam', label:t.name, icon:t.icon, sub:'Red Team' })), ]; const seen = new Set(); const filtered = items.filter(i => { const k = i.type+i.label; if (seen.has(k)) return false; seen.add(k); return i.label.toLowerCase().includes(q.toLowerCase()); }).slice(0, 9); return (
e.stopPropagation()} style={{ width:'min(580px,92vw)', background:'var(--bg-panel)', border:'1px solid var(--line-bright)', borderRadius:14, overflow:'hidden', boxShadow:'0 30px 80px -20px rgba(0,0,0,.7)' }}>
setQ(e.target.value)} placeholder="Comando o herramienta…" style={{ flex:1, background:'none', border:'none', outline:'none', color:'var(--txt-hi)', fontSize:15, fontFamily:'var(--font-mono)' }} /> ESC
{filtered.map((i, idx) => ( ))} {!filtered.length &&
Sin resultados
}
); } Object.assign(window, { Sidebar, Topbar, CmdPalette });