refactor(fwlog): Live-Log als Child-Route /firewall/live statt Firewall-Tab

User-Feedback: Tab fühlt sich falsch an, will eine eigene Page mit
URL-Pfad unter /firewall.

UI:
- pages/Firewall/LiveLog.tsx → pages/FirewallLive/index.tsx
- FirewallPage entfernt den live-Tab aus tabs[]
- App.tsx routet /firewall/live → FirewallLivePage
- Sidebar: neuer Eintrag „Firewall-Log" eingerückt direkt unter
  „Firewall" in der Security-Section (child: true Flag → CSS-Klasse
  sidebar-menu-item--child mit padding-left 28px + dünnem vertikalem
  Trenn-Stab links). Sibling-Active-Logik exklusiv: /firewall matched
  NICHT mehr wenn /firewall/live aktiv ist.
- AppLayout PAGE_TITLES bekommt /firewall/live VOR /firewall damit
  der Title-Lookup den spezifischeren Pfad zuerst trifft.

Keine Backend-Änderungen.

Bekanntes Verhalten zu erklären: Im Live-Log sehen User aktuell nur
Smoke-Test-Events (oob.prefix=edgeguard:smoke / edgeguard:42, src/dst
127.0.0.1) — das sind die manuell-injizierten nft-Rules vom End-to-
End-Test der Pipeline. Reale Pakete fließen erst durch, wenn der
Operator auf einer firewall_rule den Log-Switch aktiviert (Firewall
→ Regeln → bearbeiten → Logging an). Aktuell hat keine einzige Rule
log=true.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-13 07:04:19 +02:00
parent b031725dfe
commit 24c40bc776
10 changed files with 55 additions and 14 deletions

View File

@@ -7,6 +7,7 @@ import {
ClusterOutlined,
CrownOutlined,
DashboardOutlined,
EyeOutlined,
FileSearchOutlined,
DatabaseOutlined,
FireOutlined,
@@ -27,6 +28,7 @@ interface NavItem {
path: string
labelKey: string
icon: ReactNode
child?: boolean // visuell eingerückt unter dem Parent-Item
}
interface NavSection {
@@ -62,6 +64,7 @@ const NAV: NavSection[] = [
labelKey: 'nav.section.security',
items: [
{ path: '/firewall', labelKey: 'nav.firewall', icon: <FireOutlined /> },
{ path: '/firewall/live', labelKey: 'nav.firewallLive', icon: <EyeOutlined />, child: true },
{ path: '/vpn/wireguard', labelKey: 'nav.wireguard', icon: <ThunderboltOutlined /> },
{ path: '/forward-proxy', labelKey: 'nav.forwardProxy', icon: <CloudServerOutlined /> },
],
@@ -78,7 +81,7 @@ const NAV: NavSection[] = [
},
]
const VERSION = '1.0.67'
const VERSION = '1.0.68'
// Sidebar-Pattern 1:1 aus netcell-webpanel (enconf) übernommen:
// - <nav> als root, dunkler Gradient + Teal/Blue-Accent
@@ -104,13 +107,23 @@ export default function Sidebar({ isOpen, onClose }: SidebarProps) {
</div>
<ul className="sidebar-menu">
{section.items.map((item) => {
const isActive = location.pathname === item.path
|| location.pathname.startsWith(item.path + '/')
// exact-match → der genauere Pfad gewinnt; sonst würde
// /firewall den /firewall/live-Eintrag als „active"
// mitmarkieren. Sibling-Pfade müssen sich gegenseitig
// ausschließen.
const hasMoreSpecificSibling = section.items.some(
(other) => other.path !== item.path &&
other.path.startsWith(item.path + '/'),
)
const isActive = hasMoreSpecificSibling
? location.pathname === item.path
: location.pathname === item.path
|| location.pathname.startsWith(item.path + '/')
const cls = 'sidebar-menu-item'
+ (isActive ? ' active' : '')
+ (item.child ? ' sidebar-menu-item--child' : '')
return (
<li
key={item.path}
className={`sidebar-menu-item${isActive ? ' active' : ''}`}
>
<li key={item.path} className={cls}>
<Link to={item.path} onClick={onClose}>
{item.icon}
<span>{t(item.labelKey)}</span>