/* ============================================================
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 (
);
}
/* 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 });