Network Overview
Network Devices
{filteredComputers.length} devices found
{c.name}
{c.user || "Unknown"}
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 (
{filteredComputers.length} devices found
{c.user || "Unknown"}
Powered by LAN Sentinel
I can help you analyze security events, monitor network activity, and investigate incidents.
Loading device details...
| Time | Event ID | Type | Description |
|---|---|---|---|
| {formatTime(ev.timestamp)} | #{ev.event_id} | {ev.event_type} | {ev.message?.slice(0, 100) || 'No description'} |
Loading Sysmon processes...
{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
Loading network connections...
{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