Spaces:
Sleeping
Sleeping
Commit
·
c26ad8f
1
Parent(s):
9810f34
Optimized
Browse files- frontend/src/pages/Dashboard.jsx +556 -243
- frontend/src/pages/FlowPage.jsx +245 -243
- frontend/src/pages/ReportsPage.jsx +131 -215
- frontend/src/pages/SettingsPage.jsx +205 -779
frontend/src/pages/Dashboard.jsx
CHANGED
|
@@ -1,70 +1,78 @@
|
|
| 1 |
-
import React, { useEffect, useState } from "react";
|
| 2 |
import { useAuth } from "../context/AuthContext";
|
| 3 |
-
import { useLocation } from "react-router-dom";
|
| 4 |
import {
|
| 5 |
-
PieChart,
|
| 6 |
-
|
| 7 |
-
Cell,
|
| 8 |
-
Tooltip,
|
| 9 |
-
ResponsiveContainer,
|
| 10 |
-
BarChart,
|
| 11 |
-
Bar,
|
| 12 |
-
XAxis,
|
| 13 |
-
YAxis,
|
| 14 |
-
CartesianGrid,
|
| 15 |
} from "recharts";
|
| 16 |
import {
|
| 17 |
-
Shield,
|
| 18 |
-
|
| 19 |
-
Wifi,
|
| 20 |
-
Activity,
|
| 21 |
-
Radio,
|
| 22 |
} from "lucide-react";
|
| 23 |
import toast from "react-hot-toast";
|
| 24 |
import NeonShield from "../components/NeonShield";
|
| 25 |
-
import { useNavigate } from "react-router-dom";
|
| 26 |
import ChatAssistant from "./ChatAssistant";
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
const COLORS = ["#00e5ff", "#ff0059", "#a78bfa", "#fbbf24", "#10b981"];
|
| 29 |
|
| 30 |
export default function Dashboard() {
|
| 31 |
-
const location = useLocation();
|
| 32 |
const navigate = useNavigate();
|
| 33 |
const [systemStats, setSystemStats] = useState(null);
|
| 34 |
const [threats, setThreats] = useState([]);
|
| 35 |
const [mlModels, setMlModels] = useState([]);
|
| 36 |
const [loading, setLoading] = useState(true);
|
| 37 |
const [showTop, setShowTop] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
useEffect(() => {
|
| 40 |
-
const
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
const loadData = async () => {
|
| 51 |
try {
|
| 52 |
const [sys, ml, th] = await Promise.all([
|
| 53 |
-
fetch("http://127.0.0.1:5000/api/system/status").then(
|
| 54 |
-
fetch("http://127.0.0.1:5000/api/ml/models").then(
|
| 55 |
-
fetch("http://127.0.0.1:5000/api/live/stats").then(
|
| 56 |
]);
|
| 57 |
-
setSystemStats(sys
|
| 58 |
setMlModels(Array.isArray(ml) ? ml : []);
|
| 59 |
-
setThreats(
|
| 60 |
-
|
| 61 |
-
name: k.toUpperCase(),
|
| 62 |
-
value: v,
|
| 63 |
-
}))
|
| 64 |
-
);
|
| 65 |
} catch (err) {
|
| 66 |
-
|
| 67 |
-
toast.error("Failed to load dashboard data");
|
| 68 |
} finally {
|
| 69 |
setLoading(false);
|
| 70 |
}
|
|
@@ -72,243 +80,548 @@ export default function Dashboard() {
|
|
| 72 |
|
| 73 |
useEffect(() => {
|
| 74 |
loadData();
|
|
|
|
|
|
|
| 75 |
}, []);
|
| 76 |
|
| 77 |
return (
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
-
|
| 89 |
-
<
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
{/* LEFT TEXT */}
|
| 94 |
-
<div className="space-y-6 lg:space-y-7 text-center lg:text-left">
|
| 95 |
-
<div className="flex items-center justify-center lg:justify-start gap-3">
|
| 96 |
-
<div className="p-2 rounded-full border border-accent/50 shadow-neon">
|
| 97 |
-
<Shield size={20} className="text-accent" />
|
| 98 |
-
</div>
|
| 99 |
-
<span className="text-xs lg:text-sm text-slate-300/80 tracking-wide uppercase">
|
| 100 |
-
AstraGuard AI • Adaptive NIDS
|
| 101 |
-
</span>
|
| 102 |
-
</div>
|
| 103 |
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
Learn more
|
| 126 |
-
</button>
|
| 127 |
-
</div>
|
| 128 |
-
</div>
|
| 129 |
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
</div>
|
|
|
|
| 137 |
</div>
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
<div className="
|
| 144 |
-
<div
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
Real-time AI NIDS operations
|
| 150 |
-
</p>
|
| 151 |
-
</div>
|
| 152 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
|
|
|
|
|
|
| 168 |
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
{mlModels.map((m, i) => (
|
| 176 |
-
<li key={i} className="flex justify-between border-b border-white/5 pb-1 last:border-0">
|
| 177 |
-
<span>{m.name}</span>
|
| 178 |
-
<span className="text-accent font-mono">{m.accuracy ?? "98.2"}%</span>
|
| 179 |
-
</li>
|
| 180 |
-
))}
|
| 181 |
-
</ul>
|
| 182 |
-
) : <p className="text-slate-500 text-xs">No models active</p>}
|
| 183 |
-
</div>
|
| 184 |
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
</h3>
|
| 189 |
-
|
| 190 |
-
<ul className="text-sm text-slate-300 space-y-2">
|
| 191 |
-
{threats.slice(0, 3).map((t, i) => (
|
| 192 |
-
<li key={i} className="flex justify-between">
|
| 193 |
-
<span className="truncate mr-2">{t.name}</span>
|
| 194 |
-
<span className="text-rose-400 font-mono">{t.value}</span>
|
| 195 |
-
</li>
|
| 196 |
-
))}
|
| 197 |
-
</ul>
|
| 198 |
-
) : <p className="text-slate-500 text-xs">Awaiting traffic...</p>}
|
| 199 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
</div>
|
| 201 |
|
| 202 |
-
{/*
|
| 203 |
-
<div className="
|
| 204 |
-
<
|
| 205 |
-
<
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
{
|
| 210 |
-
<
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
</div>
|
| 220 |
</div>
|
|
|
|
| 221 |
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
</
|
| 237 |
-
|
| 238 |
-
|
| 239 |
</div>
|
| 240 |
</div>
|
| 241 |
</div>
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
</button>
|
| 257 |
-
<button onClick={() => window.open("https://www.linkedin.com/in/ayushrai13", "_blank")} className="p-2 rounded-full border border-accent/40 text-accent hover:bg-accent/10 transition">
|
| 258 |
-
<svg width="18" height="18" fill="currentColor" viewBox="0 0 24 24"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5.001 2.5 2.5 0 0 1 0-5.001zM3 9h4v12H3zM9 9h3.8v1.6h.1c.5-.9 1.8-1.9 3.7-1.9C21.2 8.7 22 10.9 22 14.1V21h-4v-6.1c0-1.6-.6-2.7-2-2.7-1.1 0-1.7.8-2 1.6-.1.2-.1.6-.1.9V21H9z" /></svg>
|
| 259 |
-
</button>
|
| 260 |
</div>
|
| 261 |
</div>
|
| 262 |
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
<
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
<li>Threat Intel</li>
|
| 276 |
-
<li>Anomaly Detection</li>
|
| 277 |
-
</ul>
|
| 278 |
</div>
|
|
|
|
| 279 |
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
</div>
|
| 287 |
</div>
|
|
|
|
|
|
|
| 288 |
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 293 |
</div>
|
|
|
|
| 294 |
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
>
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 309 |
|
| 310 |
<ChatAssistant />
|
| 311 |
-
|
| 312 |
);
|
| 313 |
-
}
|
| 314 |
-
|
|
|
|
| 1 |
+
import React, { useEffect, useState, useMemo, useRef } from "react";
|
| 2 |
import { useAuth } from "../context/AuthContext";
|
| 3 |
+
import { useLocation, useNavigate } from "react-router-dom";
|
| 4 |
import {
|
| 5 |
+
PieChart, Pie, Cell, Tooltip, ResponsiveContainer,
|
| 6 |
+
BarChart, Bar, XAxis, YAxis, CartesianGrid, AreaChart, Area
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
} from "recharts";
|
| 8 |
import {
|
| 9 |
+
Shield, Cpu, Wifi, Activity, Github, Linkedin,
|
| 10 |
+
Server, Terminal, Globe, Zap, AlertTriangle, Lock
|
|
|
|
|
|
|
|
|
|
| 11 |
} from "lucide-react";
|
| 12 |
import toast from "react-hot-toast";
|
| 13 |
import NeonShield from "../components/NeonShield";
|
|
|
|
| 14 |
import ChatAssistant from "./ChatAssistant";
|
| 15 |
+
import CicidsImg from "../assests/fig4_acc.png";
|
| 16 |
+
import BccImg from "../assests/fig3_loss.png";
|
| 17 |
+
import LiveImg from "../assests/dashboard.png";
|
| 18 |
|
| 19 |
const COLORS = ["#00e5ff", "#ff0059", "#a78bfa", "#fbbf24", "#10b981"];
|
| 20 |
|
| 21 |
export default function Dashboard() {
|
|
|
|
| 22 |
const navigate = useNavigate();
|
| 23 |
const [systemStats, setSystemStats] = useState(null);
|
| 24 |
const [threats, setThreats] = useState([]);
|
| 25 |
const [mlModels, setMlModels] = useState([]);
|
| 26 |
const [loading, setLoading] = useState(true);
|
| 27 |
const [showTop, setShowTop] = useState(false);
|
| 28 |
+
const [isSimulated, setIsSimulated] = useState(false);
|
| 29 |
+
const [packetCount, setPacketCount] = useState(1240500);
|
| 30 |
+
const [logs, setLogs] = useState([
|
| 31 |
+
"[OK] Neural_Engine_Symmetry_Check... PASS",
|
| 32 |
+
"[INFO] Establishing encrypted tunnel to Node_Alpha...",
|
| 33 |
+
"[WARN] Anomalous handshake detected at Gateway_7"
|
| 34 |
+
]);
|
| 35 |
|
| 36 |
+
// --- DATA FALLBACKS ---
|
| 37 |
+
const dummyThreats = [
|
| 38 |
+
{ name: "DDOS", value: 45 }, { name: "MALWARE", value: 32 },
|
| 39 |
+
{ name: "PORT SCAN", value: 18 }, { name: "BRUTE FORCE", value: 12 }
|
| 40 |
+
];
|
| 41 |
+
const displayThreats = threats.length > 0 ? threats : dummyThreats;
|
| 42 |
+
const displayML = mlModels.length > 0 ? mlModels : [
|
| 43 |
+
{ name: "Neural_Kernel_v4", accuracy: 98.4 },
|
| 44 |
+
{ name: "Behavior_Pulse", accuracy: 96.2 },
|
| 45 |
+
{ name: "Heuristic_Lab", accuracy: 99.1 }
|
| 46 |
+
];
|
| 47 |
+
|
| 48 |
+
// --- LOGIC: SIMULATED LIVE FEED ---
|
| 49 |
useEffect(() => {
|
| 50 |
+
const logInterval = setInterval(() => {
|
| 51 |
+
const messages = [
|
| 52 |
+
`[INFO] Packet scrutinized: ${Math.random().toString(16).slice(2, 10).toUpperCase()}`,
|
| 53 |
+
`[OK] Filtered traffic from ${Math.floor(Math.random()*255)}.168.${Math.floor(Math.random()*255)}.1`,
|
| 54 |
+
`[WARN] Latency spike in sector_${Math.floor(Math.random()*9)}`,
|
| 55 |
+
`[SEC] Mitigated potential ${displayThreats[Math.floor(Math.random()*displayThreats.length)].name} attempt`
|
| 56 |
+
];
|
| 57 |
+
setLogs(prev => [messages[Math.floor(Math.random()*messages.length)], ...prev].slice(0, 8));
|
| 58 |
+
setPacketCount(prev => prev + Math.floor(Math.random() * 50));
|
| 59 |
+
}, 3000);
|
| 60 |
+
return () => clearInterval(logInterval);
|
| 61 |
+
}, [displayThreats]);
|
| 62 |
|
| 63 |
const loadData = async () => {
|
| 64 |
try {
|
| 65 |
const [sys, ml, th] = await Promise.all([
|
| 66 |
+
fetch("http://127.0.0.1:5000/api/system/status").then(r => r.json()),
|
| 67 |
+
fetch("http://127.0.0.1:5000/api/ml/models").then(r => r.json()),
|
| 68 |
+
fetch("http://127.0.0.1:5000/api/live/stats").then(r => r.json()),
|
| 69 |
]);
|
| 70 |
+
setSystemStats(sys);
|
| 71 |
setMlModels(Array.isArray(ml) ? ml : []);
|
| 72 |
+
setThreats(Object.entries(th || {}).map(([k, v]) => ({ name: k.toUpperCase(), value: v })));
|
| 73 |
+
setIsSimulated(false);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
} catch (err) {
|
| 75 |
+
setIsSimulated(true);
|
|
|
|
| 76 |
} finally {
|
| 77 |
setLoading(false);
|
| 78 |
}
|
|
|
|
| 80 |
|
| 81 |
useEffect(() => {
|
| 82 |
loadData();
|
| 83 |
+
const interval = setInterval(loadData, 10000);
|
| 84 |
+
return () => clearInterval(interval);
|
| 85 |
}, []);
|
| 86 |
|
| 87 |
return (
|
| 88 |
+
<div className="relative min-h-screen text-slate-200 font-sans selection:bg-accent selection:text-black z-10">
|
| 89 |
+
{/* 1. DYNAMIC BACKGROUND LAYER */}
|
| 90 |
+
<div className="fixed inset-0 -z-20 pointer-events-none overflow-hidden bg-[#030617]">
|
| 91 |
+
{/* The Grid Layer */}
|
| 92 |
+
<div className="absolute inset-0 opacity-[0.15]" style={{ backgroundImage: "radial-gradient(var(--accent) 0.5px, transparent 0.5px)", backgroundSize: "40px 40px" }} />
|
| 93 |
+
|
| 94 |
+
{/* NeonShield Moved Here: Positioned in the center-right behind the main panel */}
|
| 95 |
+
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-[1000px] opacity-40 blur-[2px] -z-0 h-[800px]">
|
| 96 |
+
<NeonShield />
|
| 97 |
+
</div>
|
| 98 |
+
|
| 99 |
+
{/* Ambient Glows */}
|
| 100 |
+
<div className="absolute left-[-10%] top-[10%] w-[600px] h-[600px] bg-accent/10 blur-[150px] rounded-full animate-pulse" />
|
| 101 |
+
<div className="absolute right-[10%] bottom-[10%] w-[400px] h-[400px] bg-purple-500/10 blur-[150px] rounded-full animate-bounce" style={{ animationDuration: '10s' }} />
|
| 102 |
+
</div>
|
| 103 |
+
|
| 104 |
+
{/* 2. HERO SECTION - MURF.AI INSPIRED REDESIGN */}
|
| 105 |
+
<header className="relative pb-20 lg:pt-12 lg:pb-20 overflow-hidden">
|
| 106 |
+
<div className="container mx-auto px-6 lg:px-12 relative z-10">
|
| 107 |
+
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 items-center">
|
| 108 |
+
|
| 109 |
+
{/* LEFT COLUMN: THE CONTENT (6/12 Width) */}
|
| 110 |
+
<div className="lg:col-span-7 text-center lg:text-left space-y-8">
|
| 111 |
+
<div className="inline-flex items-center gap-2 px-4 py-1.5 rounded-full border border-accent/20 bg-accent/5 backdrop-blur-md">
|
| 112 |
+
<div className="w-2 h-2 rounded-full bg-lime-500 animate-ping" />
|
| 113 |
+
<span className="text-[10px] uppercase tracking-[0.3em] font-black text-accent/80">Neural_Engine_v4.0_Active</span>
|
| 114 |
</div>
|
| 115 |
+
|
| 116 |
+
<h1 className="text-6xl md:text-8xl xl:text-9xl font-black tracking-tighter leading-[0.85]">
|
| 117 |
+
<span className=" text-transparent bg-clip-text bg-gradient-to-r from-[#00e5ff] via-[#a78bfa] to-[#ff0059] drop-shadow-[0_0_30px_rgba(167,139,250,0.3)] italic ">Network</span> <br /></h1>
|
| 118 |
+
<span className="text-transparent italic text-8xl bg-clip-text bg-gradient-to-r from-[#00e5ff] via-[#a78bfa] to-[#ff0059] drop-shadow-[0_0_30px_rgba(167,139,250,0.3)]">
|
| 119 |
+
Intrusion
|
| 120 |
+
</span>
|
| 121 |
|
| 122 |
+
|
| 123 |
+
<p className="text-slate-400 text-lg md:text-xl font-mono leading-relaxed max-w-2xl mx-auto lg:mx-0 border-l-2 border-accent/20 pl-6 italic">
|
| 124 |
+
> Analyzing global packet telemetry in real-time. <br />
|
| 125 |
+
> Heuristic layers: <span className="text-emerald-400 font-bold">SYNCHRONIZED</span>
|
| 126 |
+
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
|
| 128 |
+
<div className="flex flex-wrap justify-center lg:justify-start gap-5 pt-4">
|
| 129 |
+
<button
|
| 130 |
+
onClick={() => navigate("/livetraffic")}
|
| 131 |
+
className="px-10 py-5 bg-gradient-to-r border-white/10 border-2 from-accent to-blue-600 text-[var(--accent)] font-black uppercase tracking-tighter hover:scale-105 hover:shadow-[0_0_40px_rgba(0,229,255,0.5)] transition-all duration-300 active:scale-95"
|
| 132 |
+
>
|
| 133 |
+
Live Traffic
|
| 134 |
+
</button>
|
| 135 |
+
<button
|
| 136 |
+
onClick={() => navigate("/threats")}
|
| 137 |
+
className="px-10 py-5 border-2 border-white/10 text-white font-black uppercase tracking-tighter hover:shadow-[0_0_40px_rgba(0,229,255,0.5)] transition-all active:scale-95"
|
| 138 |
+
>
|
| 139 |
+
System Docs
|
| 140 |
+
</button>
|
| 141 |
+
</div>
|
| 142 |
+
</div>
|
| 143 |
|
| 144 |
+
{/* RIGHT COLUMN: TECHNICAL PERFORMANCE METRICS */}
|
| 145 |
+
<div className="lg:col-span-5 relative hidden lg:block hover:shadow-[0_0_40px_rgba(0,229,255,0.5)]">
|
| 146 |
+
<div className="rounded-xl border border-indigo-500/30 bg-[#05091a] p-8 shadow-2xl font-mono relative overflow-hidden">
|
| 147 |
+
|
| 148 |
+
{/* Header Area: Primary Model */}
|
| 149 |
+
<div className="flex justify-between items-start mb-8 pb-6 border-indigo-500/30 border-b-4">
|
| 150 |
+
<div>
|
| 151 |
+
<div className="text-[10px] text-slate-500 uppercase tracking-widest mb-1">Architecture_01</div>
|
| 152 |
+
<div className="text-2xl font-black text-white italic">DNN <span className="text-xs font-normal not-italic text-slate-500">/ Deep Neural Network</span></div>
|
| 153 |
+
</div>
|
| 154 |
+
<div className="text-right">
|
| 155 |
+
<div className="text-[10px] text-slate-500 uppercase tracking-widest mb-1">Benchmark</div>
|
| 156 |
+
<div className="text-2xl font-black text-emerald-500 italic text-glow-sm">93%</div>
|
| 157 |
+
</div>
|
| 158 |
+
</div>
|
| 159 |
|
| 160 |
+
{/* Dataset & Model Comparison Grid */}
|
| 161 |
+
<div className="space-y-8">
|
| 162 |
+
{/* CIC-IDS2018 Section */}
|
| 163 |
+
<div className="space-y-3">
|
| 164 |
+
<div className="flex justify-between text-[10px] uppercase">
|
| 165 |
+
<span className="text-slate-400">Dataset: <span className="text-white">CIC-IDS2018</span></span>
|
| 166 |
+
<span className="text-slate-500">Loss: 0.042</span>
|
| 167 |
+
</div>
|
| 168 |
+
<div className="h-1.5 w-full bg-slate-900 rounded-full overflow-hidden">
|
| 169 |
+
<div className="h-full bg-slate-400 w-[93%]" />
|
| 170 |
+
</div>
|
| 171 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
|
| 173 |
+
{/* LightGBM / BCC Darknet Section */}
|
| 174 |
+
<div className="pt-4 border-t-4 border-indigo-500/30 ">
|
| 175 |
+
<div className="flex justify-between items-center mb-4">
|
| 176 |
+
<div>
|
| 177 |
+
<div className="text-[10px] text-slate-500 uppercase tracking-widest mb-1">Architecture_02</div>
|
| 178 |
+
<div className="text-xl font-bold text-white uppercase italic tracking-tighter">LightGBM</div>
|
| 179 |
+
</div>
|
| 180 |
+
<div className="text-right">
|
| 181 |
+
<div className="text-[10px] text-slate-500 uppercase tracking-widest mb-1">BCC_Darknet</div>
|
| 182 |
+
<div className="text-xl font-bold text-accent italic">96%</div>
|
| 183 |
+
</div>
|
| 184 |
+
</div>
|
| 185 |
+
<div className="h-1.5 w-full bg-orange-500 rounded-full overflow-hidden">
|
| 186 |
+
<div className="h-full bg-accent w-[90%]" />
|
| 187 |
+
</div>
|
| 188 |
+
</div>
|
| 189 |
+
</div>
|
| 190 |
+
|
| 191 |
+
{/* Technical Footer: Training Metadata */}
|
| 192 |
+
<div className="grid grid-cols-2 gap-4 mt-8 pt-6 pb-4 border-t-4 border-indigo-500/30 border-b-4">
|
| 193 |
+
<div className="space-y-1 text-left ">
|
| 194 |
+
<div className="text-slate-500 uppercase text-[10px]">Input_Vector</div>
|
| 195 |
+
<div className="text-white font-bold tracking-widest font-mono italic">SHAPE(None, 78)</div>
|
| 196 |
+
</div>
|
| 197 |
+
<div className="space-y-1 text-right">
|
| 198 |
+
<div className="text-slate-500 uppercase text-[10px]">Optimization</div>
|
| 199 |
+
<div className="text-white font-bold tracking-widest font-mono italic">ADAM_GRADIENT</div>
|
| 200 |
+
</div>
|
| 201 |
+
</div>
|
| 202 |
+
|
| 203 |
+
{/* Final Console Output */}
|
| 204 |
+
<div className="mt-6 p-3 bg-black/40 rounded border border-white/5 font-mono text-[9px] text-slate-600">
|
| 205 |
+
<div className="flex gap-2">
|
| 206 |
+
<span className="text-blue-500">[SYS]</span>
|
| 207 |
+
Initializing Multi-Layer Perceptron...
|
| 208 |
+
</div>
|
| 209 |
+
<div className="flex gap-2 animate-pulse">
|
| 210 |
+
<span className="text-emerald-500">[OK]</span>
|
| 211 |
+
Weights Loaded Successfully.
|
| 212 |
+
</div>
|
| 213 |
+
</div>
|
| 214 |
+
</div>
|
| 215 |
+
</div>
|
| 216 |
+
</div>
|
| 217 |
+
</div>
|
| 218 |
+
</header>
|
| 219 |
+
|
| 220 |
+
{/* 2.5 PROJECT INSIGHT (The "Murf" Style Section) */}
|
| 221 |
+
<section className="container mx-auto px-6 mb-24 relative z-10">
|
| 222 |
+
<div className="relative overflow-hidden rounded-[3rem] bg-gradient-to-br from-[#0a0f29] to-[#030617] border border-white/5 p-10 md:p-20 shadow-2xl">
|
| 223 |
+
|
| 224 |
+
{/* Visual Accent: Soft Glow */}
|
| 225 |
+
<div className="absolute top-0 right-0 w-[500px] h-[500px] bg-accent/5 blur-[120px] rounded-full -mr-40 -mt-40 pointer-events-none" />
|
| 226 |
+
|
| 227 |
+
<div className="grid lg:grid-cols-2 gap-16 items-center">
|
| 228 |
+
<div className="space-y-8">
|
| 229 |
+
<div>
|
| 230 |
+
<h4 className="text-accent font-mono text-[10px] uppercase tracking-[0.5em] mb-4">Development_Project</h4>
|
| 231 |
+
<h2 className="text-4xl md:text-6xl font-black text-orange-500 leading-[1.1] italic uppercase tracking-tighter">
|
| 232 |
+
Transparent <br />
|
| 233 |
+
<span className="text-transparent bg-clip-text bg-gradient-to-r from-orange-500 to-slate-500">Security Insight</span>
|
| 234 |
+
</h2>
|
| 235 |
+
</div>
|
| 236 |
+
|
| 237 |
+
<p className="text-slate-400 text-lg font-mono leading-relaxed max-w-xl">
|
| 238 |
+
AstraGuard simplifies complex network telemetry into a unified visual experience.
|
| 239 |
+
By monitoring live traffic flows and applying baseline heuristic analysis, we help
|
| 240 |
+
identify patterns and common threat vectors.
|
| 241 |
+
</p>
|
| 242 |
+
|
| 243 |
+
<div className="flex flex-wrap gap-4">
|
| 244 |
+
<button
|
| 245 |
+
onClick={() => window.open("https://github.com/yishu13")}
|
| 246 |
+
className="group flex items-center gap-3 px-8 py-4 bg-white text-black font-black uppercase tracking-tighter hover:bg-accent transition-all duration-300"
|
| 247 |
+
>
|
| 248 |
+
<Github size={20} />
|
| 249 |
+
<span>GitHub</span>
|
| 250 |
+
</button>
|
| 251 |
+
|
| 252 |
+
<button
|
| 253 |
+
onClick={() => window.open("https://huggingface.co")}
|
| 254 |
+
className="group flex items-center gap-3 px-8 py-4 border border-white/10 text-white font-bold uppercase tracking-tighter hover:bg-white/5 transition-all duration-300"
|
| 255 |
+
>
|
| 256 |
+
<span className="text-2xl group-hover:scale-110 transition-transform">🤗</span>
|
| 257 |
+
<span>Hugging Face</span>
|
| 258 |
+
</button>
|
| 259 |
+
</div>
|
| 260 |
+
</div>
|
| 261 |
+
|
| 262 |
+
{/* RIGHT SIDE: Interactive Visual Element */}
|
| 263 |
+
<div className="relative hidden lg:block">
|
| 264 |
+
<div className="relative z-10 rounded-[2rem] border border-white/10 bg-black/40 backdrop-blur-xl p-8 shadow-2xl border-t-accent/30">
|
| 265 |
+
<div className="flex items-center justify-between mb-8">
|
| 266 |
+
<div className="flex gap-1.5">
|
| 267 |
+
<div className="w-2 h-2 rounded-full bg-rose-500/50" />
|
| 268 |
+
<div className="w-2 h-2 rounded-full bg-amber-500/50" />
|
| 269 |
+
<div className="w-2 h-2 rounded-full bg-emerald-500/50" />
|
| 270 |
</div>
|
| 271 |
+
<div className="text-[10px] font-mono text-slate-500 uppercase tracking-widest">Astra_Shield_v1.0</div>
|
| 272 |
</div>
|
| 273 |
+
|
| 274 |
+
<div className="space-y-6">
|
| 275 |
+
<div className="h-2 w-3/4 bg-white/5 rounded-full overflow-hidden">
|
| 276 |
+
<div className="h-full bg-accent animate-pulse w-[65%]" />
|
| 277 |
+
</div>
|
| 278 |
+
<div className="h-2 w-full bg-white/5 rounded-full overflow-hidden">
|
| 279 |
+
<div className="h-full bg-accent/40 w-[40%]" />
|
| 280 |
+
</div>
|
| 281 |
+
<div className="pt-4 border-t border-white/5">
|
| 282 |
+
<div className="text-[10px] font-mono text-accent uppercase mb-2">Neural_Engine_Status</div>
|
| 283 |
+
<div className="text-2xl font-mono text-white">98.2% <span className="text-[10px] text-slate-500 uppercase">Accuracy</span></div>
|
|
|
|
|
|
|
|
|
|
| 284 |
</div>
|
| 285 |
+
</div>
|
| 286 |
+
</div>
|
| 287 |
+
</div>
|
| 288 |
+
</div>
|
| 289 |
+
</div>
|
| 290 |
+
</section>
|
| 291 |
|
| 292 |
+
{/* 3. TACTICAL INFO BAR (DENSITY ADDITION) */}
|
| 293 |
+
<div className="container mx-auto px-6 -mt-30 mb-20 grid grid-cols-2 md:grid-cols-4 gap-4 z-40 relative">
|
| 294 |
+
{[
|
| 295 |
+
{ label: "Packets Scanned", val: packetCount.toLocaleString(), icon: <Globe size={16}/> },
|
| 296 |
+
{ label: "Uptime", val: "99.98%", icon: <Activity size={16}/> },
|
| 297 |
+
{ label: "Threats Blocked", val: "12,402", icon: <Shield size={16}/> },
|
| 298 |
+
{ label: "Nodes Active", val: "24/24", icon: <Server size={16}/> }
|
| 299 |
+
].map((item, i) => (
|
| 300 |
+
<div key={i} className="p-4 rounded-xl border border-white/5 bg-black/60 backdrop-blur-xl group hover:border-accent/50 transition-all text-[var(--accent)]">
|
| 301 |
+
<div className="flex items-center gap-3 text-[var(--accent)] mb-2">
|
| 302 |
+
{item.icon} <span className=" uppercase font-bold text-orange-600 tracking-widest">{item.label}</span>
|
| 303 |
+
</div>
|
| 304 |
+
<div className="text-xl font-mono font-bold text-[var(--accent)] group-hover:text-accent transition-colors">{item.val}</div>
|
| 305 |
+
</div>
|
| 306 |
+
))}
|
| 307 |
+
</div>
|
| 308 |
|
| 309 |
+
{/* 3.5 FEATURE SPOTLIGHT SECTION */}
|
| 310 |
+
<section className="container mx-auto px-6 mb-20 relative z-10">
|
| 311 |
+
<div className="relative overflow-hidden rounded-[3rem] bg-gradient-to-br from-[#0a0f29] to-[#030617] border border-white/5 p-8 md:p-16">
|
| 312 |
+
|
| 313 |
+
{/* Background Decorative Glow */}
|
| 314 |
+
<div className="absolute top-0 right-0 w-[500px] h-[500px] bg-accent/5 blur-[120px] rounded-full -mr-64 -mt-64" />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 315 |
|
| 316 |
+
<div className="grid lg:grid-cols-2 gap-12 items-center">
|
| 317 |
+
<div>
|
| 318 |
+
<h4 className="text-accent font-mono text-xs uppercase tracking-[0.4em] mb-4">Astra_Studio_v1</h4>
|
| 319 |
+
<h2 className="text-4xl md:text-5xl font-black leading-tight mb-6 italic uppercase text-[var(--accent)] ">
|
| 320 |
+
Network Intrusion <br /> <span className="text-transparent bg-clip-text bg-gradient-to-r from-white to-slate-500"> Based On Two Dataset </span>
|
| 321 |
+
</h2>
|
| 322 |
+
<p className="text-slate-400 text-lg font-mono mb-10 leading-relaxed">
|
| 323 |
+
Transition from raw data to actionable intelligence using our Neural Interface.
|
| 324 |
+
Visualize live traffic flows and utilize baseline heuristic models to categorize
|
| 325 |
+
network activity and identify common threat vectors.
|
| 326 |
+
</p>
|
| 327 |
+
|
| 328 |
+
<div className="flex flex-wrap gap-4">
|
| 329 |
+
<button
|
| 330 |
+
onClick={() => window.open("https://github.com/ayu-yishu13")}
|
| 331 |
+
className="px-8 py-4 bg-white text-black font-black uppercase tracking-tighter hover:bg-indigo-500 transition-all flex items-center gap-2"
|
| 332 |
+
>
|
| 333 |
+
<Github size={18} /> Github
|
| 334 |
+
</button>
|
| 335 |
+
<button
|
| 336 |
+
onClick={() => window.open("https://huggingface.co/CodebaseAi")}
|
| 337 |
+
className="px-8 py-4 border border-white/20 text-white font-bold uppercase tracking-tighter hover:bg-white/5 transition-all flex items-center gap-2"
|
| 338 |
+
>
|
| 339 |
+
<span className="text-xl">🤗</span> Hugging Face
|
| 340 |
+
</button>
|
| 341 |
+
</div>
|
| 342 |
+
</div>
|
| 343 |
+
|
| 344 |
+
{/* The "Visual Card" - Mimicking the Murf.ai right side */}
|
| 345 |
+
<div className="relative">
|
| 346 |
+
<div className="relative z-10 rounded-2xl border border-white/10 bg-black/40 backdrop-blur-md p-2 shadow-2xl">
|
| 347 |
+
<img
|
| 348 |
+
src="/path-to-your-ui-preview.png"
|
| 349 |
+
alt="Interface Preview"
|
| 350 |
+
className="rounded-xl opacity-80"
|
| 351 |
+
/>
|
| 352 |
+
</div>
|
| 353 |
+
{/* Floating "Magic" Card */}
|
| 354 |
+
<div className="absolute -bottom-6 -left-6 z-20 w-48 p-4 rounded-xl border border-accent/30 bg-[#030617] shadow-[0_20px_50px_rgba(0,0,0,0.5)] animate-bounce" style={{ animationDuration: '4s' }}>
|
| 355 |
+
<div className="flex items-center gap-2 mb-2">
|
| 356 |
+
<div className="w-2 h-2 rounded-full bg-emerald-500 shadow-[0_0_8px_#10b981]" />
|
| 357 |
+
<span className="text-[10px] font-mono text-slate-400">Neural_Sync</span>
|
| 358 |
+
</div>
|
| 359 |
+
<div className="h-1 w-full bg-white/5 rounded-full overflow-hidden">
|
| 360 |
+
<div className="h-full bg-accent w-3/4" />
|
| 361 |
+
</div>
|
| 362 |
+
</div>
|
| 363 |
+
</div>
|
| 364 |
+
</div>
|
| 365 |
+
</div>
|
| 366 |
+
</section>
|
| 367 |
+
|
| 368 |
+
{/* 4. PRIMARY DASHBOARD PANEL */}
|
| 369 |
+
<main className="container mx-auto px-4 lg:px-6 pb-20 relative z-10">
|
| 370 |
+
<div className="glass-shell p-6 lg:p-10 rounded-[2rem] border border-white/10 bg-black/20 backdrop-blur-xl shadow-2xl overflow-hidden relative">
|
| 371 |
+
|
| 372 |
+
{/* Subtle Corner Deco */}
|
| 373 |
+
<div className="absolute top-0 right-0 w-32 h-32 bg-accent/5 rounded-bl-full pointer-events-none" />
|
| 374 |
+
|
| 375 |
+
{/* Section: Status & Gauges */}
|
| 376 |
+
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 mb-12">
|
| 377 |
+
|
| 378 |
+
{/* System Resource Gauges */}
|
| 379 |
+
<div className="lg:col-span-4 space-y-8 p-6 rounded-2xl border border-white/5 bg-white/[0.02]">
|
| 380 |
+
<div className="flex justify-between items-center">
|
| 381 |
+
<h3 className="text-accent text-[10px] font-black uppercase tracking-[0.3em] flex items-center gap-2">
|
| 382 |
+
<Cpu size={14} /> Neural Load
|
| 383 |
</h3>
|
| 384 |
+
<span className="text-[8px] font-mono text-emerald-500 bg-emerald-500/10 px-2 py-0.5 rounded">Nominal</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 385 |
</div>
|
| 386 |
+
|
| 387 |
+
{[
|
| 388 |
+
{ label: "Cortex Processing", val: systemStats?.cpu_usage ?? (isSimulated ? "32" : "0") },
|
| 389 |
+
{ label: "Synaptic Memory", val: systemStats?.ram_usage ?? (isSimulated ? "54" : "0") },
|
| 390 |
+
{ label: "Buffer Capacity", val: systemStats?.disk_usage ?? (isSimulated ? "18" : "0") }
|
| 391 |
+
].map((s, i) => (
|
| 392 |
+
<div key={i} className="space-y-2">
|
| 393 |
+
<div className="flex justify-between text-[10px] font-mono uppercase text-slate-400">
|
| 394 |
+
<span>{s.label}</span>
|
| 395 |
+
<span className="text-accent">{s.val}%</span>
|
| 396 |
+
</div>
|
| 397 |
+
<div className="h-1.5 w-full bg-white/5 rounded-full overflow-hidden">
|
| 398 |
+
<div className="h-full bg-gradient-to-r from-accent to-blue-500 transition-all duration-1000 shadow-[0_0_10px_var(--accent)]" style={{ width: `${s.val}%` }} />
|
| 399 |
+
</div>
|
| 400 |
+
</div>
|
| 401 |
+
))}
|
| 402 |
</div>
|
| 403 |
|
| 404 |
+
{/* AI Model Intelligence */}
|
| 405 |
+
<div className="lg:col-span-4 p-6 rounded-2xl border border-white/5 bg-white/[0.02]">
|
| 406 |
+
<h3 className="text-accent text-[10px] font-black uppercase tracking-[0.3em] mb-8 flex items-center gap-2">
|
| 407 |
+
<Activity size={14} /> Logic Core Confidence
|
| 408 |
+
</h3>
|
| 409 |
+
<div className="space-y-4">
|
| 410 |
+
{displayML.map((m, i) => (
|
| 411 |
+
<div key={i} className="group flex justify-between items-center p-3 rounded-xl border border-white/5 bg-black/20 hover:border-accent/30 transition-all">
|
| 412 |
+
<span className="text-xs font-mono text-slate-300 italic">{m.name}</span>
|
| 413 |
+
<div className="flex items-center gap-2">
|
| 414 |
+
<div className="w-12 h-1 bg-white/10 rounded-full overflow-hidden">
|
| 415 |
+
<div className="h-full bg-emerald-500" style={{ width: `${m.accuracy}%` }} />
|
| 416 |
+
</div>
|
| 417 |
+
<span className="text-emerald-400 font-mono text-xs">{m.accuracy}%</span>
|
| 418 |
+
</div>
|
| 419 |
+
</div>
|
| 420 |
+
))}
|
|
|
|
| 421 |
</div>
|
| 422 |
+
</div>
|
| 423 |
|
| 424 |
+
{/* Tactical Threat Feed */}
|
| 425 |
+
<div className="lg:col-span-4 p-6 rounded-2xl border border-white/5 bg-white/[0.02]">
|
| 426 |
+
<h3 className="text-rose-500 text-[10px] font-black uppercase tracking-[0.3em] mb-8 flex items-center gap-2">
|
| 427 |
+
<AlertTriangle size={14} /> Priority Intercepts
|
| 428 |
+
</h3>
|
| 429 |
+
<div className="space-y-3">
|
| 430 |
+
{displayThreats.slice(0, 3).map((t, i) => (
|
| 431 |
+
<div key={i} className="group relative flex justify-between items-center p-3 rounded-xl border border-rose-500/10 bg-rose-500/5 hover:bg-rose-500/10 transition-all">
|
| 432 |
+
<div>
|
| 433 |
+
<div className="text-[10px] text-slate-500 uppercase font-mono">Type_{t.name}</div>
|
| 434 |
+
<div className="text-rose-400 font-bold text-sm tracking-tight">{t.value} Attempts</div>
|
| 435 |
+
</div>
|
| 436 |
+
<button className="p-2 opacity-0 group-hover:opacity-100 bg-rose-500 text-white rounded transition-all active:scale-90">
|
| 437 |
+
<Lock size={12}/>
|
| 438 |
+
</button>
|
| 439 |
+
</div>
|
| 440 |
+
))}
|
| 441 |
</div>
|
| 442 |
</div>
|
| 443 |
</div>
|
| 444 |
+
|
| 445 |
+
{/* Section: Visual Analytics */}
|
| 446 |
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-12">
|
| 447 |
+
<div className="p-8 rounded-3xl border border-white/5 bg-white/[0.01]">
|
| 448 |
+
<h3 className="text-accent text-[10px] font-black uppercase tracking-[0.3em] mb-8">Classification Distribution</h3>
|
| 449 |
+
<div className="h-64">
|
| 450 |
+
<ResponsiveContainer width="100%" height="100%">
|
| 451 |
+
<PieChart>
|
| 452 |
+
<Pie data={displayThreats} dataKey="value" outerRadius="100%" innerRadius="75%" paddingAngle={10}>
|
| 453 |
+
{displayThreats.map((_, i) => <Cell key={i} fill={COLORS[i % COLORS.length]} stroke="none" />)}
|
| 454 |
+
</Pie>
|
| 455 |
+
<Tooltip contentStyle={{ backgroundColor: '#030617', border: '1px solid #00e5ff', borderRadius: '12px' }} />
|
| 456 |
+
</PieChart>
|
| 457 |
+
</ResponsiveContainer>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 458 |
</div>
|
| 459 |
</div>
|
| 460 |
|
| 461 |
+
<div className="p-8 rounded-3xl border border-white/5 bg-white/[0.01]">
|
| 462 |
+
<h3 className="text-accent text-[10px] font-black uppercase tracking-[0.3em] mb-8">Temporal Analysis</h3>
|
| 463 |
+
<div className="h-64">
|
| 464 |
+
<ResponsiveContainer width="100%" height="100%">
|
| 465 |
+
<BarChart data={displayThreats}>
|
| 466 |
+
<CartesianGrid strokeDasharray="3 3" strokeOpacity={0.03} vertical={false} />
|
| 467 |
+
<XAxis dataKey="name" fontSize={10} tick={{ fill: '#475569' }} axisLine={false} tickLine={false} />
|
| 468 |
+
<YAxis fontSize={10} tick={{ fill: '#475569' }} axisLine={false} tickLine={false} />
|
| 469 |
+
<Bar dataKey="value" fill="var(--accent)" radius={[6, 6, 0, 0]} barSize={40} />
|
| 470 |
+
</BarChart>
|
| 471 |
+
</ResponsiveContainer>
|
| 472 |
+
</div>
|
|
|
|
|
|
|
|
|
|
| 473 |
</div>
|
| 474 |
+
</div>
|
| 475 |
|
| 476 |
+
{/* Section: The Live Terminal Feed */}
|
| 477 |
+
<div className="rounded-2xl border border-white/5 bg-black/80 p-5 font-mono">
|
| 478 |
+
<div className="flex items-center gap-2 mb-4 text-accent/60">
|
| 479 |
+
<Terminal size={14} />
|
| 480 |
+
<span className="text-[10px] uppercase tracking-[0.4em]">Root@NIDS_AstraGuard:~# Live_Feed</span>
|
| 481 |
+
</div>
|
| 482 |
+
<div className="space-y-1 h-32 overflow-hidden flex flex-col-reverse">
|
| 483 |
+
{logs.map((log, i) => (
|
| 484 |
+
<div key={i} className={`text-[11px] ${log.includes('[WARN]') ? 'text-amber-500' : log.includes('[SEC]') ? 'text-rose-500' : 'text-slate-500'}`}>
|
| 485 |
+
{log}
|
| 486 |
+
</div>
|
| 487 |
+
))}
|
| 488 |
</div>
|
| 489 |
</div>
|
| 490 |
+
</div>
|
| 491 |
+
</main>
|
| 492 |
|
| 493 |
+
{/* 3. PROJECT ARCHITECTURE & INTERFACE HIGHLIGHTS */}
|
| 494 |
+
<section className="container mx-auto px-6 mb-24 relative z-10">
|
| 495 |
+
<div className="mb-12">
|
| 496 |
+
<h3 className="text-5xl italic font-bold uppercase tracking-tighter mb-2 bg-clip-text text-transparent bg-gradient-to-r from-orange-500 to-slate-500">Technical Implementation</h3>
|
| 497 |
+
<div className="h-1 w-12 bg-slate-700" />
|
| 498 |
+
</div>
|
| 499 |
+
|
| 500 |
+
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
|
| 501 |
+
|
| 502 |
+
{/* HIGHLIGHT 1: Model Training/Results */}
|
| 503 |
+
<div className="group space-y-4">
|
| 504 |
+
<div className="aspect-video rounded-lg border border-slate-800 bg-slate-900/50 overflow-hidden relative">
|
| 505 |
+
<img
|
| 506 |
+
src={CicidsImg}
|
| 507 |
+
alt="CIC-IDS2018 Training Results"
|
| 508 |
+
className="object-cover w-full h-full grayscale group-hover:grayscale-0 transition-all duration-500"
|
| 509 |
+
/>
|
| 510 |
+
<div className="absolute top-2 right-2 px-2 py-1 bg-black/80 rounded text-[9px] font-mono text-emerald-500 border border-emerald-500/20">
|
| 511 |
+
93% ACCURACY
|
| 512 |
+
</div>
|
| 513 |
+
</div>
|
| 514 |
+
<div>
|
| 515 |
+
<h4 className="text-white font-bold text-sm uppercase">01. Model Validation</h4>
|
| 516 |
+
<p className="text-slate-500 text-xs font-mono leading-relaxed mt-1">
|
| 517 |
+
Performance metrics for the Deep Neural Network (DNN) trained on the CIC-IDS2018 dataset.
|
| 518 |
+
</p>
|
| 519 |
</div>
|
| 520 |
+
</div>
|
| 521 |
|
| 522 |
+
{/* HIGHLIGHT 2: Live Traffic Monitoring */}
|
| 523 |
+
<div className="group space-y-4">
|
| 524 |
+
<div className="aspect-video rounded-lg border border-slate-800 bg-slate-900/50 overflow-hidden relative">
|
| 525 |
+
<img
|
| 526 |
+
src={LiveImg}
|
| 527 |
+
alt="Live Traffic Capture"
|
| 528 |
+
className="object-cover w-full h-full grayscale group-hover:grayscale-0 transition-all duration-500"
|
| 529 |
+
/>
|
| 530 |
+
<div className="absolute top-2 right-2 px-2 py-1 bg-black/80 rounded text-[9px] font-mono text-accent border border-accent/20">
|
| 531 |
+
REAL-TIME
|
| 532 |
+
</div>
|
| 533 |
+
</div>
|
| 534 |
+
<div>
|
| 535 |
+
<h4 className="text-white font-bold text-sm uppercase">02. Packet Ingestion</h4>
|
| 536 |
+
<p className="text-slate-500 text-xs font-mono leading-relaxed mt-1">
|
| 537 |
+
Visualization of incoming flow features before classification by the LightGBM engine.
|
| 538 |
+
</p>
|
| 539 |
+
</div>
|
| 540 |
+
</div>
|
| 541 |
+
|
| 542 |
+
{/* HIGHLIGHT 3: Darknet Classification */}
|
| 543 |
+
<div className="group space-y-4">
|
| 544 |
+
<div className="aspect-video rounded-lg border border-slate-800 bg-slate-900/50 overflow-hidden relative">
|
| 545 |
+
<img
|
| 546 |
+
src={BccImg}
|
| 547 |
+
alt="BCC Darknet Results"
|
| 548 |
+
className="object-cover w-full h-full grayscale group-hover:grayscale-0 transition-all duration-500"
|
| 549 |
+
/>
|
| 550 |
+
<div className="absolute top-2 right-2 px-2 py-1 bg-black/80 rounded text-[9px] font-mono text-amber-500 border border-amber-500/20">
|
| 551 |
+
96% ACCURACY
|
| 552 |
+
</div>
|
| 553 |
+
</div>
|
| 554 |
+
<div>
|
| 555 |
+
<h4 className="text-white font-bold text-sm uppercase">03. Darknet Analysis</h4>
|
| 556 |
+
<p className="text-slate-500 text-xs font-mono leading-relaxed mt-1">
|
| 557 |
+
Identifying malicious patterns using the BCC Darknet dataset with ensemble learning.
|
| 558 |
+
</p>
|
| 559 |
+
</div>
|
| 560 |
+
</div>
|
| 561 |
+
|
| 562 |
+
</div>
|
| 563 |
+
</section>
|
| 564 |
+
|
| 565 |
+
{/* FOOTER */}
|
| 566 |
+
<footer className="mt-24 border-t border-white/5 bg-[#030617] py-20">
|
| 567 |
+
<div className="container mx-auto px-6 lg:px-12">
|
| 568 |
+
<div className="grid grid-cols-1 md:grid-cols-12 gap-16">
|
| 569 |
+
<div className="md:col-span-5">
|
| 570 |
+
<div className="flex items-center gap-2 mb-6 group cursor-pointer">
|
| 571 |
+
<div className="w-10 h-10 rounded-lg bg-accent/10 border border-accent/40 flex items-center justify-center group-hover:bg-accent group-hover:text-orange-700 text-accent transition-all">
|
| 572 |
+
<Shield size={20} />
|
| 573 |
+
</div>
|
| 574 |
+
<h2 className="text-2xl font-black italic tracking-tighter uppercase">AI-NIDS</h2>
|
| 575 |
+
</div>
|
| 576 |
+
<p className="text-slate-500 font-mono text-[10px] uppercase leading-relaxed mb-8 max-w-sm">
|
| 577 |
+
<span className="text-accent/60 font-bold">// ENCRYPTED SESSION ACTIVE</span> <br />
|
| 578 |
+
AstraGuard is a decentralized neural defense platform monitoring global packet telemetry.
|
| 579 |
+
Neural-layer packet filtering enabled via Secure_V4 Protocol.
|
| 580 |
+
Heuristic mitigation active across 24 edge nodes.
|
| 581 |
+
</p>
|
| 582 |
+
<div className="flex gap-4 text-accent">
|
| 583 |
+
<button onClick={() => window.open("https://github.com/yishu13")} className="w-12 h-12 rounded-xl border border-white/5 bg-white/5 flex items-center justify-center hover:border-accent transition-all text-slate-400 hover:text-accent">
|
| 584 |
+
<Github size={20} />
|
| 585 |
+
</button>
|
| 586 |
+
<button onClick={() => window.open("https://linkedin.com/in/ayushrai13")} className="w-12 h-12 rounded-xl border border-white/5 bg-white/5 flex items-center justify-center hover:border-accent transition-all text-slate-400 hover:text-accent">
|
| 587 |
+
<Linkedin size={20} />
|
| 588 |
+
</button>
|
| 589 |
+
</div>
|
| 590 |
+
</div>
|
| 591 |
+
|
| 592 |
+
<div className="md:col-span-7 grid grid-cols-2 sm:grid-cols-3 gap-8">
|
| 593 |
+
{[
|
| 594 |
+
{ title: "Network", links: ["Live Traffic", "AI Alerts", "Protocol Analysis"] },
|
| 595 |
+
{ title: "Intelligence", links: ["Threat Maps", "Core Logs", "ML Training"] },
|
| 596 |
+
{ title: "Support", links: ["Documentation", "API Spec", "Whitepaper"] }
|
| 597 |
+
].map((group, i) => (
|
| 598 |
+
<div key={i}>
|
| 599 |
+
<h4 className="text-accent text-[10px] font-black uppercase tracking-widest mb-6 italic">{group.title}</h4>
|
| 600 |
+
<ul className="space-y-4">
|
| 601 |
+
{group.links.map((link, j) => (
|
| 602 |
+
<li key={j} className="text-xs text-slate-500 hover:text-white cursor-pointer transition-colors font-mono">> {link}</li>
|
| 603 |
+
))}
|
| 604 |
+
</ul>
|
| 605 |
+
</div>
|
| 606 |
+
))}
|
| 607 |
+
</div>
|
| 608 |
+
</div>
|
| 609 |
+
|
| 610 |
+
<div className="mt-20 pt-8 border-t border-white/5 flex flex-col sm:flex-row justify-between items-center gap-6">
|
| 611 |
+
<div className="flex items-center gap-4">
|
| 612 |
+
<div className="flex items-center gap-2">
|
| 613 |
+
<div className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
|
| 614 |
+
<span className="text-[10px] font-mono text-emerald-500/80 uppercase tracking-widest">Global_Status: Online</span>
|
| 615 |
+
</div>
|
| 616 |
+
</div>
|
| 617 |
+
<div className="text-[10px] font-mono text-slate-700 uppercase tracking-widest">
|
| 618 |
+
© {new Date().getFullYear()} ASTRAGUARD // PROTOCOL_V.04
|
| 619 |
+
</div>
|
| 620 |
+
</div>
|
| 621 |
+
</div>
|
| 622 |
+
</footer>
|
| 623 |
|
| 624 |
<ChatAssistant />
|
| 625 |
+
</div>
|
| 626 |
);
|
| 627 |
+
}
|
|
|
frontend/src/pages/FlowPage.jsx
CHANGED
|
@@ -2,29 +2,14 @@ import React, { useMemo, useState, useEffect, useRef } from "react";
|
|
| 2 |
import ChatAssistant from "./ChatAssistant";
|
| 3 |
import { useLocation, useNavigate } from "react-router-dom";
|
| 4 |
import {
|
| 5 |
-
Shield,
|
| 6 |
-
Lock,
|
| 7 |
-
Server,
|
| 8 |
-
Activity,
|
| 9 |
-
Wifi,
|
| 10 |
-
Play,
|
| 11 |
-
Pause,
|
| 12 |
-
Zap,
|
| 13 |
-
Radar,
|
| 14 |
-
RefreshCcw,
|
| 15 |
-
FileDown,
|
| 16 |
} from "lucide-react";
|
| 17 |
import {
|
| 18 |
-
BarChart,
|
| 19 |
-
Bar,
|
| 20 |
-
XAxis,
|
| 21 |
-
YAxis,
|
| 22 |
-
CartesianGrid,
|
| 23 |
-
Tooltip,
|
| 24 |
-
ResponsiveContainer,
|
| 25 |
} from "recharts";
|
| 26 |
import jsPDF from "jspdf";
|
| 27 |
import html2canvas from "html2canvas";
|
|
|
|
| 28 |
|
| 29 |
function useQuery() {
|
| 30 |
return new URLSearchParams(useLocation().search);
|
|
@@ -49,63 +34,55 @@ export default function FlowPage() {
|
|
| 49 |
getComputedStyle(document.body).getPropertyValue("--accent") || "#00e5ff"
|
| 50 |
);
|
| 51 |
|
| 52 |
-
// 🌀 Listen for theme color changes (syncs with system theme)
|
| 53 |
useEffect(() => {
|
| 54 |
const observer = new MutationObserver(() => {
|
| 55 |
const newAccent = getComputedStyle(document.body).getPropertyValue("--accent");
|
| 56 |
setAccentColor(newAccent.trim());
|
| 57 |
});
|
| 58 |
-
|
| 59 |
observer.observe(document.body, { attributes: true, attributeFilter: ["class"] });
|
| 60 |
-
|
| 61 |
return () => observer.disconnect();
|
| 62 |
}, []);
|
| 63 |
|
| 64 |
-
// 🧠 Generate sample logs
|
| 65 |
useEffect(() => {
|
| 66 |
const interval = setInterval(() => {
|
| 67 |
if (!paused && !replayActive) {
|
| 68 |
const t = new Date().toLocaleTimeString();
|
| 69 |
-
const fake = `[${t}] ${
|
| 70 |
-
Math.random() > 0.6 ? "⚠️ Suspicious" : "✅ Normal"
|
| 71 |
-
}`;
|
| 72 |
setLogs((p) => [fake, ...p.slice(0, 10)]);
|
| 73 |
}
|
| 74 |
}, 1500);
|
| 75 |
return () => clearInterval(interval);
|
| 76 |
-
}, [paused, replayActive]);
|
| 77 |
|
| 78 |
-
// 🎯 Flow definitions
|
| 79 |
const flow = useMemo(() => {
|
| 80 |
const titleMap = {
|
| 81 |
-
TOR: "TOR Network Attack Flow
|
| 82 |
-
I2P: "I2P Encrypted
|
| 83 |
-
VPN: "VPN Tunnel
|
| 84 |
-
FREENET: "Freenet
|
| 85 |
-
ZERONET: "ZeroNet
|
| 86 |
};
|
| 87 |
|
| 88 |
const nodes = [
|
| 89 |
-
{ id: "attacker", label: "
|
| 90 |
-
{ id: "entry", label: "Entry
|
| 91 |
-
{ id: "relay", label: "Relay
|
| 92 |
-
{ id: "exit", label: "Exit
|
| 93 |
-
{ id: "victim", label: "Victim
|
| 94 |
-
{ id: "detection", label: "
|
| 95 |
];
|
| 96 |
|
| 97 |
const paths = [
|
| 98 |
-
"M100 200 C200 100, 240 100,
|
| 99 |
-
"
|
| 100 |
-
"
|
| 101 |
-
"
|
| 102 |
-
"
|
| 103 |
];
|
| 104 |
|
| 105 |
return { title: titleMap[type], nodes, paths };
|
| 106 |
}, [type]);
|
| 107 |
|
| 108 |
-
// 🎞️ Replay Animation
|
| 109 |
useEffect(() => {
|
| 110 |
if (replayActive) {
|
| 111 |
let stage = 0;
|
|
@@ -119,9 +96,8 @@ export default function FlowPage() {
|
|
| 119 |
}, 1200);
|
| 120 |
return () => clearInterval(interval);
|
| 121 |
}
|
| 122 |
-
}, [replayActive]);
|
| 123 |
|
| 124 |
-
// 🧾 Export as PDF
|
| 125 |
const exportPDF = async () => {
|
| 126 |
const el = flowRef.current;
|
| 127 |
const canvas = await html2canvas(el);
|
|
@@ -130,246 +106,272 @@ export default function FlowPage() {
|
|
| 130 |
pdf.save(`${type}_Flow_Report.pdf`);
|
| 131 |
};
|
| 132 |
|
| 133 |
-
// 📊 Comparison data
|
| 134 |
const compareData = [
|
| 135 |
{ name: "TOR", risk: 85, detection: 92 },
|
| 136 |
{ name: "VPN", risk: 65, detection: 75 },
|
| 137 |
{ name: "I2P", risk: 75, detection: 88 },
|
| 138 |
{ name: "Freenet", risk: 50, detection: 70 },
|
| 139 |
-
{ name: "ZeroNet", risk: 60, detection: 73 },
|
| 140 |
];
|
| 141 |
|
| 142 |
return (
|
| 143 |
-
<div
|
| 144 |
-
|
| 145 |
-
className="
|
| 146 |
-
|
| 147 |
-
{/* Subtle animated theme glow */}
|
| 148 |
-
<div
|
| 149 |
-
className="absolute inset-0 blur-3xl opacity-20 pointer-events-none animate-pulse"
|
| 150 |
-
style={{
|
| 151 |
-
background: `radial-gradient(circle at 50% 50%, ${accentColor}55 0%, transparent 70%)`,
|
| 152 |
-
}}
|
| 153 |
-
/>
|
| 154 |
|
| 155 |
-
{/* Header */}
|
| 156 |
-
<
|
| 157 |
-
<button
|
| 158 |
-
onClick={() => navigate(-1)}
|
| 159 |
-
className="px-4 py-2 bg-[var(--card)]/50 border border-[var(--accent)]/30 rounded-lg text-[var(--accent)] hover:bg-[var(--accent)]/10 transition"
|
| 160 |
-
>
|
| 161 |
← Back
|
| 162 |
</button>
|
| 163 |
-
<h2 className="text-3xl font-bold text-[var(--accent)]
|
| 164 |
{flow.title}
|
| 165 |
</h2>
|
| 166 |
-
<button
|
| 167 |
-
|
| 168 |
-
className="px-3 py-2 bg-[var(--accent)]/20 border border-[var(--accent)]/30 rounded-lg text-[var(--accent)] hover:bg-[var(--accent)]/30 flex items-center gap-2"
|
| 169 |
-
>
|
| 170 |
-
<FileDown size={16} /> Export Report
|
| 171 |
</button>
|
| 172 |
-
</
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
stopOpacity="0.9"
|
| 184 |
-
/>
|
| 185 |
-
<stop
|
| 186 |
-
offset="100%"
|
| 187 |
-
stopColor={accentColor}
|
| 188 |
-
stopOpacity="0.3"
|
| 189 |
-
/>
|
| 190 |
-
</linearGradient>
|
| 191 |
-
<filter id="glow">
|
| 192 |
-
<feGaussianBlur stdDeviation="3.5" result="b" />
|
| 193 |
-
<feMerge>
|
| 194 |
-
<feMergeNode in="b" />
|
| 195 |
-
<feMergeNode in="SourceGraphic" />
|
| 196 |
-
</feMerge>
|
| 197 |
-
</filter>
|
| 198 |
-
</defs>
|
| 199 |
-
|
| 200 |
-
<g stroke="url(#flowGrad)" strokeWidth="3.5" fill="none" filter="url(#glow)">
|
| 201 |
-
{flow.paths.map((path, i) => {
|
| 202 |
-
const pathId = pid(`${flow.title}_${i}`);
|
| 203 |
-
return (
|
| 204 |
-
<g key={pathId}>
|
| 205 |
-
<path
|
| 206 |
-
id={pathId}
|
| 207 |
-
d={path}
|
| 208 |
-
strokeLinecap="round"
|
| 209 |
-
opacity={replayActive && i > activeStage ? 0.15 : 0.8}
|
| 210 |
-
/>
|
| 211 |
-
{!paused &&
|
| 212 |
-
Array.from({ length: 5 }).map((_, j) => (
|
| 213 |
-
<circle key={j} r="4" fill={highlightDetection ? "#ff0044" : accentColor} opacity="0.9">
|
| 214 |
-
<animateMotion
|
| 215 |
-
dur={`${speed}s`}
|
| 216 |
-
repeatCount="indefinite"
|
| 217 |
-
begin={`${j * 0.7}s`}
|
| 218 |
-
>
|
| 219 |
-
<mpath href={`#${pathId}`} />
|
| 220 |
-
</animateMotion>
|
| 221 |
</circle>
|
| 222 |
))}
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
</g>
|
| 227 |
-
|
| 228 |
-
{flow.nodes.map((n, i) => (
|
| 229 |
-
<g key={i}>
|
| 230 |
-
<circle
|
| 231 |
-
cx={n.x}
|
| 232 |
-
cy={n.y}
|
| 233 |
-
r="26"
|
| 234 |
-
fill={accentColor}
|
| 235 |
-
opacity={activeStage >= i || !replayActive ? 0.35 : 0.15}
|
| 236 |
-
stroke={accentColor}
|
| 237 |
-
strokeWidth="1.5"
|
| 238 |
-
filter="url(#glow)"
|
| 239 |
-
/>
|
| 240 |
-
<foreignObject x={n.x - 10} y={n.y - 10} width="20" height="20">
|
| 241 |
-
<div className="flex items-center justify-center w-full h-full text-[var(--text)]">
|
| 242 |
-
{n.icon}
|
| 243 |
-
</div>
|
| 244 |
-
</foreignObject>
|
| 245 |
-
<text
|
| 246 |
-
x={n.x}
|
| 247 |
-
y={n.y + 45}
|
| 248 |
-
textAnchor="middle"
|
| 249 |
-
fontSize="12"
|
| 250 |
-
fill="var(--text)"
|
| 251 |
-
>
|
| 252 |
-
{n.label}
|
| 253 |
-
</text>
|
| 254 |
</g>
|
| 255 |
-
|
| 256 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
</div>
|
| 258 |
|
| 259 |
-
{/* Logs */}
|
| 260 |
-
<div className="w-80 h-[
|
| 261 |
-
<h4 className="text-[var(--accent)] font-semibold mb-2 flex items-center gap-2">
|
| 262 |
<Radar size={14} /> Live Logs
|
| 263 |
</h4>
|
| 264 |
{logs.map((log, i) => (
|
| 265 |
-
<div key={i} className="border-b border-[var(--accent)]/10 pb-1">
|
| 266 |
-
{log}
|
| 267 |
-
</div>
|
| 268 |
))}
|
| 269 |
</div>
|
| 270 |
</div>
|
| 271 |
|
| 272 |
-
{/* Timeline */}
|
| 273 |
-
<div className="mt-8 px-10">
|
| 274 |
-
<h3 className="text-lg text-[var(--accent)] font-semibold mb-
|
| 275 |
-
<div className="flex items-center gap-8">
|
| 276 |
-
{flow.nodes.map((n,i)=>(
|
| 277 |
<div key={i} className="flex flex-col items-center">
|
| 278 |
-
<div className={`w-4 h-4 rounded-full ${i<=activeStage?"bg-[var(--accent)]":"bg-slate-700"}`}></div>
|
| 279 |
-
<p className="text-
|
| 280 |
</div>
|
| 281 |
))}
|
| 282 |
</div>
|
| 283 |
</div>
|
| 284 |
|
| 285 |
-
{/* Tabs */}
|
| 286 |
-
<div className="
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
))}
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
{activeTab===
|
| 300 |
-
<
|
| 301 |
-
)}
|
| 302 |
-
{activeTab==="mitigation" && (
|
| 303 |
-
<p>Network segmentation, DNS filtering, and retraining are key mitigations for {type}-based intrusions.</p>
|
| 304 |
-
)}
|
| 305 |
-
{activeTab==="dataset" && (
|
| 306 |
-
<p>Trained on CICIDS2017 + Darknet + custom captures across 18-class distribution including VPN, TOR, I2P.</p>
|
| 307 |
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 308 |
</div>
|
| 309 |
</div>
|
|
|
|
|
|
|
|
|
|
| 310 |
|
| 311 |
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 327 |
</div>
|
| 328 |
|
| 329 |
-
{/* Controls */}
|
| 330 |
-
<div className="fixed bottom-4 left-1/2 -translate-x-1/2 bg-[var(--card)]/
|
| 331 |
-
<
|
| 332 |
-
onClick={() => setPaused(!paused)}
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
<div className="flex items-center gap-2 text-sm text-[var(--accent)]">
|
| 339 |
-
<Zap size={16} /> Speed:
|
| 340 |
-
<input
|
| 341 |
-
type="range"
|
| 342 |
-
min="2"
|
| 343 |
-
max="10"
|
| 344 |
-
value={speed}
|
| 345 |
-
onChange={(e) => setSpeed(e.target.value)}
|
| 346 |
-
className="accent-[var(--accent)] w-28"
|
| 347 |
-
/>
|
| 348 |
-
<span>{speed}s</span>
|
| 349 |
</div>
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
<button
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
highlightDetection
|
| 360 |
-
? "bg-rose-600/30 border-rose-500/40 text-rose-300"
|
| 361 |
-
: "bg-[var(--accent)]/10 border-[var(--accent)]/30 text-[var(--accent)]"
|
| 362 |
-
}`}
|
| 363 |
-
>
|
| 364 |
-
{highlightDetection ? "Detection ON 🔴" : "Highlight Detection"}
|
| 365 |
</button>
|
| 366 |
</div>
|
|
|
|
| 367 |
<ChatAssistant />
|
| 368 |
</div>
|
| 369 |
);
|
| 370 |
-
}
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
|
|
|
| 2 |
import ChatAssistant from "./ChatAssistant";
|
| 3 |
import { useLocation, useNavigate } from "react-router-dom";
|
| 4 |
import {
|
| 5 |
+
Shield, Lock, Server, Activity, Wifi, Play, Pause, Zap, Radar, RefreshCcw, FileDown,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
} from "lucide-react";
|
| 7 |
import {
|
| 8 |
+
BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
} from "recharts";
|
| 10 |
import jsPDF from "jspdf";
|
| 11 |
import html2canvas from "html2canvas";
|
| 12 |
+
import toast, { Toaster } from "react-hot-toast"; // Fixed missing import
|
| 13 |
|
| 14 |
function useQuery() {
|
| 15 |
return new URLSearchParams(useLocation().search);
|
|
|
|
| 34 |
getComputedStyle(document.body).getPropertyValue("--accent") || "#00e5ff"
|
| 35 |
);
|
| 36 |
|
|
|
|
| 37 |
useEffect(() => {
|
| 38 |
const observer = new MutationObserver(() => {
|
| 39 |
const newAccent = getComputedStyle(document.body).getPropertyValue("--accent");
|
| 40 |
setAccentColor(newAccent.trim());
|
| 41 |
});
|
|
|
|
| 42 |
observer.observe(document.body, { attributes: true, attributeFilter: ["class"] });
|
|
|
|
| 43 |
return () => observer.disconnect();
|
| 44 |
}, []);
|
| 45 |
|
|
|
|
| 46 |
useEffect(() => {
|
| 47 |
const interval = setInterval(() => {
|
| 48 |
if (!paused && !replayActive) {
|
| 49 |
const t = new Date().toLocaleTimeString();
|
| 50 |
+
const fake = `[${t}] ${type} flow → ${Math.random() > 0.6 ? "⚠️ Suspicious" : "✅ Normal"}`;
|
|
|
|
|
|
|
| 51 |
setLogs((p) => [fake, ...p.slice(0, 10)]);
|
| 52 |
}
|
| 53 |
}, 1500);
|
| 54 |
return () => clearInterval(interval);
|
| 55 |
+
}, [paused, replayActive, type]);
|
| 56 |
|
|
|
|
| 57 |
const flow = useMemo(() => {
|
| 58 |
const titleMap = {
|
| 59 |
+
TOR: "TOR Network Attack Flow",
|
| 60 |
+
I2P: "I2P Encrypted Flow",
|
| 61 |
+
VPN: "VPN Tunnel Simulation",
|
| 62 |
+
FREENET: "Freenet Data Flow",
|
| 63 |
+
ZERONET: "ZeroNet P2P Flow",
|
| 64 |
};
|
| 65 |
|
| 66 |
const nodes = [
|
| 67 |
+
{ id: "attacker", label: "Origin", x: 100, y: 200, icon: <Activity size={16} /> },
|
| 68 |
+
{ id: "entry", label: "Entry", x: 300, y: 120, icon: <Lock size={16} /> },
|
| 69 |
+
{ id: "relay", label: "Relay", x: 550, y: 150, icon: <Wifi size={16} /> },
|
| 70 |
+
{ id: "exit", label: "Exit", x: 800, y: 200, icon: <Lock size={16} /> },
|
| 71 |
+
{ id: "victim", label: "Victim", x: 1050, y: 250, icon: <Server size={16} /> },
|
| 72 |
+
{ id: "detection", label: "AI", x: 1250, y: 250, icon: <Shield size={16} /> },
|
| 73 |
];
|
| 74 |
|
| 75 |
const paths = [
|
| 76 |
+
"M100 200 C200 100, 240 100, 300 120",
|
| 77 |
+
"M300 120 C400 100, 480 120, 550 150",
|
| 78 |
+
"M550 150 C650 160, 720 180, 800 200",
|
| 79 |
+
"M800 200 C950 240, 1000 260, 1050 250",
|
| 80 |
+
"M1050 250 C1150 260, 1200 260, 1250 250",
|
| 81 |
];
|
| 82 |
|
| 83 |
return { title: titleMap[type], nodes, paths };
|
| 84 |
}, [type]);
|
| 85 |
|
|
|
|
| 86 |
useEffect(() => {
|
| 87 |
if (replayActive) {
|
| 88 |
let stage = 0;
|
|
|
|
| 96 |
}, 1200);
|
| 97 |
return () => clearInterval(interval);
|
| 98 |
}
|
| 99 |
+
}, [replayActive, flow.nodes.length]);
|
| 100 |
|
|
|
|
| 101 |
const exportPDF = async () => {
|
| 102 |
const el = flowRef.current;
|
| 103 |
const canvas = await html2canvas(el);
|
|
|
|
| 106 |
pdf.save(`${type}_Flow_Report.pdf`);
|
| 107 |
};
|
| 108 |
|
|
|
|
| 109 |
const compareData = [
|
| 110 |
{ name: "TOR", risk: 85, detection: 92 },
|
| 111 |
{ name: "VPN", risk: 65, detection: 75 },
|
| 112 |
{ name: "I2P", risk: 75, detection: 88 },
|
| 113 |
{ name: "Freenet", risk: 50, detection: 70 },
|
|
|
|
| 114 |
];
|
| 115 |
|
| 116 |
return (
|
| 117 |
+
<div ref={flowRef} className="relative min-h-screen bg-[var(--card)] text-[var(--text)] overflow-x-hidden pb-32">
|
| 118 |
+
<Toaster position="bottom-right" />
|
| 119 |
+
<div className="absolute inset-0 blur-3xl opacity-20 pointer-events-none animate-pulse"
|
| 120 |
+
style={{ background: `radial-gradient(circle at 50% 50%, ${accentColor}55 0%, transparent 70%)` }} />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
|
| 122 |
+
{/* Responsive Header */}
|
| 123 |
+
<header className="flex flex-wrap items-center justify-between p-4 md:p-6 relative z-10 gap-4">
|
| 124 |
+
<button onClick={() => navigate(-1)} className="px-4 py-2 bg-[var(--card)]/50 border border-[var(--accent)]/30 rounded-lg text-[var(--accent)] text-sm">
|
|
|
|
|
|
|
|
|
|
| 125 |
← Back
|
| 126 |
</button>
|
| 127 |
+
<h2 className="text-xl md:text-3xl font-bold text-[var(--accent)] text-center flex-1 md:flex-none">
|
| 128 |
{flow.title}
|
| 129 |
</h2>
|
| 130 |
+
<button onClick={exportPDF} className="px-3 py-2 bg-[var(--accent)]/20 border border-[var(--accent)]/30 rounded-lg text-[var(--accent)] flex items-center gap-2 text-sm">
|
| 131 |
+
<FileDown size={16} /> <span className="hidden sm:inline">Export</span>
|
|
|
|
|
|
|
|
|
|
| 132 |
</button>
|
| 133 |
+
</header>
|
| 134 |
+
|
| 135 |
+
{/* Main Content Grid */}
|
| 136 |
+
<div className="flex flex-col lg:flex-row gap-6 px-4 md:px-6 relative z-10">
|
| 137 |
+
|
| 138 |
+
{/* SVG Flow - Makes it scrollable on tiny screens, scales on tablets */}
|
| 139 |
+
<div className="flex-1 overflow-x-auto lg:overflow-visible bg-black/20 rounded-2xl border border-white/5 p-4">
|
| 140 |
+
<div className="min-w-[800px] lg:min-w-full">
|
| 141 |
+
<svg viewBox="0 0 1350 400" width="100%" className="h-auto max-h-[500px]">
|
| 142 |
+
<defs>
|
| 143 |
+
<linearGradient id="flowGrad" x1="0" y1="0" x2="1" y2="1">
|
| 144 |
+
<stop offset="0%" stopColor={highlightDetection ? "#ff0044" : accentColor} stopOpacity="0.9" />
|
| 145 |
+
<stop offset="100%" stopColor={accentColor} stopOpacity="0.3" />
|
| 146 |
+
</linearGradient>
|
| 147 |
+
<filter id="glow"><feGaussianBlur stdDeviation="3.5" result="b" /><feMerge><feMergeNode in="b" /><feMergeNode in="SourceGraphic" /></feMerge></filter>
|
| 148 |
+
</defs>
|
| 149 |
|
| 150 |
+
<g stroke="url(#flowGrad)" strokeWidth="3.5" fill="none" filter="url(#glow)">
|
| 151 |
+
{flow.paths.map((path, i) => {
|
| 152 |
+
const pathId = pid(`${type}_${i}`);
|
| 153 |
+
return (
|
| 154 |
+
<g key={pathId}>
|
| 155 |
+
<path id={pathId} d={path} strokeLinecap="round" opacity={replayActive && i > activeStage ? 0.15 : 0.8} />
|
| 156 |
+
{!paused && Array.from({ length: 5 }).map((_, j) => (
|
| 157 |
+
<circle key={j} r="4" fill={highlightDetection ? "#ff0044" : accentColor}>
|
| 158 |
+
<animateMotion dur={`${speed}s`} repeatCount="indefinite" begin={`${j * 0.7}s`}><mpath href={`#${pathId}`} /></animateMotion>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
</circle>
|
| 160 |
))}
|
| 161 |
+
</g>
|
| 162 |
+
);
|
| 163 |
+
})}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
</g>
|
| 165 |
+
|
| 166 |
+
{flow.nodes.map((n, i) => (
|
| 167 |
+
<g key={i}>
|
| 168 |
+
<circle cx={n.x} cy={n.y} r="26" fill={accentColor} opacity={activeStage >= i || !replayActive ? 0.35 : 0.15} stroke={accentColor} strokeWidth="1.5" filter="url(#glow)" />
|
| 169 |
+
<foreignObject x={n.x - 10} y={n.y - 10} width="20" height="20">
|
| 170 |
+
<div className="flex items-center justify-center w-full h-full text-[var(--text)]">{n.icon}</div>
|
| 171 |
+
</foreignObject>
|
| 172 |
+
<text x={n.x} y={n.y + 45} textAnchor="middle" fontSize="12" fill="var(--text)" className="font-bold">{n.label}</text>
|
| 173 |
+
</g>
|
| 174 |
+
))}
|
| 175 |
+
</svg>
|
| 176 |
+
</div>
|
| 177 |
</div>
|
| 178 |
|
| 179 |
+
{/* Responsive Logs Panel */}
|
| 180 |
+
<div className="w-full lg:w-80 h-64 lg:h-[500px] bg-[var(--card)]/70 border border-[var(--accent)]/30 rounded-xl p-3 text-xs font-mono overflow-y-auto backdrop-blur-sm">
|
| 181 |
+
<h4 className="text-[var(--accent)] font-semibold mb-2 flex items-center gap-2 sticky top-0 bg-[var(--card)] py-1">
|
| 182 |
<Radar size={14} /> Live Logs
|
| 183 |
</h4>
|
| 184 |
{logs.map((log, i) => (
|
| 185 |
+
<div key={i} className="border-b border-[var(--accent)]/10 pb-1 py-1">{log}</div>
|
|
|
|
|
|
|
| 186 |
))}
|
| 187 |
</div>
|
| 188 |
</div>
|
| 189 |
|
| 190 |
+
{/* Timeline - Horizontal Scroll on Mobile */}
|
| 191 |
+
<div className="mt-8 px-4 md:px-10 overflow-x-auto pb-4">
|
| 192 |
+
<h3 className="text-lg text-[var(--accent)] font-semibold mb-4">Attack Timeline</h3>
|
| 193 |
+
<div className="flex items-center gap-4 md:gap-8 min-w-max">
|
| 194 |
+
{flow.nodes.map((n, i) => (
|
| 195 |
<div key={i} className="flex flex-col items-center">
|
| 196 |
+
<div className={`w-4 h-4 rounded-full transition-all duration-500 ${i <= activeStage ? "bg-[var(--accent)] scale-125 shadow-[0_0_10px_var(--accent)]" : "bg-slate-700"}`}></div>
|
| 197 |
+
<p className="text-[10px] mt-2 text-[var(--text)]/60">{n.label}</p>
|
| 198 |
</div>
|
| 199 |
))}
|
| 200 |
</div>
|
| 201 |
</div>
|
| 202 |
|
| 203 |
+
{/* Tabs & Comparison - Grid layout */}
|
| 204 |
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 px-4 md:px-10 mt-6 mb-10">
|
| 205 |
+
<div className="flex flex-col gap-3">
|
| 206 |
+
{/* Tactical Tab Navigation */}
|
| 207 |
+
<div className="flex flex-wrap gap-2">
|
| 208 |
+
{["behavior", "detection", "mitigation", "dataset"].map((tab) => (
|
| 209 |
+
<button
|
| 210 |
+
key={tab}
|
| 211 |
+
onClick={() => setActiveTab(tab)}
|
| 212 |
+
className={`relative px-4 py-2 text-[10px] font-black uppercase tracking-widest transition-all duration-300 overflow-hidden
|
| 213 |
+
${activeTab === tab
|
| 214 |
+
? "text-[var(--accent)] border-b-2 border-[var(--accent)]"
|
| 215 |
+
: "text-[var(--text)]/40 hover:text-[var(--text)]/80 border-b border-white/5"}`}
|
| 216 |
+
>
|
| 217 |
+
{activeTab === tab && (
|
| 218 |
+
<span className="absolute inset-0 bg-[var(--accent)]/5 animate-pulse" />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
)}
|
| 220 |
+
{tab}
|
| 221 |
+
</button>
|
| 222 |
+
))}
|
| 223 |
+
</div>
|
| 224 |
+
|
| 225 |
+
{/* Content Terminal Window */}
|
| 226 |
+
<div className="relative group">
|
| 227 |
+
{/* Decorative Brackets */}
|
| 228 |
+
<div className="absolute -top-2 -left-2 w-4 h-4 border-t-2 border-l-2 border-[var(--accent)]/30 group-hover:border-[var(--accent)] transition-colors" />
|
| 229 |
+
<div className="absolute -bottom-2 -right-2 w-4 h-4 border-b-2 border-r-2 border-[var(--accent)]/30 group-hover:border-[var(--accent)] transition-colors" />
|
| 230 |
+
|
| 231 |
+
<div className="bg-[var(--card)]/80 backdrop-blur-md border border-white/5 p-6 min-h-[160px] flex flex-col justify-between">
|
| 232 |
+
<div className="space-y-4">
|
| 233 |
+
<div className="flex items-center gap-2">
|
| 234 |
+
<div className="w-1.5 h-1.5 bg-[var(--accent)] animate-ping" />
|
| 235 |
+
<span className="text-[9px] font-mono text-[var(--accent)] tracking-[0.3em] uppercase">
|
| 236 |
+
Sector_{activeTab}_Analysis
|
| 237 |
+
</span>
|
| 238 |
+
</div>
|
| 239 |
+
|
| 240 |
+
<div className="font-mono text-sm leading-relaxed text-[var(--text)]/90 border-l-2 border-[var(--accent)]/20 pl-4 py-1">
|
| 241 |
+
{activeTab === "behavior" && (
|
| 242 |
+
<p><span className="text-[var(--accent)] font-bold">REPORT:</span> {type} utilizes a decentralized layered encryption mesh. Every node transition re-encapsulates the payload, creating a "Matryoshka" effect that obfuscates the original source IP and prevents packet-level correlation.</p>
|
| 243 |
+
)}
|
| 244 |
+
{activeTab === "detection" && (
|
| 245 |
+
<p><span className="text-[var(--accent)] font-bold">NEURAL_SIG:</span> AstraGuard AI employs recurrent feature extraction to identify microscopic jitter and inter-arrival time (IAT) variances unique to {type} tunnels, achieving an F1-score of 0.94.</p>
|
| 246 |
+
)}
|
| 247 |
+
{activeTab === "mitigation" && (
|
| 248 |
+
<p><span className="text-[var(--accent)] font-bold">DEFENSE:</span> Automated Null-Route triggers are prepared for localized clusters. Implementing dynamic circuit breaking and TLS-fingerprint filtering to strip {type} obfuscation layers at the edge gateway.</p>
|
| 249 |
+
)}
|
| 250 |
+
{activeTab === "dataset" && (
|
| 251 |
+
<p><span className="text-[var(--accent)] font-bold">SOURCE:</span> Synthesized from 1.4TB of telemetry including CICIDS2017, Darknet-2020, and live-captured PCAPs. Distribution covers 18 distinct traffic classes with supervised labeling.</p>
|
| 252 |
+
)}
|
| 253 |
+
</div>
|
| 254 |
+
</div>
|
| 255 |
+
|
| 256 |
+
{/* Bottom Metadata Line */}
|
| 257 |
+
<div className="mt-4 pt-4 border-t border-white/5 flex justify-between items-center opacity-40">
|
| 258 |
+
<span className="text-[8px] font-bold uppercase tracking-widest text-[var(--accent)]">Security Level: Level_4_Clearance</span>
|
| 259 |
+
<span className="text-[8px] font-bold text-[var(--accent)]">ID: {Math.random().toString(16).substr(2, 8).toUpperCase()}</span>
|
| 260 |
</div>
|
| 261 |
</div>
|
| 262 |
+
</div>
|
| 263 |
+
</div>
|
| 264 |
+
|
| 265 |
|
| 266 |
|
| 267 |
+
<div className="bg-[var(--card)]/70 p-6 rounded-xl border border-[var(--accent)]/30 h-[350px] relative overflow-hidden group">
|
| 268 |
+
{/* Decorative background scan line */}
|
| 269 |
+
<div className="absolute inset-0 pointer-events-none opacity-5 bg-[linear-gradient(transparent_50%,rgba(0,229,255,0.1)_50%)] bg-[length:100%_4px] animate-pulse" />
|
| 270 |
+
|
| 271 |
+
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-[var(--accent)] mb-6 flex items-center gap-2">
|
| 272 |
+
<Activity size={14} className="animate-pulse" /> Threat Propensity vs. Detection Accuracy
|
| 273 |
+
</h3>
|
| 274 |
+
|
| 275 |
+
<ResponsiveContainer width="100%" height="85%">
|
| 276 |
+
<BarChart data={compareData} margin={{ top: 10, right: 10, left: -20, bottom: 0 }}>
|
| 277 |
+
<defs>
|
| 278 |
+
{/* Gradient for Detection Bars */}
|
| 279 |
+
<linearGradient id="barGrad" x1="0" y1="0" x2="0" y2="1">
|
| 280 |
+
<stop offset="0%" stopColor="var(--accent)" stopOpacity={1} />
|
| 281 |
+
<stop offset="100%" stopColor="var(--accent)" stopOpacity={0.2} />
|
| 282 |
+
</linearGradient>
|
| 283 |
+
{/* Gradient for Risk Bars */}
|
| 284 |
+
<linearGradient id="riskGrad" x1="0" y1="0" x2="0" y2="1">
|
| 285 |
+
<stop offset="0%" stopColor="#f43f5e" stopOpacity={1} />
|
| 286 |
+
<stop offset="100%" stopColor="#f43f5e" stopOpacity={0.2} />
|
| 287 |
+
</linearGradient>
|
| 288 |
+
</defs>
|
| 289 |
+
|
| 290 |
+
<CartesianGrid
|
| 291 |
+
strokeDasharray="0"
|
| 292 |
+
vertical={false}
|
| 293 |
+
stroke="rgba(255,255,255,0.05)"
|
| 294 |
+
/>
|
| 295 |
+
|
| 296 |
+
<XAxis
|
| 297 |
+
dataKey="name"
|
| 298 |
+
axisLine={false}
|
| 299 |
+
tickLine={false}
|
| 300 |
+
tick={{ fill: 'var(--text)', fontSize: 10, fontWeight: 'bold' }}
|
| 301 |
+
dy={10}
|
| 302 |
+
/>
|
| 303 |
+
|
| 304 |
+
<YAxis
|
| 305 |
+
axisLine={false}
|
| 306 |
+
tickLine={false}
|
| 307 |
+
tick={{ fill: 'var(--text)', opacity: 0.4, fontSize: 9 }}
|
| 308 |
+
/>
|
| 309 |
+
|
| 310 |
+
<Tooltip
|
| 311 |
+
cursor={{ fill: 'rgba(255,255,255,0.03)' }}
|
| 312 |
+
contentStyle={{
|
| 313 |
+
backgroundColor: 'rgba(10,10,10,0.95)',
|
| 314 |
+
border: '1px solid var(--accent)',
|
| 315 |
+
borderRadius: '8px',
|
| 316 |
+
fontSize: '11px',
|
| 317 |
+
backdropFilter: 'blur(10px)'
|
| 318 |
+
}}
|
| 319 |
+
itemStyle={{ fontWeight: 'bold', textTransform: 'uppercase' }}
|
| 320 |
+
/>
|
| 321 |
+
|
| 322 |
+
{/* Main Bars with Glow Effect */}
|
| 323 |
+
<Bar
|
| 324 |
+
dataKey="risk"
|
| 325 |
+
fill="url(#riskGrad)"
|
| 326 |
+
radius={[2, 2, 0, 0]}
|
| 327 |
+
barSize={12}
|
| 328 |
+
/>
|
| 329 |
+
<Bar
|
| 330 |
+
dataKey="detection"
|
| 331 |
+
fill="url(#barGrad)"
|
| 332 |
+
radius={[2, 2, 0, 0]}
|
| 333 |
+
barSize={12}
|
| 334 |
+
/>
|
| 335 |
+
</BarChart>
|
| 336 |
+
</ResponsiveContainer>
|
| 337 |
+
|
| 338 |
+
{/* Legend Overlay */}
|
| 339 |
+
<div className="absolute bottom-4 right-6 flex gap-4">
|
| 340 |
+
<div className="flex items-center gap-1.5">
|
| 341 |
+
<div className="w-2 h-2 rounded-full bg-rose-500 shadow-[0_0_8px_#f43f5e]" />
|
| 342 |
+
<span className="text-[8px] font-black uppercase opacity-60 tracking-widest">Risk Index</span>
|
| 343 |
+
</div>
|
| 344 |
+
<div className="flex items-center gap-1.5">
|
| 345 |
+
<div className="w-2 h-2 rounded-full bg-[var(--accent)] shadow-[0_0_8px_var(--accent)]" />
|
| 346 |
+
<span className="text-[8px] font-black uppercase opacity-60 tracking-widest">AI Confidence</span>
|
| 347 |
+
</div>
|
| 348 |
+
</div>
|
| 349 |
+
</div>
|
| 350 |
</div>
|
| 351 |
|
| 352 |
+
{/* Responsive Floating Controls */}
|
| 353 |
+
<div className="fixed bottom-4 left-1/2 -translate-x-1/2 w-[92%] max-w-2xl bg-[var(--card)]/90 backdrop-blur-xl px-4 py-3 border border-[var(--accent)]/30 rounded-2xl flex flex-wrap items-center justify-between gap-3 shadow-2xl z-50">
|
| 354 |
+
<div className="flex items-center gap-4">
|
| 355 |
+
<button onClick={() => setPaused(!paused)} className="text-[var(--accent)] flex items-center gap-3 font-bold">Pause
|
| 356 |
+
{paused ? <Play size={20} /> : <Pause size={20} />}
|
| 357 |
+
</button>
|
| 358 |
+
<button onClick={() => setReplayActive(true)} className="text-[var(--accent)] font-bold gap-3 flex items-center">Refresh
|
| 359 |
+
<RefreshCcw size={18} />
|
| 360 |
+
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 361 |
</div>
|
| 362 |
+
|
| 363 |
+
<div className="hidden sm:flex items-center gap-2 text-[19px] text-[var(--accent)]">
|
| 364 |
+
<Zap size={14} /> Speed
|
| 365 |
+
<input type="range" min="2" max="10" value={speed} onChange={(e) => setSpeed(e.target.value)} className="accent-[var(--accent)] w-20" />
|
| 366 |
+
</div>
|
| 367 |
+
|
| 368 |
+
<button onClick={() => setHighlightDetection(!highlightDetection)}
|
| 369 |
+
className={`px-3 py-1.5 text-cyan-500 font-bold rounded-lg border transition-all ${highlightDetection ? "bg-rose-600 border-rose-500 text-white" : "border-[var(--accent)]/30 text-[var(--accent)]"}`}>
|
| 370 |
+
{highlightDetection ? "DETECTION ACTIVE" : "ISOLATE THREAT"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 371 |
</button>
|
| 372 |
</div>
|
| 373 |
+
|
| 374 |
<ChatAssistant />
|
| 375 |
</div>
|
| 376 |
);
|
| 377 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/pages/ReportsPage.jsx
CHANGED
|
@@ -1,29 +1,14 @@
|
|
| 1 |
import React, { useEffect, useState } from "react";
|
| 2 |
import {
|
| 3 |
-
FileText,
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
Eye,
|
| 7 |
-
Trash2,
|
| 8 |
-
RefreshCcw,
|
| 9 |
-
BarChart3,
|
| 10 |
-
Mail,
|
| 11 |
-
Send,
|
| 12 |
-
PieChart,
|
| 13 |
-
AlertTriangle,
|
| 14 |
} from "lucide-react";
|
| 15 |
import toast, { Toaster } from "react-hot-toast";
|
| 16 |
import ChatAssistant from "./ChatAssistant";
|
| 17 |
import {
|
| 18 |
-
ResponsiveContainer,
|
| 19 |
-
|
| 20 |
-
Line,
|
| 21 |
-
XAxis,
|
| 22 |
-
YAxis,
|
| 23 |
-
Tooltip,
|
| 24 |
-
Pie,
|
| 25 |
-
PieChart as PieChartComp,
|
| 26 |
-
Cell,
|
| 27 |
} from "recharts";
|
| 28 |
|
| 29 |
export default function ReportsPage() {
|
|
@@ -35,26 +20,21 @@ export default function ReportsPage() {
|
|
| 35 |
const [email, setEmail] = useState("");
|
| 36 |
const [sending, setSending] = useState(false);
|
| 37 |
|
| 38 |
-
const COLORS = ["#00e5ff", "#
|
| 39 |
|
| 40 |
-
// 🧠 Fetch available reports
|
| 41 |
const fetchReports = async () => {
|
| 42 |
try {
|
| 43 |
setLoading(true);
|
| 44 |
const res = await fetch("http://127.0.0.1:5000/api/reports/list");
|
| 45 |
-
if (!res.ok) throw new Error("Failed to fetch reports");
|
| 46 |
const data = await res.json();
|
| 47 |
setReports(data);
|
| 48 |
} catch (err) {
|
| 49 |
-
toast.error("Failed to load
|
| 50 |
-
console.error("Report fetch error:", err);
|
| 51 |
} finally {
|
| 52 |
setLoading(false);
|
| 53 |
}
|
| 54 |
};
|
| 55 |
|
| 56 |
-
// 📊 Fetch chart data
|
| 57 |
-
// 📊 Fetch chart data
|
| 58 |
const fetchCharts = async () => {
|
| 59 |
try {
|
| 60 |
const trendRes = await fetch("http://127.0.0.1:5000/api/reports/trend");
|
|
@@ -63,41 +43,26 @@ export default function ReportsPage() {
|
|
| 63 |
|
| 64 |
const distRes = await fetch("http://127.0.0.1:5000/api/reports/distribution");
|
| 65 |
const distData = await distRes.json();
|
| 66 |
-
// ✅ Convert object → array for PieChart
|
| 67 |
const distArray = Object.entries(distData).map(([name, value]) => ({ name, value }));
|
| 68 |
setReportDistribution(distArray);
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
};
|
| 73 |
-
|
| 74 |
|
| 75 |
useEffect(() => {
|
| 76 |
fetchReports();
|
| 77 |
fetchCharts();
|
| 78 |
}, []);
|
| 79 |
|
| 80 |
-
// 📥 Download report
|
| 81 |
const handleDownload = (r) => {
|
| 82 |
-
if (!r.endpoint)
|
| 83 |
-
toast.error("No download link found");
|
| 84 |
-
return;
|
| 85 |
-
}
|
| 86 |
window.open(r.endpoint, "_blank");
|
| 87 |
-
toast.success(`
|
| 88 |
};
|
| 89 |
|
| 90 |
-
// 🗑 Delete report (frontend only)
|
| 91 |
-
const handleDelete = (id) => {
|
| 92 |
-
setReports((prev) => prev.filter((r) => r.id !== id));
|
| 93 |
-
toast("🗑️ Report deleted successfully", {
|
| 94 |
-
style: { background: "#001122", color: "var(--accent)" },
|
| 95 |
-
});
|
| 96 |
-
};
|
| 97 |
-
|
| 98 |
-
// 📧 Send summary email
|
| 99 |
const handleSendEmail = async () => {
|
| 100 |
-
if (!email.trim()) return toast.error("
|
| 101 |
setSending(true);
|
| 102 |
try {
|
| 103 |
const res = await fetch("http://127.0.0.1:5000/api/reports/email", {
|
|
@@ -105,216 +70,167 @@ export default function ReportsPage() {
|
|
| 105 |
headers: { "Content-Type": "application/json" },
|
| 106 |
body: JSON.stringify({ email }),
|
| 107 |
});
|
| 108 |
-
|
| 109 |
-
if (res.ok) toast.success(result.message || `Email sent to ${email}`);
|
| 110 |
-
else toast.error(result.error || "Failed to send email");
|
| 111 |
} catch (err) {
|
| 112 |
-
toast.error("
|
| 113 |
-
console.error("Email send error:", err);
|
| 114 |
} finally {
|
| 115 |
setSending(false);
|
| 116 |
}
|
| 117 |
};
|
| 118 |
|
| 119 |
-
|
| 120 |
-
const filteredReports =
|
| 121 |
-
filter === "All" ? reports : reports.filter((r) => r.type === filter);
|
| 122 |
|
| 123 |
return (
|
| 124 |
-
<div className="p-
|
| 125 |
-
<Toaster position="
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
|
|
|
|
|
|
| 135 |
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
});
|
| 149 |
-
}}
|
| 150 |
-
className="flex items-center gap-2 bg-[var(--accent)]/10 border border-[var(--accent)]/20 text-[var(--accent)] px-3 py-1.5 rounded-lg hover:bg-[var(--accent)]/20 transition"
|
| 151 |
-
>
|
| 152 |
-
<RefreshCcw size={14} /> Refresh
|
| 153 |
-
</button>
|
| 154 |
</div>
|
| 155 |
|
| 156 |
-
{/*
|
| 157 |
-
<div className="
|
| 158 |
-
<div className="flex items-center gap-
|
| 159 |
-
<Filter size={
|
| 160 |
-
<
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
|
|
|
| 172 |
</div>
|
| 173 |
|
| 174 |
-
<div className="flex items-center gap-2">
|
| 175 |
<input
|
| 176 |
type="email"
|
| 177 |
-
placeholder="
|
| 178 |
value={email}
|
| 179 |
onChange={(e) => setEmail(e.target.value)}
|
| 180 |
-
className="bg-black/
|
| 181 |
/>
|
| 182 |
<button
|
| 183 |
onClick={handleSendEmail}
|
| 184 |
disabled={sending}
|
| 185 |
-
className="
|
| 186 |
>
|
| 187 |
-
{sending ? <
|
| 188 |
-
{sending ? "Sending..." : "Email Reports"}
|
| 189 |
</button>
|
| 190 |
</div>
|
| 191 |
</div>
|
| 192 |
|
| 193 |
-
{/*
|
| 194 |
-
<div className="
|
| 195 |
-
<
|
| 196 |
-
<
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
</p>
|
| 202 |
-
) : filteredReports.length === 0 ? (
|
| 203 |
-
<p className="text-center text-slate-500 py-10">
|
| 204 |
-
No reports available for this filter.
|
| 205 |
-
</p>
|
| 206 |
-
) : (
|
| 207 |
-
<div className="overflow-x-auto">
|
| 208 |
-
<table className="w-full text-sm text-left text-slate-300">
|
| 209 |
-
<thead className="text-xs uppercase text-[var(--accent)] border-b border-[var(--accent)]/20">
|
| 210 |
-
<tr>
|
| 211 |
-
<th className="px-3 py-2">Report Name</th>
|
| 212 |
-
<th className="px-3 py-2">Type</th>
|
| 213 |
-
<th className="px-3 py-2">Size</th>
|
| 214 |
-
<th className="px-3 py-2">Date</th>
|
| 215 |
-
<th className="px-3 py-2 text-right">Actions</th>
|
| 216 |
-
</tr>
|
| 217 |
-
</thead>
|
| 218 |
-
<tbody>
|
| 219 |
-
{filteredReports.map((r, i) => (
|
| 220 |
-
<tr
|
| 221 |
-
key={i}
|
| 222 |
-
className="border-b border-[var(--accent)]/10 hover:bg-[var(--accent)]/5 transition"
|
| 223 |
-
>
|
| 224 |
-
<td className="px-3 py-2 text-[var(--accent)] font-mono truncate">
|
| 225 |
-
{r.name}
|
| 226 |
-
</td>
|
| 227 |
-
<td className="px-3 py-2">{r.type}</td>
|
| 228 |
-
<td className="px-3 py-2">{r.size}</td>
|
| 229 |
-
<td className="px-3 py-2">{r.date}</td>
|
| 230 |
-
<td className="px-3 py-2 text-right space-x-2">
|
| 231 |
-
<button
|
| 232 |
-
onClick={() => handleDownload(r)}
|
| 233 |
-
className="text-emerald-400 hover:text-emerald-300"
|
| 234 |
-
title="Download"
|
| 235 |
-
>
|
| 236 |
-
<Download size={16} />
|
| 237 |
-
</button>
|
| 238 |
-
<button
|
| 239 |
-
onClick={() => toast.info(`Preview not available for ${r.name}`)}
|
| 240 |
-
className="text-cyan-400 hover:text-cyan-300"
|
| 241 |
-
title="Preview"
|
| 242 |
-
>
|
| 243 |
-
<Eye size={16} />
|
| 244 |
-
</button>
|
| 245 |
-
<button
|
| 246 |
-
onClick={() => handleDelete(r.id)}
|
| 247 |
-
className="text-rose-400 hover:text-rose-300"
|
| 248 |
-
title="Delete"
|
| 249 |
-
>
|
| 250 |
-
<Trash2 size={16} />
|
| 251 |
-
</button>
|
| 252 |
-
</td>
|
| 253 |
-
</tr>
|
| 254 |
-
))}
|
| 255 |
-
</tbody>
|
| 256 |
-
</table>
|
| 257 |
</div>
|
| 258 |
-
|
| 259 |
-
</div>
|
| 260 |
-
|
| 261 |
-
{/* ANALYTICS CHARTS */}
|
| 262 |
-
<div className="grid md:grid-cols-2 gap-6">
|
| 263 |
-
{/* Threat Trend */}
|
| 264 |
-
<div className="bg-black/40 border border-[var(--accent)]/20 rounded-xl p-5">
|
| 265 |
-
<h3 className="text-[var(--accent)] text-sm mb-3 flex items-center gap-2">
|
| 266 |
-
<AlertTriangle size={14} /> Attack Trend Overview
|
| 267 |
-
</h3>
|
| 268 |
-
<ResponsiveContainer width="100%" height={200}>
|
| 269 |
<LineChart data={attackTrend}>
|
| 270 |
-
<
|
|
|
|
| 271 |
<YAxis hide />
|
| 272 |
<Tooltip
|
| 273 |
-
contentStyle={{
|
| 274 |
-
backgroundColor: "#001122",
|
| 275 |
-
border: "1px solid var(--accent)",
|
| 276 |
-
borderRadius: "6px",
|
| 277 |
-
}}
|
| 278 |
/>
|
| 279 |
-
{
|
| 280 |
-
Object.keys(attackTrend[0])
|
| 281 |
-
.filter((key) => key !== "date")
|
| 282 |
-
.map((key, index) => (
|
| 283 |
-
<Line
|
| 284 |
-
key={index}
|
| 285 |
-
type="monotone"
|
| 286 |
-
dataKey={key}
|
| 287 |
-
stroke={COLORS[index % COLORS.length]}
|
| 288 |
-
strokeWidth={2}
|
| 289 |
-
/>
|
| 290 |
-
))}
|
| 291 |
</LineChart>
|
| 292 |
</ResponsiveContainer>
|
| 293 |
</div>
|
| 294 |
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
<h3 className="text-[var(--accent)] text-sm mb-3 flex items-center gap-2">
|
| 298 |
-
<PieChart size={14} /> Report Type Distribution
|
| 299 |
-
</h3>
|
| 300 |
<ResponsiveContainer width="100%" height={200}>
|
| 301 |
<PieChartComp>
|
| 302 |
-
<Pie
|
| 303 |
-
data={reportDistribution}
|
| 304 |
-
cx="50%"
|
| 305 |
-
cy="50%"
|
| 306 |
-
labelLine={false}
|
| 307 |
-
outerRadius={80}
|
| 308 |
-
dataKey="value"
|
| 309 |
-
>
|
| 310 |
{reportDistribution.map((entry, index) => (
|
| 311 |
-
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
|
| 312 |
))}
|
| 313 |
</Pie>
|
|
|
|
| 314 |
</PieChartComp>
|
| 315 |
</ResponsiveContainer>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 316 |
</div>
|
| 317 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
<ChatAssistant />
|
| 319 |
</div>
|
| 320 |
);
|
|
|
|
| 1 |
import React, { useEffect, useState } from "react";
|
| 2 |
import {
|
| 3 |
+
FileText, Filter, Download, Eye, Trash2, RefreshCcw,
|
| 4 |
+
BarChart3, Mail, Send, PieChart, AlertTriangle,
|
| 5 |
+
ShieldCheck, FileSearch, Database
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
} from "lucide-react";
|
| 7 |
import toast, { Toaster } from "react-hot-toast";
|
| 8 |
import ChatAssistant from "./ChatAssistant";
|
| 9 |
import {
|
| 10 |
+
ResponsiveContainer, LineChart, Line, XAxis, YAxis, Tooltip,
|
| 11 |
+
Pie, PieChart as PieChartComp, Cell, CartesianGrid
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
} from "recharts";
|
| 13 |
|
| 14 |
export default function ReportsPage() {
|
|
|
|
| 20 |
const [email, setEmail] = useState("");
|
| 21 |
const [sending, setSending] = useState(false);
|
| 22 |
|
| 23 |
+
const COLORS = ["#00e5ff", "#a78bfa", "#34d399", "#f43f5e"];
|
| 24 |
|
|
|
|
| 25 |
const fetchReports = async () => {
|
| 26 |
try {
|
| 27 |
setLoading(true);
|
| 28 |
const res = await fetch("http://127.0.0.1:5000/api/reports/list");
|
|
|
|
| 29 |
const data = await res.json();
|
| 30 |
setReports(data);
|
| 31 |
} catch (err) {
|
| 32 |
+
toast.error("Failed to load Intelligence logs");
|
|
|
|
| 33 |
} finally {
|
| 34 |
setLoading(false);
|
| 35 |
}
|
| 36 |
};
|
| 37 |
|
|
|
|
|
|
|
| 38 |
const fetchCharts = async () => {
|
| 39 |
try {
|
| 40 |
const trendRes = await fetch("http://127.0.0.1:5000/api/reports/trend");
|
|
|
|
| 43 |
|
| 44 |
const distRes = await fetch("http://127.0.0.1:5000/api/reports/distribution");
|
| 45 |
const distData = await distRes.json();
|
|
|
|
| 46 |
const distArray = Object.entries(distData).map(([name, value]) => ({ name, value }));
|
| 47 |
setReportDistribution(distArray);
|
| 48 |
+
} catch (err) {
|
| 49 |
+
console.error("Analytics fetch error:", err);
|
| 50 |
+
}
|
| 51 |
+
};
|
|
|
|
| 52 |
|
| 53 |
useEffect(() => {
|
| 54 |
fetchReports();
|
| 55 |
fetchCharts();
|
| 56 |
}, []);
|
| 57 |
|
|
|
|
| 58 |
const handleDownload = (r) => {
|
| 59 |
+
if (!r.endpoint) return toast.error("Binary source unavailable");
|
|
|
|
|
|
|
|
|
|
| 60 |
window.open(r.endpoint, "_blank");
|
| 61 |
+
toast.success(`Exporting: ${r.name}`);
|
| 62 |
};
|
| 63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
const handleSendEmail = async () => {
|
| 65 |
+
if (!email.trim()) return toast.error("Target address required");
|
| 66 |
setSending(true);
|
| 67 |
try {
|
| 68 |
const res = await fetch("http://127.0.0.1:5000/api/reports/email", {
|
|
|
|
| 70 |
headers: { "Content-Type": "application/json" },
|
| 71 |
body: JSON.stringify({ email }),
|
| 72 |
});
|
| 73 |
+
if (res.ok) toast.success(`Intelligence Summary dispatched to ${email}`);
|
|
|
|
|
|
|
| 74 |
} catch (err) {
|
| 75 |
+
toast.error("Dispatch failure");
|
|
|
|
| 76 |
} finally {
|
| 77 |
setSending(false);
|
| 78 |
}
|
| 79 |
};
|
| 80 |
|
| 81 |
+
const filteredReports = filter === "All" ? reports : reports.filter((r) => r.type === filter);
|
|
|
|
|
|
|
| 82 |
|
| 83 |
return (
|
| 84 |
+
<div className="p-8 space-y-8 bg-[#020617] min-h-screen text-slate-300 font-mono">
|
| 85 |
+
<Toaster position="top-center" />
|
| 86 |
+
|
| 87 |
+
{/* HEADER & META DATA */}
|
| 88 |
+
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-6 border-b border-slate-800 pb-8">
|
| 89 |
+
<div>
|
| 90 |
+
<div className="flex items-center gap-2 text-accent text-[10px] uppercase tracking-[0.3em] mb-2 font-black">
|
| 91 |
+
<ShieldCheck size={14} /> Security Intelligence Unit
|
| 92 |
+
</div>
|
| 93 |
+
<h1 className="text-4xl font-black text-white italic uppercase tracking-tighter">
|
| 94 |
+
Analytical <span className="text-slate-500">Reports</span>
|
| 95 |
+
</h1>
|
| 96 |
+
</div>
|
| 97 |
|
| 98 |
+
<div className="flex items-center gap-4">
|
| 99 |
+
<div className="hidden lg:block text-right mr-4">
|
| 100 |
+
<div className="text-[10px] text-slate-500 uppercase">System_Clock</div>
|
| 101 |
+
<div className="text-xs text-white uppercase">{new Date().toLocaleTimeString()}</div>
|
| 102 |
+
</div>
|
| 103 |
+
<button
|
| 104 |
+
onClick={() => { fetchReports(); fetchCharts(); }}
|
| 105 |
+
className="p-3 bg-white/5 border border-white/10 rounded-full hover:bg-accent hover:text-black transition-all"
|
| 106 |
+
>
|
| 107 |
+
<RefreshCcw size={18} />
|
| 108 |
+
</button>
|
| 109 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
</div>
|
| 111 |
|
| 112 |
+
{/* QUICK ACTIONS & EMAIL UTILITY */}
|
| 113 |
+
<div className="grid lg:grid-cols-3 gap-6">
|
| 114 |
+
<div className="lg:col-span-2 flex items-center gap-4 bg-slate-900/40 p-4 rounded-xl border border-white/5">
|
| 115 |
+
<Filter size={18} className="text-accent" />
|
| 116 |
+
<div className="flex gap-2">
|
| 117 |
+
{["All", "Threat Intelligence", "Network Analysis", "System Health"].map((cat) => (
|
| 118 |
+
<button
|
| 119 |
+
key={cat}
|
| 120 |
+
onClick={() => setFilter(cat)}
|
| 121 |
+
className={`px-4 py-1.5 rounded-md text-[10px] uppercase font-bold transition-all ${
|
| 122 |
+
filter === cat ? "bg-accent text-black" : "bg-white/5 text-slate-500 border border-white/5"
|
| 123 |
+
}`}
|
| 124 |
+
>
|
| 125 |
+
{cat}
|
| 126 |
+
</button>
|
| 127 |
+
))}
|
| 128 |
+
</div>
|
| 129 |
</div>
|
| 130 |
|
| 131 |
+
<div className="flex items-center gap-2 bg-slate-900/40 p-4 rounded-xl border border-white/5">
|
| 132 |
<input
|
| 133 |
type="email"
|
| 134 |
+
placeholder="Analyst Email Address"
|
| 135 |
value={email}
|
| 136 |
onChange={(e) => setEmail(e.target.value)}
|
| 137 |
+
className="flex-1 bg-black/50 border border-white/10 rounded-lg px-4 py-2 text-xs text-accent placeholder:text-slate-700 focus:outline-none focus:border-accent"
|
| 138 |
/>
|
| 139 |
<button
|
| 140 |
onClick={handleSendEmail}
|
| 141 |
disabled={sending}
|
| 142 |
+
className="bg-accent/10 border border-accent/30 text-accent p-2 rounded-lg hover:bg-accent hover:text-black transition-all"
|
| 143 |
>
|
| 144 |
+
{sending ? <RefreshCcw size={18} className="animate-spin" /> : <Send size={18} />}
|
|
|
|
| 145 |
</button>
|
| 146 |
</div>
|
| 147 |
</div>
|
| 148 |
|
| 149 |
+
{/* ANALYTICS PREVIEW SECTION */}
|
| 150 |
+
<div className="grid lg:grid-cols-12 gap-6">
|
| 151 |
+
<div className="lg:col-span-8 bg-slate-900/20 border border-white/5 rounded-2xl p-6">
|
| 152 |
+
<div className="flex justify-between items-center mb-6">
|
| 153 |
+
<h3 className="text-sm font-bold uppercase tracking-widest text-white flex items-center gap-2">
|
| 154 |
+
<AlertTriangle size={16} className="text-rose-500" /> Temporal Attack Trend
|
| 155 |
+
</h3>
|
| 156 |
+
<span className="text-[10px] text-slate-500 uppercase tracking-tighter italic">Source: CIC-IDS2018 Pipeline</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
</div>
|
| 158 |
+
<ResponsiveContainer width="100%" height={250}>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
<LineChart data={attackTrend}>
|
| 160 |
+
<CartesianGrid strokeDasharray="3 3" stroke="#1e293b" vertical={false} />
|
| 161 |
+
<XAxis dataKey="date" stroke="#475569" fontSize={10} tickLine={false} axisLine={false} />
|
| 162 |
<YAxis hide />
|
| 163 |
<Tooltip
|
| 164 |
+
contentStyle={{ backgroundColor: "#0f172a", border: "1px solid #334155", borderRadius: "8px", fontSize: "10px" }}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
/>
|
| 166 |
+
<Line type="monotone" dataKey="value" stroke="#00e5ff" strokeWidth={3} dot={{ r: 4, fill: "#00e5ff" }} activeDot={{ r: 6 }} />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
</LineChart>
|
| 168 |
</ResponsiveContainer>
|
| 169 |
</div>
|
| 170 |
|
| 171 |
+
<div className="lg:col-span-4 bg-slate-900/20 border border-white/5 rounded-2xl p-6 flex flex-col items-center justify-center">
|
| 172 |
+
<h3 className="text-sm font-bold uppercase tracking-widest text-white mb-6 self-start">Categorical Weight</h3>
|
|
|
|
|
|
|
|
|
|
| 173 |
<ResponsiveContainer width="100%" height={200}>
|
| 174 |
<PieChartComp>
|
| 175 |
+
<Pie data={reportDistribution} innerRadius={60} outerRadius={80} paddingAngle={5} dataKey="value">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
{reportDistribution.map((entry, index) => (
|
| 177 |
+
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} stroke="none" />
|
| 178 |
))}
|
| 179 |
</Pie>
|
| 180 |
+
<Tooltip />
|
| 181 |
</PieChartComp>
|
| 182 |
</ResponsiveContainer>
|
| 183 |
+
<div className="grid grid-cols-2 gap-4 mt-4 w-full">
|
| 184 |
+
{reportDistribution.slice(0, 4).map((item, i) => (
|
| 185 |
+
<div key={i} className="flex items-center gap-2">
|
| 186 |
+
<div className="w-2 h-2 rounded-full" style={{ backgroundColor: COLORS[i] }} />
|
| 187 |
+
<span className="text-[9px] uppercase text-slate-500 truncate">{item.name}</span>
|
| 188 |
+
</div>
|
| 189 |
+
))}
|
| 190 |
+
</div>
|
| 191 |
</div>
|
| 192 |
</div>
|
| 193 |
+
|
| 194 |
+
{/* DATA GRID - THE REPORTS */}
|
| 195 |
+
<div className="space-y-4">
|
| 196 |
+
<h3 className="text-sm font-bold uppercase tracking-widest text-white flex items-center gap-2 px-2">
|
| 197 |
+
<Database size={16} className="text-accent" /> Data Repository
|
| 198 |
+
</h3>
|
| 199 |
+
|
| 200 |
+
{loading ? (
|
| 201 |
+
<div className="h-48 flex items-center justify-center border border-dashed border-slate-800 rounded-2xl">
|
| 202 |
+
<span className="animate-pulse text-slate-600 text-xs uppercase tracking-[0.5em]">Syncing_Database...</span>
|
| 203 |
+
</div>
|
| 204 |
+
) : (
|
| 205 |
+
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
| 206 |
+
{filteredReports.map((r, i) => (
|
| 207 |
+
<div key={i} className="group bg-slate-900/40 border border-white/5 p-5 rounded-2xl hover:border-accent/40 transition-all">
|
| 208 |
+
<div className="flex justify-between items-start mb-4">
|
| 209 |
+
<div className="p-3 bg-black/50 rounded-xl border border-white/5 text-accent">
|
| 210 |
+
<FileSearch size={24} />
|
| 211 |
+
</div>
|
| 212 |
+
<div className="flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
| 213 |
+
<button onClick={() => handleDownload(r)} className="p-2 hover:bg-emerald-500/20 text-emerald-500 rounded-md transition-colors"><Download size={16} /></button>
|
| 214 |
+
<button className="p-2 hover:bg-rose-500/20 text-rose-500 rounded-md transition-colors"><Trash2 size={16} /></button>
|
| 215 |
+
</div>
|
| 216 |
+
</div>
|
| 217 |
+
<div className="space-y-1">
|
| 218 |
+
<h4 className="text-white font-bold text-sm truncate uppercase tracking-tight">{r.name}</h4>
|
| 219 |
+
<div className="flex items-center justify-between">
|
| 220 |
+
<span className="text-[10px] text-slate-500 font-mono">{r.type}</span>
|
| 221 |
+
<span className="text-[10px] text-accent bg-accent/10 px-2 py-0.5 rounded uppercase font-bold">{r.size}</span>
|
| 222 |
+
</div>
|
| 223 |
+
</div>
|
| 224 |
+
<div className="mt-4 pt-4 border-t border-white/5 text-[9px] text-slate-600 flex justify-between">
|
| 225 |
+
<span>TIMESTAMP: {r.date}</span>
|
| 226 |
+
<span className="text-emerald-500/50">SECURED_V4</span>
|
| 227 |
+
</div>
|
| 228 |
+
</div>
|
| 229 |
+
))}
|
| 230 |
+
</div>
|
| 231 |
+
)}
|
| 232 |
+
</div>
|
| 233 |
+
|
| 234 |
<ChatAssistant />
|
| 235 |
</div>
|
| 236 |
);
|
frontend/src/pages/SettingsPage.jsx
CHANGED
|
@@ -1,814 +1,240 @@
|
|
| 1 |
-
|
| 2 |
-
import React, { useState, useEffect } from "react";
|
| 3 |
import {
|
| 4 |
-
Settings,
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
Wifi,
|
| 8 |
-
Save,
|
| 9 |
-
RefreshCcw,
|
| 10 |
-
Brain,
|
| 11 |
-
Zap,
|
| 12 |
-
FileDown,
|
| 13 |
-
Palette,
|
| 14 |
-
Bell,
|
| 15 |
-
Sliders,
|
| 16 |
-
ShieldAlert,
|
| 17 |
-
HardDrive,
|
| 18 |
-
UploadCloud,
|
| 19 |
-
Users,
|
| 20 |
} from "lucide-react";
|
| 21 |
import toast, { Toaster } from "react-hot-toast";
|
| 22 |
import { useAuth } from "../context/AuthContext";
|
| 23 |
|
| 24 |
-
// ---------- DEFAULT HELPERS (no shared reference issues) ----------
|
| 25 |
-
|
| 26 |
-
const createDefaultThreatRules = () => ({
|
| 27 |
-
// CICIDS2018 classes (from your list, ignoring counts)
|
| 28 |
-
cicids2018: {
|
| 29 |
-
BENIGN: true,
|
| 30 |
-
Bot: true,
|
| 31 |
-
"DoS attacks-Hulk": true,
|
| 32 |
-
"DoS attacks-SlowHTTPTest": true,
|
| 33 |
-
Infilteration: true,
|
| 34 |
-
"DoS attacks-GoldenEye": true,
|
| 35 |
-
"DoS attacks-Slowloris": true,
|
| 36 |
-
"FTP-BruteForce": true,
|
| 37 |
-
"SSH-Bruteforce": true,
|
| 38 |
-
"DDOS attack-HOIC": true,
|
| 39 |
-
"DDOS attack-LOIC-UDP": true,
|
| 40 |
-
"Brute Force -Web": true,
|
| 41 |
-
"Brute Force -XSS": true,
|
| 42 |
-
"SQL Injection": true,
|
| 43 |
-
},
|
| 44 |
-
// BCC classes
|
| 45 |
-
bcc: {
|
| 46 |
-
Freenet: true,
|
| 47 |
-
TOR: true,
|
| 48 |
-
ZERONET: true,
|
| 49 |
-
I2P: true,
|
| 50 |
-
VPN: true,
|
| 51 |
-
},
|
| 52 |
-
});
|
| 53 |
-
|
| 54 |
-
const createDefaultCaptureSettings = () => ({
|
| 55 |
-
interface: "AUTO",
|
| 56 |
-
protocol: "ANY",
|
| 57 |
-
maxPackets: 5000,
|
| 58 |
-
sampleRate: "1x",
|
| 59 |
-
});
|
| 60 |
-
|
| 61 |
-
const createDefaultRetention = () => ({
|
| 62 |
-
logDays: 7,
|
| 63 |
-
anonymizeIP: false,
|
| 64 |
-
autoPurge: true,
|
| 65 |
-
});
|
| 66 |
-
|
| 67 |
-
const createDefaultNotifications = () => ({
|
| 68 |
-
enablePopup: true,
|
| 69 |
-
emailAlerts: false,
|
| 70 |
-
email: "",
|
| 71 |
-
criticalThreshold: 10,
|
| 72 |
-
});
|
| 73 |
-
|
| 74 |
-
const createDefaultModelConfig = () => ({
|
| 75 |
-
activeDataset: "CICIDS2018", // or "BCC"
|
| 76 |
-
activeModelName: "CICIDS2018_Default",
|
| 77 |
-
customModelName: "",
|
| 78 |
-
lastUpdated: null,
|
| 79 |
-
});
|
| 80 |
-
|
| 81 |
export default function SettingsPage() {
|
| 82 |
const { settings, setSettings, saveSettings, user } = useAuth();
|
| 83 |
-
|
| 84 |
-
//
|
| 85 |
-
const [
|
| 86 |
-
const [
|
| 87 |
-
const [
|
| 88 |
-
const [
|
| 89 |
-
const [
|
| 90 |
-
const [
|
| 91 |
-
const [
|
| 92 |
-
const [
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
const
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
);
|
| 99 |
-
const [retention, setRetention] = useState(createDefaultRetention);
|
| 100 |
-
const [notificationSettings, setNotificationSettings] = useState(
|
| 101 |
-
createDefaultNotifications
|
| 102 |
-
);
|
| 103 |
-
const [modelConfig, setModelConfig] = useState(createDefaultModelConfig);
|
| 104 |
-
|
| 105 |
-
// UI-only state
|
| 106 |
-
const [activeThreatDataset, setActiveThreatDataset] =
|
| 107 |
-
useState("CICIDS2018"); // "CICIDS2018" | "BCC"
|
| 108 |
-
const [modelFile, setModelFile] = useState(null);
|
| 109 |
-
|
| 110 |
-
// 🧠 Load from Firestore on login/settings change
|
| 111 |
-
useEffect(() => {
|
| 112 |
-
if (settings) {
|
| 113 |
-
setAutoRefresh(settings.autoRefresh);
|
| 114 |
-
setSoundAlerts(settings.soundAlerts);
|
| 115 |
-
setAiSensitivity(settings.aiSensitivity);
|
| 116 |
-
setResponseMode(settings.responseMode);
|
| 117 |
-
setIpConfig(settings.ipConfig);
|
| 118 |
-
setPortConfig(settings.portConfig);
|
| 119 |
-
setTheme(settings.theme);
|
| 120 |
-
applyTheme(settings.theme);
|
| 121 |
-
|
| 122 |
-
setThreatRules(
|
| 123 |
-
settings.threatRules || createDefaultThreatRules()
|
| 124 |
-
);
|
| 125 |
-
setCaptureSettings(
|
| 126 |
-
settings.captureSettings || createDefaultCaptureSettings()
|
| 127 |
-
);
|
| 128 |
-
setRetention(
|
| 129 |
-
settings.retention || createDefaultRetention()
|
| 130 |
-
);
|
| 131 |
-
setNotificationSettings(
|
| 132 |
-
settings.notificationSettings ||
|
| 133 |
-
createDefaultNotifications()
|
| 134 |
-
);
|
| 135 |
-
setModelConfig(
|
| 136 |
-
settings.modelConfig || createDefaultModelConfig()
|
| 137 |
-
);
|
| 138 |
-
}
|
| 139 |
-
}, [settings]);
|
| 140 |
-
|
| 141 |
-
// 🎨 Apply theme globally
|
| 142 |
-
const applyTheme = (selectedTheme) => {
|
| 143 |
const body = document.body;
|
| 144 |
-
body.classList.remove(
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
"theme-emerald",
|
| 148 |
-
"theme-default"
|
| 149 |
-
);
|
| 150 |
-
switch (selectedTheme) {
|
| 151 |
-
case "Cyber Blue":
|
| 152 |
-
body.classList.add("theme-cyber");
|
| 153 |
-
break;
|
| 154 |
-
case "Crimson Dark":
|
| 155 |
-
body.classList.add("theme-crimson");
|
| 156 |
-
break;
|
| 157 |
-
case "Emerald Matrix":
|
| 158 |
-
body.classList.add("theme-emerald");
|
| 159 |
-
break;
|
| 160 |
-
default:
|
| 161 |
-
body.classList.add("theme-default");
|
| 162 |
-
}
|
| 163 |
};
|
| 164 |
|
| 165 |
-
// 💾 Save to Firestore (extended)
|
| 166 |
const handleSave = async () => {
|
| 167 |
-
const newSettings = {
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
aiSensitivity,
|
| 171 |
-
responseMode,
|
| 172 |
-
ipConfig,
|
| 173 |
-
portConfig,
|
| 174 |
-
theme,
|
| 175 |
-
|
| 176 |
-
// new enterprise sections
|
| 177 |
-
threatRules,
|
| 178 |
-
captureSettings,
|
| 179 |
-
retention,
|
| 180 |
-
notificationSettings,
|
| 181 |
-
modelConfig,
|
| 182 |
-
};
|
| 183 |
-
|
| 184 |
-
setSettings(newSettings);
|
| 185 |
-
await saveSettings(newSettings); // 🔥 Saves to Firestore
|
| 186 |
-
toast.success("✅ Settings saved");
|
| 187 |
-
};
|
| 188 |
-
|
| 189 |
-
// Backup to local file (for download)
|
| 190 |
-
const handleBackup = () => {
|
| 191 |
-
toast("🧬 Generating system backup...", { icon: "💾" });
|
| 192 |
-
setBackupProgress(0);
|
| 193 |
-
let progress = 0;
|
| 194 |
-
const timer = setInterval(() => {
|
| 195 |
-
progress += 10;
|
| 196 |
-
setBackupProgress(progress);
|
| 197 |
-
if (progress >= 100) {
|
| 198 |
-
clearInterval(timer);
|
| 199 |
-
toast.success("✅ Backup completed!");
|
| 200 |
-
const blob = new Blob(
|
| 201 |
-
[JSON.stringify(settings, null, 2)],
|
| 202 |
-
{ type: "application/json" }
|
| 203 |
-
);
|
| 204 |
-
const link = document.createElement("a");
|
| 205 |
-
link.href = URL.createObjectURL(blob);
|
| 206 |
-
link.download = "nids_system_backup.json";
|
| 207 |
-
link.click();
|
| 208 |
-
}
|
| 209 |
-
}, 200);
|
| 210 |
-
};
|
| 211 |
-
|
| 212 |
-
const handleReset = async () => {
|
| 213 |
-
if (!window.confirm("⚠️ Reset all settings to default?")) return;
|
| 214 |
-
|
| 215 |
-
const def = {
|
| 216 |
-
theme: "Cyber Blue",
|
| 217 |
-
autoRefresh: true,
|
| 218 |
-
soundAlerts: true,
|
| 219 |
-
aiSensitivity: 70,
|
| 220 |
-
responseMode: "Semi-Auto",
|
| 221 |
-
ipConfig: "127.0.0.1",
|
| 222 |
-
portConfig: "5000",
|
| 223 |
-
|
| 224 |
-
threatRules: createDefaultThreatRules(),
|
| 225 |
-
captureSettings: createDefaultCaptureSettings(),
|
| 226 |
-
retention: createDefaultRetention(),
|
| 227 |
-
notificationSettings: createDefaultNotifications(),
|
| 228 |
-
modelConfig: createDefaultModelConfig(),
|
| 229 |
-
};
|
| 230 |
-
|
| 231 |
-
setSettings(def);
|
| 232 |
-
await saveSettings(def);
|
| 233 |
-
applyTheme("Cyber Blue");
|
| 234 |
-
setThreatRules(def.threatRules);
|
| 235 |
-
setCaptureSettings(def.captureSettings);
|
| 236 |
-
setRetention(def.retention);
|
| 237 |
-
setNotificationSettings(def.notificationSettings);
|
| 238 |
-
setModelConfig(def.modelConfig);
|
| 239 |
-
toast.success("✅ Settings restored to default");
|
| 240 |
-
};
|
| 241 |
-
|
| 242 |
-
// Threat rule toggler
|
| 243 |
-
const handleToggleRule = (datasetKey, ruleKey) => {
|
| 244 |
-
setThreatRules((prev) => ({
|
| 245 |
-
...prev,
|
| 246 |
-
[datasetKey]: {
|
| 247 |
-
...prev[datasetKey],
|
| 248 |
-
[ruleKey]: !prev[datasetKey][ruleKey],
|
| 249 |
-
},
|
| 250 |
-
}));
|
| 251 |
-
};
|
| 252 |
-
|
| 253 |
-
// Model upload (no backend, safe)
|
| 254 |
-
const handleModelUpload = () => {
|
| 255 |
-
if (!modelFile) {
|
| 256 |
-
toast.error("Please select a model file first.");
|
| 257 |
-
return;
|
| 258 |
-
}
|
| 259 |
-
|
| 260 |
-
const updated = {
|
| 261 |
-
...modelConfig,
|
| 262 |
-
customModelName: modelFile.name,
|
| 263 |
-
lastUpdated: new Date().toISOString(),
|
| 264 |
-
};
|
| 265 |
-
|
| 266 |
-
setModelConfig(updated);
|
| 267 |
-
toast.success(
|
| 268 |
-
"✅ Custom model registered (metadata saved in settings)."
|
| 269 |
-
);
|
| 270 |
};
|
| 271 |
|
| 272 |
-
const currentThreatKey =
|
| 273 |
-
activeThreatDataset === "CICIDS2018" ? "cicids2018" : "bcc";
|
| 274 |
-
const currentThreatRules = threatRules[currentThreatKey] || {};
|
| 275 |
-
|
| 276 |
return (
|
| 277 |
-
<div className="p-
|
| 278 |
<Toaster position="bottom-right" />
|
| 279 |
-
<div
|
| 280 |
-
className="absolute inset-0 animate-pulse-slow pointer-events-none"
|
| 281 |
-
style={{
|
| 282 |
-
background:
|
| 283 |
-
"radial-gradient(circle at center, color-mix(in srgb, var(--accent) 25%, transparent) 8%, transparent 75%)",
|
| 284 |
-
opacity: 0.25,
|
| 285 |
-
}}
|
| 286 |
-
/>
|
| 287 |
-
|
| 288 |
-
{/* HEADER */}
|
| 289 |
-
<div className="flex justify-between items-center relative z-10">
|
| 290 |
-
<h2 className="text-2xl font-semibold text-accent flex items-center gap-2">
|
| 291 |
-
<Settings size={22} /> System Configuration
|
| 292 |
-
</h2>
|
| 293 |
-
<button
|
| 294 |
-
onClick={handleSave}
|
| 295 |
-
className="px-3 py-2 bg-cyan-500/20 border border-cyan-400/30 rounded-lg hover:bg-cyan-500/30 text-cyan-300 flex items-center gap-2"
|
| 296 |
-
>
|
| 297 |
-
<Save size={14} /> Save
|
| 298 |
-
</button>
|
| 299 |
-
</div>
|
| 300 |
-
|
| 301 |
-
{/* ⚙️ SYSTEM PREFERENCES */}
|
| 302 |
-
<div className="card-glow rounded-xl p-5 relative z-10">
|
| 303 |
-
<h3 className="text-accent text-sm mb-3 flex items-center gap-2">
|
| 304 |
-
<Zap size={14} /> System Preferences
|
| 305 |
-
</h3>
|
| 306 |
-
<div className="flex flex-wrap gap-6 text-sm text-[var(--text)]/80">
|
| 307 |
-
{/* Auto Refresh */}
|
| 308 |
-
<div
|
| 309 |
-
className="flex items-center gap-3 cursor-pointer hover:text-accent"
|
| 310 |
-
onClick={() => setAutoRefresh(!autoRefresh)}
|
| 311 |
-
>
|
| 312 |
-
{autoRefresh ? (
|
| 313 |
-
<ToggleRight size={20} />
|
| 314 |
-
) : (
|
| 315 |
-
<ToggleLeft size={20} />
|
| 316 |
-
)}
|
| 317 |
-
Auto Refresh
|
| 318 |
-
</div>
|
| 319 |
-
|
| 320 |
-
{/* Sound Alerts */}
|
| 321 |
-
<div
|
| 322 |
-
className="flex items-center gap-3 cursor-pointer hover:text-accent"
|
| 323 |
-
onClick={() => setSoundAlerts(!soundAlerts)}
|
| 324 |
-
>
|
| 325 |
-
{soundAlerts ? (
|
| 326 |
-
<ToggleRight size={20} />
|
| 327 |
-
) : (
|
| 328 |
-
<ToggleLeft size={20} />
|
| 329 |
-
)}
|
| 330 |
-
Sound Alerts
|
| 331 |
-
</div>
|
| 332 |
-
|
| 333 |
-
{/* Data Retention */}
|
| 334 |
-
<div className="flex items-center gap-2">
|
| 335 |
-
<span>Data Retention:</span>
|
| 336 |
-
<select
|
| 337 |
-
value={retention.logDays}
|
| 338 |
-
onChange={(e) =>
|
| 339 |
-
setRetention((prev) => ({
|
| 340 |
-
...prev,
|
| 341 |
-
logDays: Number(e.target.value),
|
| 342 |
-
}))
|
| 343 |
-
}
|
| 344 |
-
className="bg-card border border-accent rounded px-2 py-1 text-accent"
|
| 345 |
-
>
|
| 346 |
-
<option value={1}>24 Hours</option>
|
| 347 |
-
<option value={7}>7 Days</option>
|
| 348 |
-
<option value={30}>30 Days</option>
|
| 349 |
-
</select>
|
| 350 |
-
</div>
|
| 351 |
-
|
| 352 |
-
{/* Anonymize IP */}
|
| 353 |
-
<div
|
| 354 |
-
className="flex items-center gap-3 cursor-pointer hover:text-accent"
|
| 355 |
-
onClick={() =>
|
| 356 |
-
setRetention((prev) => ({
|
| 357 |
-
...prev,
|
| 358 |
-
anonymizeIP: !prev.anonymizeIP,
|
| 359 |
-
}))
|
| 360 |
-
}
|
| 361 |
-
>
|
| 362 |
-
{retention.anonymizeIP ? (
|
| 363 |
-
<ToggleRight size={20} />
|
| 364 |
-
) : (
|
| 365 |
-
<ToggleLeft size={20} />
|
| 366 |
-
)}
|
| 367 |
-
Anonymize IP Addresses
|
| 368 |
-
</div>
|
| 369 |
-
</div>
|
| 370 |
-
</div>
|
| 371 |
|
| 372 |
-
{/*
|
| 373 |
-
<div className="
|
| 374 |
-
<
|
| 375 |
-
<
|
| 376 |
-
|
| 377 |
-
<div className="flex flex-wrap gap-4 text-sm text-[var(--text)]/80 items-center">
|
| 378 |
-
<select
|
| 379 |
-
value={theme}
|
| 380 |
-
onChange={(e) => {
|
| 381 |
-
setTheme(e.target.value);
|
| 382 |
-
applyTheme(e.target.value);
|
| 383 |
-
}}
|
| 384 |
-
className="bg-card border border-accent rounded px-3 py-2 text-accent"
|
| 385 |
-
>
|
| 386 |
-
<option>Cyber Blue</option>
|
| 387 |
-
<option>Crimson Dark</option>
|
| 388 |
-
<option>Emerald Matrix</option>
|
| 389 |
-
<option>Default</option>
|
| 390 |
-
</select>
|
| 391 |
-
<span className="text-xs text-[var(--text)]/50 italic">
|
| 392 |
-
Instantly applies across all pages
|
| 393 |
-
</span>
|
| 394 |
-
</div>
|
| 395 |
-
</div>
|
| 396 |
-
|
| 397 |
-
{/* 🧠 AI BEHAVIOR */}
|
| 398 |
-
<div className="card-glow rounded-xl p-5 relative z-10">
|
| 399 |
-
<h3 className="text-accent text-sm mb-3 flex items-center gap-2">
|
| 400 |
-
<Brain size={14} /> AI Behavior Settings
|
| 401 |
-
</h3>
|
| 402 |
-
<div className="space-y-4 text-sm text-[var(--text)]/80">
|
| 403 |
-
<div>
|
| 404 |
-
<p className="mb-2">AI Sensitivity: {aiSensitivity}%</p>
|
| 405 |
-
<input
|
| 406 |
-
type="range"
|
| 407 |
-
min="30"
|
| 408 |
-
max="100"
|
| 409 |
-
value={aiSensitivity}
|
| 410 |
-
onChange={(e) => setAiSensitivity(Number(e.target.value))}
|
| 411 |
-
className="w-full accent-[var(--accent)] cursor-pointer"
|
| 412 |
-
/>
|
| 413 |
</div>
|
| 414 |
<div>
|
| 415 |
-
<
|
| 416 |
-
<
|
| 417 |
-
value={responseMode}
|
| 418 |
-
onChange={(e) => setResponseMode(e.target.value)}
|
| 419 |
-
className="bg-card border border-accent rounded px-2 py-1 text-accent"
|
| 420 |
-
>
|
| 421 |
-
<option>Passive</option>
|
| 422 |
-
<option>Semi-Auto</option>
|
| 423 |
-
<option>Fully Auto</option>
|
| 424 |
-
</select>
|
| 425 |
</div>
|
| 426 |
</div>
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
<div className="card-glow rounded-xl p-5 relative z-10">
|
| 431 |
-
<h3 className="text-accent text-sm mb-3 flex items-center gap-2">
|
| 432 |
-
<Wifi size={14} /> Network Configuration
|
| 433 |
-
</h3>
|
| 434 |
-
<div className="grid md:grid-cols-2 gap-4 text-sm text-[var(--text)]/80">
|
| 435 |
-
<div>
|
| 436 |
-
<p>Server IP</p>
|
| 437 |
-
<input
|
| 438 |
-
type="text"
|
| 439 |
-
value={ipConfig}
|
| 440 |
-
onChange={(e) => setIpConfig(e.target.value)}
|
| 441 |
-
className="w-full bg-card border border-accent rounded px-2 py-1 text-accent"
|
| 442 |
-
/>
|
| 443 |
-
</div>
|
| 444 |
-
<div>
|
| 445 |
-
<p>Server Port</p>
|
| 446 |
-
<input
|
| 447 |
-
type="text"
|
| 448 |
-
value={portConfig}
|
| 449 |
-
onChange={(e) => setPortConfig(e.target.value)}
|
| 450 |
-
className="w-full bg-card border border-accent rounded px-2 py-1 text-accent"
|
| 451 |
-
/>
|
| 452 |
-
</div>
|
| 453 |
-
</div>
|
| 454 |
-
<button
|
| 455 |
-
onClick={() =>
|
| 456 |
-
toast.success("✅ Network settings saved (local)!")
|
| 457 |
-
}
|
| 458 |
-
className="mt-4 px-4 py-2 bg-accent/20 border border-accent text-accent rounded-lg hover:bg-accent/30 transition flex items-center gap-2"
|
| 459 |
-
>
|
| 460 |
-
<Save size={14} /> Save Configuration
|
| 461 |
-
</button>
|
| 462 |
-
</div>
|
| 463 |
-
|
| 464 |
-
{/* 🛡️ THREAT RULE MANAGER */}
|
| 465 |
-
<div className="card-glow rounded-xl p-5 relative z-10">
|
| 466 |
-
<h3 className="text-accent text-sm mb-3 flex items-center gap-2">
|
| 467 |
-
<ShieldAlert size={14} /> Threat Rule Manager
|
| 468 |
-
</h3>
|
| 469 |
-
|
| 470 |
-
{/* Dataset switch */}
|
| 471 |
-
<div className="flex flex-wrap gap-3 mb-4 text-xs text-[var(--text)]/80">
|
| 472 |
-
<button
|
| 473 |
-
className={`px-3 py-1.5 rounded-full border ${
|
| 474 |
-
activeThreatDataset === "CICIDS2018"
|
| 475 |
-
? "border-accent bg-accent/20 text-accent"
|
| 476 |
-
: "border-slate-500/40 hover:border-accent/50"
|
| 477 |
-
}`}
|
| 478 |
-
onClick={() => setActiveThreatDataset("CICIDS2018")}
|
| 479 |
-
>
|
| 480 |
-
CICIDS 2018 Rules
|
| 481 |
</button>
|
| 482 |
-
<button
|
| 483 |
-
className={`px-3 py-1.5 rounded-full border ${
|
| 484 |
-
activeThreatDataset === "BCC"
|
| 485 |
-
? "border-accent bg-accent/20 text-accent"
|
| 486 |
-
: "border-slate-500/40 hover:border-accent/50"
|
| 487 |
-
}`}
|
| 488 |
-
onClick={() => setActiveThreatDataset("BCC")}
|
| 489 |
-
>
|
| 490 |
-
BCC Rules
|
| 491 |
-
</button>
|
| 492 |
-
<span className="text-[11px] text-[var(--text)]/50 italic">
|
| 493 |
-
Toggle which classes should trigger alerts for the active
|
| 494 |
-
model.
|
| 495 |
-
</span>
|
| 496 |
-
</div>
|
| 497 |
-
|
| 498 |
-
{/* Rules */}
|
| 499 |
-
<div className="grid md:grid-cols-3 gap-3 text-sm text-[var(--text)]/85">
|
| 500 |
-
{Object.keys(currentThreatRules).map((ruleKey) => (
|
| 501 |
-
<button
|
| 502 |
-
key={ruleKey}
|
| 503 |
-
onClick={() =>
|
| 504 |
-
handleToggleRule(currentThreatKey, ruleKey)
|
| 505 |
-
}
|
| 506 |
-
className={`flex items-center justify-between px-3 py-2 rounded-lg border text-xs ${
|
| 507 |
-
currentThreatRules[ruleKey]
|
| 508 |
-
? "border-accent bg-accent/15 text-accent"
|
| 509 |
-
: "border-slate-600/60 bg-card/40 hover:border-accent/50"
|
| 510 |
-
}`}
|
| 511 |
-
>
|
| 512 |
-
<span className="truncate mr-2">{ruleKey}</span>
|
| 513 |
-
{currentThreatRules[ruleKey] ? (
|
| 514 |
-
<ToggleRight size={16} />
|
| 515 |
-
) : (
|
| 516 |
-
<ToggleLeft size={16} />
|
| 517 |
-
)}
|
| 518 |
-
</button>
|
| 519 |
-
))}
|
| 520 |
</div>
|
| 521 |
</div>
|
| 522 |
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
<
|
| 530 |
-
<
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
|
| 539 |
-
|
| 540 |
-
>
|
| 541 |
-
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
<
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
|
| 552 |
-
|
| 553 |
-
|
| 554 |
-
|
| 555 |
-
|
| 556 |
-
|
| 557 |
-
|
| 558 |
-
|
| 559 |
-
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
|
| 563 |
-
|
| 564 |
-
|
| 565 |
-
<
|
| 566 |
-
<
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
| 578 |
-
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
|
| 593 |
-
<
|
| 594 |
-
</
|
| 595 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 596 |
</div>
|
| 597 |
-
</div>
|
| 598 |
-
|
| 599 |
-
{/* 🔔 NOTIFICATION SETTINGS */}
|
| 600 |
-
<div className="card-glow rounded-xl p-5 relative z-10">
|
| 601 |
-
<h3 className="text-accent text-sm mb-3 flex items-center gap-2">
|
| 602 |
-
<Bell size={14} /> Notification Settings
|
| 603 |
-
</h3>
|
| 604 |
-
<div className="space-y-4 text-sm text-[var(--text)]/80">
|
| 605 |
-
<div
|
| 606 |
-
className="flex items-center gap-3 cursor-pointer hover:text-accent"
|
| 607 |
-
onClick={() =>
|
| 608 |
-
setNotificationSettings((prev) => ({
|
| 609 |
-
...prev,
|
| 610 |
-
enablePopup: !prev.enablePopup,
|
| 611 |
-
}))
|
| 612 |
-
}
|
| 613 |
-
>
|
| 614 |
-
{notificationSettings.enablePopup ? (
|
| 615 |
-
<ToggleRight size={20} />
|
| 616 |
-
) : (
|
| 617 |
-
<ToggleLeft size={20} />
|
| 618 |
-
)}
|
| 619 |
-
Enable In-App Popup Alerts
|
| 620 |
-
</div>
|
| 621 |
|
| 622 |
-
|
| 623 |
-
|
| 624 |
-
|
| 625 |
-
|
| 626 |
-
|
| 627 |
-
|
| 628 |
-
}
|
| 629 |
-
|
| 630 |
-
|
| 631 |
-
|
| 632 |
-
|
| 633 |
-
|
| 634 |
-
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
|
| 638 |
-
|
| 639 |
-
|
| 640 |
-
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
| 655 |
-
|
| 656 |
-
|
| 657 |
-
|
| 658 |
-
|
| 659 |
-
|
| 660 |
-
|
| 661 |
-
|
| 662 |
-
|
| 663 |
-
|
| 664 |
-
|
| 665 |
-
|
| 666 |
-
|
| 667 |
-
|
| 668 |
-
|
| 669 |
-
|
| 670 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 671 |
|
| 672 |
-
|
| 673 |
-
|
| 674 |
-
|
| 675 |
-
|
| 676 |
-
</h3>
|
| 677 |
-
<div className="space-y-4 text-sm text-[var(--text)]/80">
|
| 678 |
-
{/* Dataset selection */}
|
| 679 |
-
<div className="flex flex-wrap gap-3 items-center">
|
| 680 |
-
<span className="text-xs uppercase tracking-[0.15em] text-[var(--text)]/60">
|
| 681 |
-
Active Dataset:
|
| 682 |
-
</span>
|
| 683 |
-
<button
|
| 684 |
-
className={`px-3 py-1.5 rounded-full border ${
|
| 685 |
-
modelConfig.activeDataset === "CICIDS2018"
|
| 686 |
-
? "border-accent bg-accent/20 text-accent"
|
| 687 |
-
: "border-slate-500/40 hover:border-accent/50"
|
| 688 |
-
}`}
|
| 689 |
-
onClick={() =>
|
| 690 |
-
setModelConfig((prev) => ({
|
| 691 |
-
...prev,
|
| 692 |
-
activeDataset: "CICIDS2018",
|
| 693 |
-
activeModelName: "CICIDS2018_Default",
|
| 694 |
-
}))
|
| 695 |
-
}
|
| 696 |
-
>
|
| 697 |
-
CICIDS 2018
|
| 698 |
-
</button>
|
| 699 |
-
<button
|
| 700 |
-
className={`px-3 py-1.5 rounded-full border ${
|
| 701 |
-
modelConfig.activeDataset === "BCC"
|
| 702 |
-
? "border-accent bg-accent/20 text-accent"
|
| 703 |
-
: "border-slate-500/40 hover:border-accent/50"
|
| 704 |
-
}`}
|
| 705 |
-
onClick={() =>
|
| 706 |
-
setModelConfig((prev) => ({
|
| 707 |
-
...prev,
|
| 708 |
-
activeDataset: "BCC",
|
| 709 |
-
activeModelName: "BCC_Default",
|
| 710 |
-
}))
|
| 711 |
-
}
|
| 712 |
-
>
|
| 713 |
-
BCC
|
| 714 |
</button>
|
| 715 |
-
|
| 716 |
-
|
| 717 |
-
{/* Upload Model */}
|
| 718 |
-
<div className="grid md:grid-cols-[2fr_auto] gap-3 items-center">
|
| 719 |
-
<div>
|
| 720 |
-
<p className="mb-1 flex items-center gap-2">
|
| 721 |
-
<UploadCloud size={14} /> Upload Custom Model (.pkl/.joblib)
|
| 722 |
-
</p>
|
| 723 |
-
<input
|
| 724 |
-
type="file"
|
| 725 |
-
accept=".pkl,.joblib,.onnx"
|
| 726 |
-
onChange={(e) => setModelFile(e.target.files[0] || null)}
|
| 727 |
-
className="w-full text-xs text-[var(--text)]/70 bg-card border border-accent/40 rounded px-2 py-1 file:mr-3 file:px-2 file:py-1 file:text-xs file:rounded file:bg-accent/20 file:border-none file:text-accent"
|
| 728 |
-
/>
|
| 729 |
-
</div>
|
| 730 |
-
<button
|
| 731 |
-
onClick={handleModelUpload}
|
| 732 |
-
className="h-[38px] px-4 py-2 bg-accent/20 border border-accent text-accent rounded-lg hover:bg-accent/30 transition flex items-center gap-2 justify-center"
|
| 733 |
-
>
|
| 734 |
-
<Brain size={14} /> Register Model
|
| 735 |
</button>
|
| 736 |
</div>
|
| 737 |
|
| 738 |
-
<div className="text-xs text-[var(--text)]/60">
|
| 739 |
-
<p>Active model: {modelConfig.activeModelName}</p>
|
| 740 |
-
{modelConfig.customModelName && (
|
| 741 |
-
<p>
|
| 742 |
-
Custom model:{" "}
|
| 743 |
-
<span className="text-accent">
|
| 744 |
-
{modelConfig.customModelName}
|
| 745 |
-
</span>{" "}
|
| 746 |
-
{modelConfig.lastUpdated && (
|
| 747 |
-
<span>
|
| 748 |
-
(updated{" "}
|
| 749 |
-
{new Date(
|
| 750 |
-
modelConfig.lastUpdated
|
| 751 |
-
).toLocaleString()}
|
| 752 |
-
)
|
| 753 |
-
</span>
|
| 754 |
-
)}
|
| 755 |
-
</p>
|
| 756 |
-
)}
|
| 757 |
-
</div>
|
| 758 |
-
</div>
|
| 759 |
-
</div>
|
| 760 |
-
|
| 761 |
-
{/* 👥 USER & ACCESS OVERVIEW (UI-ONLY) */}
|
| 762 |
-
<div className="card-glow rounded-xl p-5 relative z-10">
|
| 763 |
-
<h3 className="text-accent text-sm mb-3 flex items-center gap-2">
|
| 764 |
-
<Users size={14} /> User & Access Overview
|
| 765 |
-
</h3>
|
| 766 |
-
<div className="text-sm text-[var(--text)]/80 space-y-2">
|
| 767 |
-
<div className="flex justify-between border-b border-slate-600/40 pb-1 text-xs text-[var(--text)]/60 uppercase tracking-[0.12em]">
|
| 768 |
-
<span>User</span>
|
| 769 |
-
<span>Role</span>
|
| 770 |
-
</div>
|
| 771 |
-
<div className="flex justify-between items-center">
|
| 772 |
-
<span>{user?.displayName || "Current Operator"}</span>
|
| 773 |
-
<span className="text-accent text-xs px-2 py-1 rounded-full border border-accent/50">
|
| 774 |
-
Operator
|
| 775 |
-
</span>
|
| 776 |
-
</div>
|
| 777 |
-
<p className="text-[11px] text-[var(--text)]/50 mt-2 italic">
|
| 778 |
-
Role-based access can be integrated with your auth provider
|
| 779 |
-
in a future enhancement.
|
| 780 |
-
</p>
|
| 781 |
</div>
|
| 782 |
</div>
|
| 783 |
-
|
| 784 |
-
{/* Backup & Reset */}
|
| 785 |
-
<div className="card-glow rounded-xl p-5 relative z-10">
|
| 786 |
-
<h3 className="text-accent text-sm mb-3 flex items-center gap-2">
|
| 787 |
-
<FileDown size={14} /> Backup & Reset
|
| 788 |
-
</h3>
|
| 789 |
-
<div className="flex flex-wrap gap-4 items-center text-sm text-[var(--text)]/80">
|
| 790 |
-
<button
|
| 791 |
-
onClick={handleBackup}
|
| 792 |
-
className="px-4 py-2 bg-[var(--accent)]/20 border border-[var(--accent)] text-[var(--accent)] rounded-lg hover:bg-[var(--accent)]/30 transition flex items-center gap-2"
|
| 793 |
-
>
|
| 794 |
-
<FileDown size={14} /> Backup Settings
|
| 795 |
-
</button>
|
| 796 |
-
<button
|
| 797 |
-
onClick={handleReset}
|
| 798 |
-
className="px-4 py-2 bg-rose-600/20 border border-rose-400/30 text-rose-300 rounded-lg hover:bg-rose-600/30 transition flex items-center gap-2"
|
| 799 |
-
>
|
| 800 |
-
<RefreshCcw size={14} /> Reset to Default
|
| 801 |
-
</button>
|
| 802 |
-
</div>
|
| 803 |
-
{backupProgress > 0 && backupProgress < 100 && (
|
| 804 |
-
<div className="mt-3 w-full bg-[var(--accent)]/10 h-2 rounded-full overflow-hidden">
|
| 805 |
-
<div
|
| 806 |
-
className="bg-[var(--accent)] h-2 animate-pulse"
|
| 807 |
-
style={{ width: `${backupProgress}%` }}
|
| 808 |
-
></div>
|
| 809 |
-
</div>
|
| 810 |
-
)}
|
| 811 |
-
</div>
|
| 812 |
</div>
|
| 813 |
);
|
| 814 |
-
}
|
|
|
|
| 1 |
+
import React, { useState, useEffect, useRef } from "react";
|
|
|
|
| 2 |
import {
|
| 3 |
+
Settings, ToggleLeft, ToggleRight, Wifi, Save, RefreshCcw, Brain, Zap,
|
| 4 |
+
FileDown, Palette, Bell, Sliders, ShieldAlert, HardDrive, UploadCloud, Users,
|
| 5 |
+
Activity, Database, ShieldCheck, Globe, Lock, History, Server, Cpu, Layers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
} from "lucide-react";
|
| 7 |
import toast, { Toaster } from "react-hot-toast";
|
| 8 |
import { useAuth } from "../context/AuthContext";
|
| 9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
export default function SettingsPage() {
|
| 11 |
const { settings, setSettings, saveSettings, user } = useAuth();
|
| 12 |
+
|
| 13 |
+
// Logic State
|
| 14 |
+
const [theme, setTheme] = useState(settings?.theme ?? "Cyber Blue");
|
| 15 |
+
const [autoRefresh, setAutoRefresh] = useState(settings?.autoRefresh ?? true);
|
| 16 |
+
const [soundAlerts, setSoundAlerts] = useState(settings?.soundAlerts ?? true);
|
| 17 |
+
const [aiSensitivity, setAiSensitivity] = useState(settings?.aiSensitivity ?? 70);
|
| 18 |
+
const [responseMode, setResponseMode] = useState(settings?.responseMode ?? "Semi-Auto");
|
| 19 |
+
const [encryptionLevel, setEncryptionLevel] = useState("AES-256");
|
| 20 |
+
const [proxyEnabled, setProxyEnabled] = useState(false);
|
| 21 |
+
const [retentionDays, setRetentionDays] = useState(30);
|
| 22 |
+
const [activeThreatDataset, setActiveThreatDataset] = useState("CICIDS2018");
|
| 23 |
+
|
| 24 |
+
const fileInputRef = useRef(null);
|
| 25 |
+
|
| 26 |
+
const applyTheme = (t) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
const body = document.body;
|
| 28 |
+
body.classList.remove("theme-cyber", "theme-crimson", "theme-emerald", "theme-default");
|
| 29 |
+
const themeMap = { "Cyber Blue": "theme-cyber", "Crimson Dark": "theme-crimson", "Emerald Matrix": "theme-emerald", "Default": "theme-default" };
|
| 30 |
+
body.classList.add(themeMap[t] || "theme-default");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
};
|
| 32 |
|
|
|
|
| 33 |
const handleSave = async () => {
|
| 34 |
+
const newSettings = { ...settings, theme, autoRefresh, aiSensitivity, responseMode };
|
| 35 |
+
await saveSettings(newSettings);
|
| 36 |
+
toast.success("All systems synchronized successfully.");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
};
|
| 38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
return (
|
| 40 |
+
<div className="min-h-screen p-4 lg:p-8 space-y-6 max-w-7xl mx-auto pb-24 relative z-10 bg-transparent">
|
| 41 |
<Toaster position="bottom-right" />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
+
{/* --- TOP BAR / OVERVIEW --- */}
|
| 44 |
+
<div className="glass-shell p-6 flex flex-col md:flex-row justify-between items-center gap-4 border-accent/20">
|
| 45 |
+
<div className="flex items-center gap-4">
|
| 46 |
+
<div className="p-3 bg-accent/10 rounded-2xl border border-accent/20">
|
| 47 |
+
<Settings className="animate-spin-slow text-accent" size={32} />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
</div>
|
| 49 |
<div>
|
| 50 |
+
<h1 className="text-2xl font-black text-accent tracking-tighter uppercase">Command Center</h1>
|
| 51 |
+
<p className="text-[10px] font-mono opacity-50 uppercase tracking-widest">User: {user?.displayName || "Operator_01"} // Auth: Level_Alpha</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
</div>
|
| 53 |
</div>
|
| 54 |
+
<div className="flex items-center gap-3">
|
| 55 |
+
<button onClick={handleSave} className="px-8 py-3 bg-accent text-black font-black uppercase text-xs rounded-xl hover:shadow-[0_0_25px_rgba(0,229,255,0.4)] transition-all flex items-center gap-2">
|
| 56 |
+
<Save size={16} /> Save Changes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
</div>
|
| 59 |
</div>
|
| 60 |
|
| 61 |
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
| 62 |
+
|
| 63 |
+
{/* --- LEFT COLUMN: SYSTEM & SECURITY --- */}
|
| 64 |
+
<div className="space-y-6">
|
| 65 |
+
|
| 66 |
+
{/* THEME & VISUALS */}
|
| 67 |
+
<section className="card-glow p-6">
|
| 68 |
+
<h3 className="text-accent text-[10px] font-black uppercase tracking-[0.2em] mb-6 flex items-center gap-2">
|
| 69 |
+
<Palette size={14} /> Interface Skins
|
| 70 |
+
</h3>
|
| 71 |
+
<div className="grid grid-cols-2 gap-3">
|
| 72 |
+
{["Cyber Blue", "Crimson Dark", "Emerald Matrix", "Default"].map((t) => (
|
| 73 |
+
<button key={t} onClick={() => { setTheme(t); applyTheme(t); }}
|
| 74 |
+
className={`py-3 text-[10px] font-bold uppercase rounded-xl border transition-all ${theme === t ? 'border-accent bg-accent/20 text-accent shadow-[0_0_15px_rgba(0,229,255,0.1)]' : 'border-white/5 bg-white/5 opacity-40 hover:opacity-100'}`}>
|
| 75 |
+
{t}
|
| 76 |
+
</button>
|
| 77 |
+
))}
|
| 78 |
+
</div>
|
| 79 |
+
</section>
|
| 80 |
+
|
| 81 |
+
{/* CORE PERFORMANCE */}
|
| 82 |
+
<section className="card-glow p-6">
|
| 83 |
+
<h3 className="text-accent text-[10px] font-black uppercase tracking-[0.2em] mb-6 flex items-center gap-2">
|
| 84 |
+
<Zap size={14} /> Global System Prefs
|
| 85 |
+
</h3>
|
| 86 |
+
<div className="space-y-3">
|
| 87 |
+
<div className="flex items-center justify-between p-4 bg-white/2 rounded-xl border border-white/5">
|
| 88 |
+
<span className="text-xs font-bold opacity-70">Real-Time Data Streaming</span>
|
| 89 |
+
<button onClick={() => setAutoRefresh(!autoRefresh)} className="text-accent">
|
| 90 |
+
{autoRefresh ? <ToggleRight size={32} /> : <ToggleLeft size={32} className="opacity-20" />}
|
| 91 |
+
</button>
|
| 92 |
+
</div>
|
| 93 |
+
<div className="flex items-center justify-between p-4 bg-white/2 rounded-xl border border-white/5">
|
| 94 |
+
<span className="text-xs font-bold opacity-70">Auditory Alert Feedback</span>
|
| 95 |
+
<button onClick={() => setSoundAlerts(!soundAlerts)} className="text-accent">
|
| 96 |
+
{soundAlerts ? <ToggleRight size={32} /> : <ToggleLeft size={32} className="opacity-20" />}
|
| 97 |
+
</button>
|
| 98 |
+
</div>
|
| 99 |
+
</div>
|
| 100 |
+
</section>
|
| 101 |
+
|
| 102 |
+
{/* SECURITY & PRIVACY */}
|
| 103 |
+
<section className="card-glow p-6">
|
| 104 |
+
<h3 className="text-accent text-[10px] font-black uppercase tracking-[0.2em] mb-6 flex items-center gap-2">
|
| 105 |
+
<Lock size={14} /> Advanced Security
|
| 106 |
+
</h3>
|
| 107 |
+
<div className="space-y-4">
|
| 108 |
+
<div className="p-3 bg-black/40 rounded-xl border border-white/5">
|
| 109 |
+
<p className="text-[9px] uppercase opacity-40 mb-2">Encryption Algorithm</p>
|
| 110 |
+
<select value={encryptionLevel} onChange={(e) => setEncryptionLevel(e.target.value)}
|
| 111 |
+
className="bg-transparent text-xs font-bold text-accent outline-none w-full appearance-none">
|
| 112 |
+
<option value="AES-256">AES-256-GCM (Hardware Accelerated)</option>
|
| 113 |
+
<option value="ChaCha20">ChaCha20-Poly1305</option>
|
| 114 |
+
</select>
|
| 115 |
+
</div>
|
| 116 |
+
<div className="flex items-center justify-between p-3 bg-white/2 rounded-xl border border-white/5">
|
| 117 |
+
<div className="flex flex-col">
|
| 118 |
+
<span className="text-xs font-bold uppercase">Network Stealth Proxy</span>
|
| 119 |
+
<span className="text-[8px] opacity-40 font-mono">Routing through {proxyEnabled ? "Active Nodes" : "Direct Link"}</span>
|
| 120 |
+
</div>
|
| 121 |
+
<button onClick={() => setProxyEnabled(!proxyEnabled)} className="text-accent">
|
| 122 |
+
{proxyEnabled ? <ToggleRight size={28} /> : <ToggleLeft size={28} className="opacity-20" />}
|
| 123 |
+
</button>
|
| 124 |
+
</div>
|
| 125 |
+
</div>
|
| 126 |
+
</section>
|
| 127 |
+
|
| 128 |
+
{/* HARDWARE TELEMETRY */}
|
| 129 |
+
<section className="card-glow p-6">
|
| 130 |
+
<h3 className="text-accent text-[10px] font-black uppercase tracking-[0.2em] mb-6 flex items-center gap-2">
|
| 131 |
+
<Cpu size={14} /> Hardware Resources
|
| 132 |
+
</h3>
|
| 133 |
+
<div className="space-y-4 font-mono text-[10px]">
|
| 134 |
+
<div className="flex justify-between">
|
| 135 |
+
<span className="opacity-50 uppercase">Processor Load</span>
|
| 136 |
+
<span className="text-emerald-400">12.4% / Normal</span>
|
| 137 |
+
</div>
|
| 138 |
+
<div className="w-full bg-black/50 h-1.5 rounded-full overflow-hidden">
|
| 139 |
+
<div className="bg-emerald-400 h-full w-[12%] shadow-[0_0_10px_#34d399]"></div>
|
| 140 |
+
</div>
|
| 141 |
+
<div className="flex justify-between">
|
| 142 |
+
<span className="opacity-50 uppercase">Neural Cache (8GB)</span>
|
| 143 |
+
<span className="text-accent">2.1 GB Static</span>
|
| 144 |
+
</div>
|
| 145 |
+
<div className="w-full bg-black/50 h-1.5 rounded-full overflow-hidden">
|
| 146 |
+
<div className="bg-accent h-full w-[26%] shadow-[0_0_10px_var(--accent)]"></div>
|
| 147 |
+
</div>
|
| 148 |
+
</div>
|
| 149 |
+
</section>
|
| 150 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
|
| 152 |
+
{/* --- RIGHT COLUMN: AI, DATA & LOGS --- */}
|
| 153 |
+
<div className="space-y-6">
|
| 154 |
+
|
| 155 |
+
{/* AI NEURAL PARAMS */}
|
| 156 |
+
<section className="card-glow p-6">
|
| 157 |
+
<h3 className="text-accent text-[10px] font-black uppercase tracking-[0.2em] mb-6 flex items-center gap-2">
|
| 158 |
+
<Brain size={14} /> AI Inference Engine
|
| 159 |
+
</h3>
|
| 160 |
+
<div className="space-y-4">
|
| 161 |
+
<div className="flex justify-between text-xs font-bold uppercase">
|
| 162 |
+
<span>Threat Sensitivity</span>
|
| 163 |
+
<span className="text-accent">{aiSensitivity}%</span>
|
| 164 |
+
</div>
|
| 165 |
+
<input type="range" min="30" max="100" value={aiSensitivity} onChange={(e) => setAiSensitivity(Number(e.target.value))}
|
| 166 |
+
className="w-full h-1.5 bg-black/60 rounded-lg appearance-none cursor-pointer accent-accent" />
|
| 167 |
+
<div className="grid grid-cols-3 gap-2">
|
| 168 |
+
{["Passive", "Semi-Auto", "Fully Auto"].map(mode => (
|
| 169 |
+
<button key={mode} onClick={() => setResponseMode(mode)}
|
| 170 |
+
className={`py-2 text-[9px] font-black uppercase rounded-lg border transition-all ${responseMode === mode ? 'bg-accent/20 border-accent text-accent' : 'border-white/5 opacity-30 hover:opacity-100'}`}>
|
| 171 |
+
{mode}
|
| 172 |
+
</button>
|
| 173 |
+
))}
|
| 174 |
+
</div>
|
| 175 |
+
</div>
|
| 176 |
+
</section>
|
| 177 |
+
|
| 178 |
+
{/* MODEL & DATASET MANAGEMENT */}
|
| 179 |
+
<section className="card-glow p-6">
|
| 180 |
+
<h3 className="text-accent text-[10px] font-black uppercase tracking-[0.2em] mb-6 flex items-center gap-2">
|
| 181 |
+
<Database size={14} /> Model Architecture
|
| 182 |
+
</h3>
|
| 183 |
+
<div className="space-y-4">
|
| 184 |
+
<div className="grid grid-cols-2 gap-3">
|
| 185 |
+
<div className="p-3 bg-black/40 rounded-xl border border-white/5">
|
| 186 |
+
<p className="text-[9px] uppercase opacity-40 mb-1">Active Dataset</p>
|
| 187 |
+
<select value={activeThreatDataset} onChange={(e) => setActiveThreatDataset(e.target.value)}
|
| 188 |
+
className="bg-transparent text-xs font-bold text-accent outline-none w-full">
|
| 189 |
+
<option value="CICIDS2018">CICIDS 2018</option>
|
| 190 |
+
<option value="BCC">BCC Traffic</option>
|
| 191 |
+
</select>
|
| 192 |
+
</div>
|
| 193 |
+
<div className="p-3 bg-black/40 rounded-xl border border-white/5">
|
| 194 |
+
<p className="text-[9px] uppercase opacity-40 mb-1">Model Version</p>
|
| 195 |
+
<p className="text-xs font-bold">RF_XENON_v4.2</p>
|
| 196 |
+
</div>
|
| 197 |
+
</div>
|
| 198 |
+
<div onClick={() => fileInputRef.current.click()} className="border-2 border-dashed border-accent/20 rounded-2xl p-6 flex flex-col items-center gap-2 hover:bg-accent/5 cursor-pointer transition-all">
|
| 199 |
+
<input type="file" ref={fileInputRef} className="hidden" />
|
| 200 |
+
<UploadCloud className="text-accent opacity-50" />
|
| 201 |
+
<span className="text-[10px] font-black uppercase">Inject Custom Weights</span>
|
| 202 |
+
</div>
|
| 203 |
+
</div>
|
| 204 |
+
</section>
|
| 205 |
+
|
| 206 |
+
{/* AUDIT TRAIL */}
|
| 207 |
+
<section className="card-glow p-6">
|
| 208 |
+
<h3 className="text-accent text-[10px] font-black uppercase tracking-[0.2em] mb-6 flex items-center gap-2">
|
| 209 |
+
<History size={14} /> System Audit Trail
|
| 210 |
+
</h3>
|
| 211 |
+
<div className="space-y-2 max-h-[140px] overflow-y-auto pr-2 custom-scroll">
|
| 212 |
+
{[
|
| 213 |
+
{ t: '12:04', m: 'Firewall: Blocked IP 192.168.1.5' },
|
| 214 |
+
{ t: '11:58', m: 'Model: Weights updated from cloud' },
|
| 215 |
+
{ t: '11:42', m: 'Admin: Session authorized' },
|
| 216 |
+
{ t: '10:15', m: 'System: Integrity check pass' },
|
| 217 |
+
].map((log, i) => (
|
| 218 |
+
<div key={i} className="flex gap-3 text-[9px] font-mono border-b border-white/5 pb-2">
|
| 219 |
+
<span className="text-accent">[{log.t}]</span>
|
| 220 |
+
<span className="opacity-60 uppercase">{log.m}</span>
|
| 221 |
+
</div>
|
| 222 |
+
))}
|
| 223 |
+
</div>
|
| 224 |
+
</section>
|
| 225 |
|
| 226 |
+
{/* DANGER ZONE */}
|
| 227 |
+
<div className="grid grid-cols-2 gap-4">
|
| 228 |
+
<button className="py-4 border border-accent/30 bg-accent/5 text-accent rounded-2xl text-[10px] font-black uppercase tracking-widest hover:bg-accent/10 transition-all flex flex-col items-center gap-2">
|
| 229 |
+
<FileDown size={20} /> Export Sync
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
</button>
|
| 231 |
+
<button className="py-4 border border-rose-500/30 bg-rose-500/5 text-rose-500 rounded-2xl text-[10px] font-black uppercase tracking-widest hover:bg-rose-500/10 transition-all flex flex-col items-center gap-2">
|
| 232 |
+
<RefreshCcw size={20} /> Purge Node
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
</button>
|
| 234 |
</div>
|
| 235 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
</div>
|
| 237 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
</div>
|
| 239 |
);
|
| 240 |
+
}
|