From 3a7ac1d0238cf99046cdde40d0e1513622e5cbc8 Mon Sep 17 00:00:00 2001 From: 2GT-Rich <107219997+2GT-Rich@users.noreply.github.com> Date: Mon, 11 May 2026 16:46:36 -0700 Subject: [PATCH] Minor UI Rework + Introduction of Operations view. --- README.md | 2 +- backend/package.json | 2 +- frontend/index.html | 3 + frontend/package.json | 2 +- frontend/src/components/layout/AppLayout.tsx | 4 +- frontend/src/components/layout/Sidebar.tsx | 433 +++--- frontend/src/components/layout/TopBar.tsx | 65 +- .../components/ports/SwitchPortDiagram.tsx | 790 +++++------ frontend/src/index.css | 297 ++-- frontend/src/pages/ClientsPage.tsx | 4 +- frontend/src/pages/DashboardPage.tsx | 1229 +++++++++++------ frontend/src/pages/DevicesPage.tsx | 679 ++++----- frontend/src/version.ts | 2 +- frontend/tailwind.config.js | 29 + 14 files changed, 1995 insertions(+), 1546 deletions(-) diff --git a/README.md b/README.md index 5f4c5b1..0f3c44e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A self-hosted, full-stack network management platform for MikroTik devices. Monitor, configure, and manage your entire MikroTik infrastructure — routers, switches, and wireless access points — from a single web interface. -![Version](https://img.shields.io/badge/version-0.10.8_Beta-blue) +![Version](https://img.shields.io/badge/version-0.10.9_Beta-blue) ![License](https://img.shields.io/badge/license-AGPLv3-blue) ![Docker](https://img.shields.io/badge/docker-compose-2496ED?logo=docker&logoColor=white) ![TypeScript](https://img.shields.io/badge/TypeScript-5.3-3178C6?logo=typescript&logoColor=white) diff --git a/backend/package.json b/backend/package.json index 2f36b6d..c776cf4 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "mikrotik-manager-backend", - "version": "0.10.8-beta", + "version": "0.10.9-beta", "description": "Mikrotik Network Management Platform - Backend API", "main": "dist/index.js", "scripts": { diff --git a/frontend/index.html b/frontend/index.html index ba98a20..bba8b26 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -6,6 +6,9 @@ Mikrotik Manager + + +
diff --git a/frontend/package.json b/frontend/package.json index 31e357b..d15fcbc 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "mikrotik-manager-frontend", - "version": "0.10.8-beta", + "version": "0.10.9-beta", "private": true, "type": "module", "scripts": { diff --git a/frontend/src/components/layout/AppLayout.tsx b/frontend/src/components/layout/AppLayout.tsx index 364ba48..8aaf085 100644 --- a/frontend/src/components/layout/AppLayout.tsx +++ b/frontend/src/components/layout/AppLayout.tsx @@ -8,7 +8,7 @@ export default function AppLayout() { const [sidebarOpen, setSidebarOpen] = useState(false); return ( -
+
{/* Mobile backdrop */} {sidebarOpen && (
setSidebarOpen((o) => !o)} /> -
+
diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx index f958ca7..09c53d2 100644 --- a/frontend/src/components/layout/Sidebar.tsx +++ b/frontend/src/components/layout/Sidebar.tsx @@ -40,8 +40,8 @@ const networkServicesSubItems = [ { to: '/network-services/dhcp', icon: Server, label: 'DHCP' }, { to: '/network-services/dns', icon: Globe, label: 'DNS' }, { to: '/network-services/ntp', icon: Clock, label: 'NTP' }, - { to: '/network-services/wireguard', icon: Shield, label: 'WireGuard' }, - { to: '/network-services/syslog', icon: FileText, label: 'Syslog' }, + { to: '/network-services/wireguard', icon: Shield, label: 'WireGuard' }, + { to: '/network-services/syslog', icon: FileText, label: 'Syslog' }, ]; interface SidebarProps { @@ -49,6 +49,43 @@ interface SidebarProps { onMobileClose: () => void; } +function NavItem({ + to, + icon: Icon, + label, + isCollapsed, + onClick, + end, +}: { + to: string; + icon: React.ElementType; + label: string; + isCollapsed: boolean; + onClick: () => void; + end?: boolean; +}) { + return ( + + clsx( + 'flex items-center gap-[10px] rounded-[6px] text-[13px] font-medium transition-colors duration-150 relative', + isCollapsed ? 'md:justify-center md:px-2 px-[10px] py-[7px]' : 'px-[10px] py-[7px]', + isActive + ? 'bg-surface-3 text-ink font-semibold border-l-2 border-accent pl-[8px]' + : 'text-ink-2 hover:bg-surface-3 hover:text-ink border-l-2 border-transparent' + ) + } + > + + {label} + + ); +} + export default function Sidebar({ mobileOpen, onMobileClose }: SidebarProps) { const [collapsed, setCollapsed] = useState(false); const location = useLocation(); @@ -63,6 +100,8 @@ export default function Sidebar({ mobileOpen, onMobileClose }: SidebarProps) { const hasRouters = devices.some(d => d.device_type === 'router'); const hasWireless = devices.some(d => d.device_type === 'wireless_ap'); + const onlineCount = devices.filter(d => d.status === 'online').length; + const switchesActive = location.pathname.startsWith('/switches'); const [switchesOpen, setSwitchesOpen] = useState(switchesActive); const effectiveSwitchesOpen = switchesOpen || switchesActive; @@ -79,77 +118,90 @@ export default function Sidebar({ mobileOpen, onMobileClose }: SidebarProps) { const [networkServicesOpen, setNetworkServicesOpen] = useState(networkServicesActive); const effectiveNetworkServicesOpen = networkServicesOpen || networkServicesActive; - // On mobile the sidebar is always expanded (never icon-only) const isCollapsed = collapsed; const handleNavClick = () => { - // Close mobile drawer when navigating onMobileClose(); }; + // Group header button (Switches / Routers / Wireless / Network Services) + const GroupHeader = ({ + icon: Icon, + label, + isActive, + isOpen, + onToggle, + }: { + icon: React.ElementType; + label: string; + isActive: boolean; + isOpen: boolean; + onToggle: () => void; + }) => ( + + ); + return (