import React, { useEffect, useState } from "react"; import './App.css'; function App() { const [computers, setComputers] = useState([]); const [filteredComputers, setFilteredComputers] = useState([]); const [stats, setStats] = useState(null); const [selectedComputer, setSelectedComputer] = useState(null); const [computerDetails, setComputerDetails] = useState(null); const [loadingDetails, setLoadingDetails] = useState(false); const [performanceData, setPerformanceData] = useState([]); const [eventDistribution, setEventDistribution] = useState([]); const [networkTraffic, setNetworkTraffic] = useState([]); const [topProcesses, setTopProcesses] = useState([]); // Бои за графикони const CHART_COLORS = { primary: '#2563eb', secondary: '#7c3aed', accentGreen: '#10b981', accentOrange: '#f59e0b', accentRed: '#ef4444', lightBlue: '#93c5fd', lightPurple: '#c4b5fd' }; // Функција за вчитување на податоци за графикони const loadChartData = () => { // Перформанс податоци (симулирани, треба да ги земеш од API) const mockPerfData = Array.from({ length: 24 }, (_, i) => ({ hour: `${i}:00`, cpu: 20 + Math.random() * 30, memory: 30 + Math.random() * 40, network: Math.random() * 100 })); setPerformanceData(mockPerfData); // Дистрибуција на настани const mockEventDist = [ { name: 'Process Create', value: 45, color: CHART_COLORS.primary }, { name: 'Network', value: 25, color: CHART_COLORS.secondary }, { name: 'File Create', value: 15, color: CHART_COLORS.accentGreen }, { name: 'Registry', value: 10, color: CHART_COLORS.accentOrange }, { name: 'Other', value: 5, color: CHART_COLORS.accentRed } ]; setEventDistribution(mockEventDist); // Мрежен сообраќај const mockNetworkData = Array.from({ length: 12 }, (_, i) => ({ time: `${i * 2}:00`, inbound: 50 + Math.random() * 200, outbound: 30 + Math.random() * 150 })); setNetworkTraffic(mockNetworkData); // Топ процеси const mockTopProcesses = [ { name: 'chrome.exe', cpu: 25, memory: 1200 }, { name: 'python.exe', cpu: 18, memory: 800 }, { name: 'explorer.exe', cpu: 12, memory: 300 }, { name: 'svchost.exe', cpu: 8, memory: 200 }, { name: 'node.exe', cpu: 6, memory: 500 } ]; setTopProcesses(mockTopProcesses); }; useEffect(() => { loadChartData(); // Автоматско освежување на графикони const chartInterval = setInterval(loadChartData, 30000); return () => clearInterval(chartInterval); }, []); // Filter state const [filters, setFilters] = useState({ status: "all", search: "", os: "all", minCpu: 0, minRam: 0 }); // AI chat state const [chatQuestion, setChatQuestion] = useState(""); const [chatAnswer, setChatAnswer] = useState(""); const [chatLoading, setChatLoading] = useState(false); const [chatComputer, setChatComputer] = useState(""); const [chatHistory, setChatHistory] = useState([]); const [isChatOpen, setIsChatOpen] = useState(true); const [showWelcome, setShowWelcome] = useState(true); // Modal tabs state const [activeTab, setActiveTab] = useState('security'); const [sysmonData, setSysmonData] = useState(null); const [networkData, setNetworkData] = useState(null); const [loadingSysmon, setLoadingSysmon] = useState(false); const [loadingNetwork, setLoadingNetwork] = useState(false); const [selectedSysmonProcess, setSelectedSysmonProcess] = useState(null); const [selectedNetworkItem, setSelectedNetworkItem] = useState(null); // Load main data useEffect(() => { loadComputers(); loadStats(); const interval = setInterval(() => { loadComputers(); loadStats(); }, 30000); return () => clearInterval(interval); }, []); // Apply filters useEffect(() => { let result = computers; if (filters.status !== "all") { result = result.filter(c => c.status === filters.status); } if (filters.os !== "all") { result = result.filter(c => c.os && c.os.toLowerCase().includes(filters.os.toLowerCase())); } if (filters.minCpu > 0) { result = result.filter(c => (c.avg_cpu || 0) >= filters.minCpu); } if (filters.minRam > 0) { result = result.filter(c => (c.avg_ram || 0) >= filters.minRam); } if (filters.search.trim()) { const searchTerm = filters.search.toLowerCase(); result = result.filter(c => c.name.toLowerCase().includes(searchTerm) || (c.user && c.user.toLowerCase().includes(searchTerm)) || (c.ip && c.ip.includes(searchTerm)) ); } setFilteredComputers(result); }, [computers, filters]); const loadComputers = () => { fetch("/api/computers") .then((r) => r.json()) .then(data => setComputers(data)) .catch((err) => console.error("API error:", err)); }; const loadStats = () => { fetch("/api/stats") .then((r) => r.json()) .then(setStats) .catch((err) => console.error("API error:", err)); }; const openComputer = (name) => { setSelectedComputer(name); setLoadingDetails(true); setComputerDetails(null); setActiveTab('security'); setSysmonData(null); setNetworkData(null); fetch(`/api/computer/${encodeURIComponent(name)}`) .then((r) => r.json()) .then((data) => { setComputerDetails(data); setLoadingDetails(false); }) .catch((err) => { console.error("API error:", err); setLoadingDetails(false); }); }; // Load Sysmon processes const loadSysmonProcesses = () => { if (!selectedComputer) return; setLoadingSysmon(true); setSelectedSysmonProcess(null); // КОРИГИРАЈ ГО ОВА URL fetch(`/api/computer/${encodeURIComponent(selectedComputer)}/sysmon`) .then((r) => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); }) .then((data) => { console.log("Sysmon data received:", data); // Ако data.processes е празна, пробај со детален endpoint if (!data.processes || data.processes.length === 0) { return fetch(`/api/computer/${encodeURIComponent(selectedComputer)}/detailed-sysmon`) .then(r => r.json()) .then(detailedData => { setSysmonData(detailedData); setLoadingSysmon(false); }); } setSysmonData(data); setLoadingSysmon(false); }) .catch((err) => { console.error("Sysmon API error:", err); // Fallback - пробај да земеш Sysmon events од општиот endpoint fetch(`/api/computer/${encodeURIComponent(selectedComputer)}`) .then(r => r.json()) .then(fullData => { if (fullData.sysmon_events) { // Конвертирај Sysmon events во процес формат const processes = fullData.sysmon_events.map((ev, idx) => ({ process_id: ev.event_id, process_name: ev.event_type, timestamp: ev.timestamp, message: ev.message, details: ev.details || {} })); setSysmonData({ computer_name: selectedComputer, processes: processes, count: processes.length }); } setLoadingSysmon(false); }) .catch(() => { setLoadingSysmon(false); }); }); }; // Load Network connections const loadNetworkConnections = () => { if (!selectedComputer) return; setLoadingNetwork(true); setSelectedNetworkItem(null); // КОРИГИРАЈ ГО ОВА URL fetch(`/api/computer/${encodeURIComponent(selectedComputer)}/network`) .then((r) => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); }) .then((data) => { console.log("Network data received:", data); setNetworkData(data); setLoadingNetwork(false); }) .catch((err) => { console.error("Network API error:", err); // Fallback - пробај да земеш network од општиот endpoint fetch(`/api/computer/${encodeURIComponent(selectedComputer)}`) .then(r => r.json()) .then(fullData => { if (fullData.network_connections) { const connections = fullData.network_connections.map((conn, idx) => ({ pid: conn.pid, process_name: conn.process_name, local_address: conn.local_address, remote_address: conn.remote_address, status: conn.status, timestamp: conn.timestamp, // Додади ги овие полиња за да match-не со очекуваниот формат local_port: conn.local_address?.split(':')?.[1] || '', remote_port: conn.remote_address?.split(':')?.[1] || '', protocol: 'TCP' })); setNetworkData({ computer_name: selectedComputer, connections: connections, count: connections.length }); } setLoadingNetwork(false); }) .catch(() => { setLoadingNetwork(false); }); }); }; const formatTime = (iso) => { if (!iso) return "-"; const d = new Date(iso); return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }); }; const formatDate = (iso) => { if (!iso) return "-"; const d = new Date(iso); return d.toLocaleDateString(); }; const askAssistant = async () => { if (!chatQuestion.trim()) return; const question = chatQuestion; setChatLoading(true); setChatQuestion(""); setShowWelcome(false); const newHistory = [...chatHistory, { type: "question", content: question, computer: chatComputer, timestamp: new Date().toISOString() }]; setChatHistory(newHistory); try { const res = await fetch("/api/chat", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ question: question, computer_name: chatComputer || null, }), }); const answer = await res.json(); const finalAnswer = answer.answer || answer.error || "I couldn't process that request."; setChatHistory([...newHistory, { type: "answer", content: finalAnswer, timestamp: new Date().toISOString() }]); } catch (err) { setChatHistory([...newHistory, { type: "answer", content: "⚠️ Connection error. Please check the server.", timestamp: new Date().toISOString() }]); } finally { setChatLoading(false); } }; const resetFilters = () => { setFilters({ status: "all", search: "", os: "all", minCpu: 0, minRam: 0 }); }; const clearChat = () => { setChatHistory([]); setChatAnswer(""); setShowWelcome(true); }; const closeModal = () => { setSelectedComputer(null); setComputerDetails(null); setSysmonData(null); setNetworkData(null); setSelectedSysmonProcess(null); setSelectedNetworkItem(null); }; const quickQuestions = [ "Show security alerts from yesterday", "Which devices have high CPU usage?", "List suspicious network connections", "Show recent Sysmon events", "Display offline devices" ]; return (
{/* Main Content */}
{/* Top Navigation */} {/* Stats Overview */}

Network Overview

Last updated: {new Date().toLocaleTimeString()}
{computers.length} Total Devices
🖥️
{computers.filter(c => c.status === 'online').length} Online
{computers.length > 0 ? Math.round((computers.filter(c => c.status === 'online').length/computers.length)*100) : 0}%
{computers.filter(c => c.status === 'idle').length} Idle
⏸️
{computers.filter(c => c.status === 'offline').length} Offline
🔴
{stats ? stats.total_sysmon_events.toLocaleString() : "0"} Sysmon Events
24h
{stats ? stats.security_alerts || 0 : "0"} Alerts
🚨
{/* Main Dashboard */}
{/* Left Sidebar - Filters */} {/* Main Content Area */}

Network Devices

{filteredComputers.length} devices found

{/* Devices Grid */}
{filteredComputers.map((c) => (
openComputer(c.name)} >
{c.os?.includes("Windows") ? "🪟" : c.os?.includes("Linux") ? "🐧" : c.os?.includes("Mac") ? "🍎" : "💻"}

{c.name}

{c.user || "Unknown"}

{c.status}
IP {c.ip}
OS {c.os}
Last Active {formatTime(c.last_seen)}
CPU {c.avg_cpu || 0}%
Memory {c.avg_ram || 0}%
{c.sysmon_available && (
🛡️ {c.recent_sysmon || 0} events
)}
))} {filteredComputers.length === 0 && (
🔍

No devices match your filters

)}
{/* AI Assistant Sidebar */}
🤖

