diff --git a/src/App.tsx b/src/App.tsx index 53b5c8c..8a3f948 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,6 +4,7 @@ import Sidebar from './components/Sidebar' import TopBar from './components/TopBar' import Glance from './pages/Glance' import Infrastructure from './pages/Infrastructure' +import Network from './pages/Network' function App() { const [sidebarCollapsed, setSidebarCollapsed] = useState(false) @@ -55,6 +56,7 @@ function App() { } /> } /> + } /> diff --git a/src/pages/Network.tsx b/src/pages/Network.tsx new file mode 100644 index 0000000..3f5bc30 --- /dev/null +++ b/src/pages/Network.tsx @@ -0,0 +1,383 @@ +import { useState } from 'react' +import { PieChart, Pie, Cell, ResponsiveContainer, AreaChart, Area, XAxis } from 'recharts' +import { Activity, Gauge, ShieldAlert, Radio, Zap, Download, ChevronDown, Globe2 } from 'lucide-react' + +const subTabs = ['Overview'] + +const statusCards = [ + { label: 'Network Health', value: '98.7%', icon: Activity, sub: '↑ 2.3% yesterday', color: '#2ECC71' }, + { label: 'Total Traffic', value: '1.23 Tbps', icon: Radio, sub: '↑ 18.6% yesterday' }, + { label: 'Packet Loss', value: '0.02%', icon: Gauge, sub: '↓ 0.01% yesterday', color: '#2ECC71' }, + { label: 'Active Connections', value: '28,457', icon: Zap, sub: '↑ 6.7% yesterday' }, + { label: 'Threats Blocked', value: '152', icon: ShieldAlert, sub: '↑ 12.4% yesterday', color: '#E67E22' }, + { label: 'Avg. Latency', value: '12.4 ms', icon: Activity, sub: '↓ 8.1% yesterday', color: '#2ECC71' }, +] + +const topTalkers = [ + { name: 'web-app-01', rate: '203.4 Gbps' }, + { name: 'db-primary', rate: '156.7 Gbps' }, + { name: 'cache-cluster', rate: '98.3 Gbps' }, + { name: 'api-gateway', rate: '76.1 Gbps' }, + { name: 'backup-server', rate: '54.8 Gbps' }, +] + +const regions = [ + { name: 'us-east-1', x: '22%', y: '38%', status: 'live' }, + { name: 'us-west-2', x: '12%', y: '42%', status: 'live' }, + { name: 'eu-west-1', x: '48%', y: '30%', status: 'warning' }, + { name: 'ap-southeast-1', x: '78%', y: '58%', status: 'live' }, + { name: 'sa-east-1', x: '32%', y: '72%', status: 'live' }, + { name: 'ap-northeast-1', x: '85%', y: '40%', status: 'critical' }, +] + +const regionStatusColor: Record = { + live: '#2ECC71', + warning: '#E67E22', + critical: '#E74C3C', +} + +const interfaces = [ + { name: 'ethernet1/1', percentage: 85 }, + { name: 'ethernet1/2', percentage: 72 }, + { name: 'ethernet1/3', percentage: 68 }, + { name: 'ethernet1/4', percentage: 55 }, + { name: 'ethernet1/5', percentage: 48 }, +] + +const alertSummary = [ + { label: 'Critical', value: 2, color: '#E74C3C' }, + { label: 'Warning', value: 5, color: '#E67E22' }, + { label: 'Info', value: 12, color: '#2ECC71' }, +] + +const trafficData = Array.from({ length: 12 }, (_, i) => ({ + hour: i * 2, + inbound: 500 + i * 40 + Math.sin(i / 2) * 60, + outbound: 350 + i * 30 + Math.cos(i / 3) * 50, + total: 900 + i * 60 + Math.sin(i / 2.5) * 80, +})) + +const protocolData = [ + { name: 'TCP', value: 65, color: '#C8A434' }, + { name: 'UDP', value: 19, color: '#E67E22' }, + { name: 'ICMP', value: 7, color: '#2ECC71' }, + { name: 'DNS', value: 4, color: '#7A7D85' }, + { name: 'Others', value: 5, color: '#3B82F6' }, +] + +const recentEvents = [ + { title: 'ethernet1/2 UP', source: 'Interface restored', time: '2m ago' }, + { title: 'High bandwidth detected', source: 'web-app-01', time: '8m ago' }, + { title: 'New device joined', source: '10.0.1.45', time: '15m ago' }, + { title: 'VPN tunnel established', source: 'us-west-2', time: '22m ago' }, + { title: 'Blocked threat', source: '185.199.108.153', time: '35m ago' }, +] + +const cardBase: React.CSSProperties = { + backgroundColor: 'rgba(10, 10, 12, 0.92)', + border: '1px solid rgba(200, 164, 52, 0.08)', + borderRadius: '12px', + padding: '20px', + boxShadow: '0 0 20px rgba(200, 164, 52, 0.03)', + transition: 'border-color 0.2s ease', + position: 'relative', + overflow: 'hidden', + height: '100%', + display: 'flex', + flexDirection: 'column', +} + +const sectionTitle: React.CSSProperties = { + fontSize: '11px', + textTransform: 'uppercase', + letterSpacing: '1.5px', + color: '#7A7D85', + fontWeight: 500, + marginBottom: '16px', +} + +function framedCard(bgUrl: string): React.CSSProperties { + return { + backgroundImage: `url(${bgUrl})`, + backgroundSize: '100% 100%', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + position: 'relative', + overflow: 'hidden', + height: '100%', + display: 'flex', + flexDirection: 'column', + padding: '20px 20px 64px 20px', + } +} + +const cardVignette: React.CSSProperties = { + position: 'absolute', + inset: 0, + pointerEvents: 'none', + background: 'radial-gradient(ellipse closest-side at center, transparent 70%, var(--color-page) 100%)', +} + +const cardDim: React.CSSProperties = { + position: 'absolute', + inset: 0, + pointerEvents: 'none', + backgroundColor: 'rgba(8, 8, 10, 0.45)', +} + +function Donut({ data, centerLabel }: { data: { name: string; value: number; color: string }[]; centerLabel?: string }) { + return ( + + + + + + {data.map((entry) => ( + + ))} + + + + {centerLabel && ( + + {centerLabel} + + )} + + + {data.map((entry) => ( + + + {entry.name} + {entry.value}% + + ))} + + + ) +} + +export default function Network() { + const [activeTab, setActiveTab] = useState('Overview') + + return ( + <> + {/* Sub-tabs + Actions */} + + + {subTabs.map((tab) => { + const active = tab === activeTab + return ( + setActiveTab(tab)} + className="cursor-pointer bg-transparent border-none transition-colors whitespace-nowrap" + style={{ + fontSize: '12px', + fontWeight: 500, + padding: '8px 14px', + borderRadius: '8px', + color: active ? '#C8A434' : '#7A7D85', + backgroundColor: active ? 'rgba(200,164,52,0.1)' : 'transparent', + }} + > + {tab} + + ) + })} + + + + Last 24 Hours + + + + + Export Report + + + + + {/* Status Cards */} + + {statusCards.map((card) => { + const Icon = card.icon + return ( + + + {card.label} + + + + {card.value} + + {card.sub} + + ) + })} + + + {/* Middle Row */} + + + {/* Top Talkers */} + + + Top Talkers + + {topTalkers.map((t) => ( + + {t.name} + {t.rate} + + ))} + + + + + {/* Network Topology */} + + + + + + Network Topology + + Live + Warning + Critical + + + + + {regions.map((r) => ( + + + + ))} + + + + + {/* Interface Utilization + Alert Summary, stacked */} + + + Interface Utilization + + {interfaces.map((iface) => ( + + + {iface.name} + {iface.percentage}% + + + + + + ))} + + + + Alert Summary + + {alertSummary.map((a) => ( + + {a.value} + {a.label} + + ))} + + + + + + + {/* Bottom Row */} + + + {/* Traffic Over Time */} + + Traffic Over Time + + + + + + + + + + + + + {/* Protocol Distribution */} + + Protocol Distribution + + + + {/* Recent Events */} + + Recent Events + + {recentEvents.map((item, i) => ( + + + {item.title} + {item.source} + + {item.time} + + ))} + + + + + + {/* Footer stats bar */} + + 6 Regions| + 42 Sites| + 248 Devices| + 1,245 Interfaces| + 28,457 Connections| + 98.7% Health + + > + ) +}
{card.sub}
{item.title}
{item.source}