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:
@@ -52,7 +52,7 @@ import (
|
||||
wgsvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/wireguard"
|
||||
)
|
||||
|
||||
var version = "1.0.67"
|
||||
var version = "1.0.68"
|
||||
|
||||
func main() {
|
||||
addr := os.Getenv("EDGEGUARD_API_ADDR")
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
var version = "1.0.67"
|
||||
var version = "1.0.68"
|
||||
|
||||
const usage = `edgeguard-ctl — EdgeGuard CLI
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
"git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts"
|
||||
)
|
||||
|
||||
var version = "1.0.67"
|
||||
var version = "1.0.68"
|
||||
|
||||
const (
|
||||
// renewTickInterval — how often we re-evaluate expiring certs.
|
||||
|
||||
@@ -25,6 +25,7 @@ const ForwardProxyPage = lazy(() => import('./pages/ForwardProxy'))
|
||||
const DNSPage = lazy(() => import('./pages/DNS'))
|
||||
const NTPPage = lazy(() => import('./pages/NTP'))
|
||||
const ClusterPage = lazy(() => import('./pages/Cluster'))
|
||||
const FirewallLivePage = lazy(() => import('./pages/FirewallLive'))
|
||||
const LogsPage = lazy(() => import('./pages/Logs'))
|
||||
const BackupsPage = lazy(() => import('./pages/Backups'))
|
||||
const LicensePage = lazy(() => import('./pages/License'))
|
||||
@@ -106,6 +107,7 @@ export default function App() {
|
||||
<Route path="/ip-addresses" element={<IPAddressesPage />} />
|
||||
<Route path="/ssl" element={<SSLPage />} />
|
||||
<Route path="/firewall" element={<FirewallPage />} />
|
||||
<Route path="/firewall/live" element={<FirewallLivePage />} />
|
||||
<Route path="/vpn/wireguard" element={<WireguardPage />} />
|
||||
<Route path="/forward-proxy" element={<ForwardProxyPage />} />
|
||||
<Route path="/dns" element={<DNSPage />} />
|
||||
|
||||
@@ -16,6 +16,8 @@ const PAGE_TITLES: Record<string, string> = {
|
||||
'/routing-rules': 'nav.routing',
|
||||
'/networks': 'nav.networks',
|
||||
'/ip-addresses': 'nav.ipAddresses',
|
||||
'/firewall/live': 'nav.firewallLive',
|
||||
'/firewall': 'nav.firewall',
|
||||
'/cluster': 'nav.cluster',
|
||||
'/logs': 'nav.logs',
|
||||
'/backups': 'nav.backups',
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -10,7 +10,6 @@ import ServiceGroupsTab from './ServiceGroups'
|
||||
import RulesTab from './Rules'
|
||||
import NATRulesTab from './NATRules'
|
||||
import ZonesTab from './Zones'
|
||||
import LiveLogTab from './LiveLog'
|
||||
|
||||
export default function FirewallPage() {
|
||||
const { t } = useTranslation()
|
||||
@@ -18,7 +17,6 @@ export default function FirewallPage() {
|
||||
const tabs = [
|
||||
{ key: 'rules', label: t('fw.tabs.rules'), children: <RulesTab /> },
|
||||
{ key: 'nat', label: t('fw.tabs.nat'), children: <NATRulesTab /> },
|
||||
{ key: 'live', label: t('fw.tabs.live'), children: <LiveLogTab /> },
|
||||
{ key: 'zones', label: t('fw.tabs.zones'), children: <ZonesTab /> },
|
||||
{ key: 'addrObj', label: t('fw.tabs.addrObj'), children: <AddressObjectsTab /> },
|
||||
{ key: 'addrGrp', label: t('fw.tabs.addrGrp'), children: <AddressGroupsTab /> },
|
||||
|
||||
@@ -7,12 +7,15 @@ import {
|
||||
AlertOutlined,
|
||||
ClearOutlined,
|
||||
DownloadOutlined,
|
||||
EyeOutlined,
|
||||
PauseCircleOutlined,
|
||||
PlayCircleOutlined,
|
||||
PoweroffOutlined,
|
||||
} from '@ant-design/icons'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import PageHeader from '../../components/PageHeader'
|
||||
|
||||
const { Text } = Typography
|
||||
|
||||
interface Entry {
|
||||
@@ -105,7 +108,7 @@ function toCSV(rows: Entry[]): string {
|
||||
// DISCONNECTED — der WebSocket wird erst beim Klick auf „Start"
|
||||
// aufgebaut. Stop schließt explizit, Filter-Änderungen reconnecten
|
||||
// nur wenn aktiv.
|
||||
export default function LiveLogTab() {
|
||||
export default function FirewallLivePage() {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [active, setActive] = useState(false) // Start/Stop master switch
|
||||
@@ -287,6 +290,11 @@ export default function LiveLogTab() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader
|
||||
icon={<EyeOutlined />}
|
||||
title={t('fwlog.title')}
|
||||
subtitle={t('fwlog.intro')}
|
||||
/>
|
||||
{!active ? (
|
||||
<Card style={{ textAlign: 'center', padding: '32px 16px' }}>
|
||||
<Empty
|
||||
@@ -152,6 +152,24 @@ h1, h2, h3, h4, h5, h6 {
|
||||
color: #CBD5E1;
|
||||
}
|
||||
|
||||
/* Child-Item: sub-nav unter einem Parent (z.B. /firewall/live unter
|
||||
/firewall). Eingerückt + dünner-vertical-Stab links damit die
|
||||
Hierarchie sofort sichtbar ist. */
|
||||
.sidebar-menu-item--child a,
|
||||
.sidebar-menu-item--child button {
|
||||
padding-left: 28px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.sidebar-menu-item--child::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 14px;
|
||||
top: 14px;
|
||||
bottom: 14px;
|
||||
width: 1px;
|
||||
background: rgba(255,255,255,0.08);
|
||||
}
|
||||
|
||||
.sidebar-menu-item.active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
||||
Reference in New Issue
Block a user