Security AI Assistant

Powered by LAN Sentinel

{showWelcome && (
🤖

Welcome to Security AI Assistant!

I can help you analyze security events, monitor network activity, and investigate incidents.

{quickQuestions.map((q, idx) => ( ))}
)} {chatHistory.map((msg, idx) => (
{msg.type === 'question' ? '👤' : '🤖'}
{msg.type === 'question' ? 'You' : 'Security AI'} {msg.computer && ( Computer: {msg.computer} )}
{msg.content}
{new Date(msg.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
))} {chatLoading && (
🤖
)}
setChatQuestion(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && askAssistant()} className="chat-input" />
{/* Enhanced Computer Details Modal */} {selectedComputer && (
e.stopPropagation()}>

{selectedComputer}

{computerDetails?.computer?.ip} {computerDetails?.computer?.os} {computerDetails?.computer?.status}
{loadingDetails ? (

Loading device details...

) : ( <> {/* Quick Stats */}
{computerDetails?.current_metrics?.cpu_usage || 0}%
CPU
💾
{computerDetails?.current_metrics?.ram_usage || 0}%
RAM
📡
{computerDetails?.current_metrics?.network_usage || 0}%
Network
🛡️
{computerDetails?.recent_sysmon || 0}
Sysmon Events
{/* Tabs */}
{/* Security Events Tab */} {activeTab === 'security' && (
{(computerDetails?.sysmon_events || []).map((ev, idx) => ( ))}
Time Event ID Type Description
{formatTime(ev.timestamp)} #{ev.event_id} {ev.event_type} {ev.message?.slice(0, 100) || 'No description'}
)} {/* Sysmon Processes Tab */} {activeTab === 'sysmon' && (

Sysmon Processes

{loadingSysmon ? (

Loading Sysmon processes...

) : sysmonData ? (
{sysmonData.processes && sysmonData.processes.length > 0 ? ( <>
{sysmonData.processes.map((proc, idx) => (
setSelectedSysmonProcess(idx)} >
{proc.process_name || 'Unknown'}
PID: {proc.process_id}
{formatTime(proc.timestamp)}
))}
{selectedSysmonProcess !== null ? (

Process Details (JSON)

                                            {JSON.stringify(sysmonData.processes[selectedSysmonProcess], null, 2)}
                                          
) : (
👈

Select a process from the list to view its JSON data

)}
) : (
📄

No Sysmon processes found

)}
) : (

Click refresh to load Sysmon processes

)}
)} {/* Network Connections Tab */} {activeTab === 'network' && (

Network Connections

{loadingNetwork ? (

Loading network connections...

) : networkData ? (
{networkData.connections && networkData.connections.length > 0 ? ( <>
{networkData.connections.map((conn, idx) => (
setSelectedNetworkItem(idx)} >
{conn.local_address}:{conn.local_port}
{conn.remote_address}:{conn.remote_port}
{conn.protocol} • {conn.state}
))}
{selectedNetworkItem !== null ? (

Connection Details (JSON)

                                            {JSON.stringify(networkData.connections[selectedNetworkItem], null, 2)}
                                          
) : (
👈

Select a connection to view its JSON data

)}
) : (
🌐

No network connections found

)}
) : (

Click refresh to load network connections

)}
)} {/* System Details Tab */} {activeTab === 'details' && computerDetails && (

System Information

Hostname: {computerDetails.computer.name}
IP Address: {computerDetails.computer.ip}
OS Version: {computerDetails.computer.os}
Last Seen: {formatTime(computerDetails.computer.last_seen)}

Current Metrics

CPU Usage: {computerDetails.current_metrics?.cpu_usage || 0}%
Memory Usage: {computerDetails.current_metrics?.ram_usage || 0}%
Disk Usage: {computerDetails.current_metrics?.disk_usage || 0}%
)}
)}
)}
); } export default App;