feat(web): Webhooks page + ALERTS nav group

New /webhooks admin page with table-based subscription management:
- CREATE WEBHOOK (inline form row — no modal) with simple-event
  checkboxes (AttackerDetail / DeckyStatus / SystemStatus) that
  expand to bus-topic patterns server-side, and an advanced-mode
  textarea for raw NATS-style patterns.
- Bulk-select + DELETE SELECTED with two-click arm pattern.
- Per-row test-ping (zap), pencil edit, and delete actions.
- Last-fired timestamp column.
- Yellow banner surfacing insecure_url warnings (WH-03): http:// is
  allowed but flagged so operators see it on every page load.
- Post-create secret modal — the secret is shown exactly once with
  a COPY button and a clear "won't see this again" notice.

Sidebar nav regrouped: /live-logs and /webhooks now live under a new
ALERTS NavGroup (Bell icon). The alertCount badge rides the Live
Logs sub-item. Command palette gains a "Webhooks" GO TO entry with
the `G W` chord.

Side-fix: useFocusSearch.ts was failing the build under
verbatimModuleSyntax (pre-existing, unrelated). Split the React
import to satisfy tsc; no behavioural change.
This commit is contained in:
2026-04-24 16:03:53 -04:00
parent c2ff8d1a4f
commit 59c405d9e5
6 changed files with 851 additions and 12 deletions

View File

@@ -3,7 +3,7 @@ import { NavLink, useLocation } from 'react-router-dom';
import {
Menu, X, Search, Activity, LayoutDashboard, Terminal, Settings, LogOut,
Server, Archive, Package, Network, ChevronDown, ChevronRight, HardDrive,
ShieldAlert,
ShieldAlert, Bell, Webhook,
} from 'lucide-react';
import './Layout.css';
@@ -25,7 +25,8 @@ const ROUTE_LABELS: Record<string, string> = {
'/': 'DASHBOARD',
'/fleet': 'FLEET',
'/mazenet': 'MAZENET',
'/live-logs': 'LOGS',
'/live-logs': 'LIVE LOGS',
'/webhooks': 'WEBHOOKS',
'/bounty': 'BOUNTY',
'/attackers': 'ATTACKERS',
'/config': 'CONFIG',
@@ -104,13 +105,23 @@ const Layout: React.FC<LayoutProps> = ({
<NavItem to="/" icon={<LayoutDashboard size={20} />} label="Dashboard" open={sidebarOpen} />
<NavItem to="/fleet" icon={<Server size={20} />} label="Decoy Fleet" open={sidebarOpen} />
<NavItem to="/mazenet" icon={<Network size={20} />} label="MazeNET" open={sidebarOpen} />
<NavItem
to="/live-logs"
icon={<Terminal size={20} />}
label="Logs"
open={sidebarOpen}
badge={alertCount}
/>
<NavGroup label="ALERTS" icon={<Bell size={20} />} open={sidebarOpen}>
<NavItem
to="/live-logs"
icon={<Terminal size={18} />}
label="Live Logs"
open={sidebarOpen}
indent
badge={alertCount}
/>
<NavItem
to="/webhooks"
icon={<Webhook size={18} />}
label="Webhooks"
open={sidebarOpen}
indent
/>
</NavGroup>
<NavItem to="/bounty" icon={<Archive size={20} />} label="Bounty" open={sidebarOpen} />
<NavItem to="/attackers" icon={<Activity size={20} />} label="Attackers" open={sidebarOpen} />
<NavGroup label="SWARM" icon={<Network size={20} />} open={sidebarOpen}>