|
|
@@ -6,6 +6,8 @@ let state = {
|
|
|
vpnStatus: null,
|
|
|
routes: [],
|
|
|
activeTab: 'dashboard',
|
|
|
+ fwSubTab: 'filter',
|
|
|
+ routesSubTab: 'routes',
|
|
|
ifaceFilter: 'all',
|
|
|
currentModalIface: null,
|
|
|
isPolling: true,
|
|
|
@@ -14,7 +16,15 @@ let state = {
|
|
|
wgData: null,
|
|
|
ipsecData: null,
|
|
|
l2tpData: null,
|
|
|
- pptpData: null
|
|
|
+ pptpData: null,
|
|
|
+ fwSummary: null,
|
|
|
+ filterRules: [],
|
|
|
+ natRules: [],
|
|
|
+ mangleRules: [],
|
|
|
+ addressLists: [],
|
|
|
+ connections: [],
|
|
|
+ policyRules: [],
|
|
|
+ routingTables: []
|
|
|
};
|
|
|
|
|
|
const API_BASE = '/api';
|
|
|
@@ -53,7 +63,8 @@ function navigate(tabName) {
|
|
|
dashboard: { title: 'Dashboard Overview', sub: 'Live router performance and network telemetry' },
|
|
|
interfaces: { title: 'Network Interfaces', sub: 'Hierarchical view of physical interfaces and nested 802.1Q VLANs' },
|
|
|
vlans: { title: 'VLAN Virtual Networks', sub: 'IEEE 802.1Q sub-interface segmentation and routing' },
|
|
|
- routes: { title: 'Kernel Routing Table', sub: 'Active IPv4 / IPv6 Linux kernel routes and gateways' },
|
|
|
+ firewall: { title: 'MikroTik Firewall', sub: 'Filter rules, NAT, Mangle, Address Lists & Active Connections tracking' },
|
|
|
+ routes: { title: 'Routing & Policy', sub: 'Routing tables, static routes (DAS/DAC), and policy routing rules' },
|
|
|
pppoe: { title: 'PPPoE Client WAN', sub: 'Point-to-Point Protocol over Ethernet WAN access' },
|
|
|
wireguard: { title: 'WireGuard Kernel VPN', sub: 'Modern ultra-fast cryptographic VPN tunnel manager' },
|
|
|
ipsec: { title: 'IPSec (IKEv2) strongSwan', sub: 'Enterprise Site-to-Site & Roadwarrior IPSec controller' },
|
|
|
@@ -63,18 +74,17 @@ function navigate(tabName) {
|
|
|
};
|
|
|
|
|
|
const header = titles[tabName] || titles.dashboard;
|
|
|
- document.getElementById('page-title').innerText = header.title;
|
|
|
- document.getElementById('page-subtitle').innerText = header.sub;
|
|
|
-
|
|
|
- // Toggle sections
|
|
|
- ['dashboard', 'interfaces', 'vlans', 'routes', 'pppoe', 'wireguard', 'ipsec', 'l2tp', 'pptp', 'persistence'].forEach(sec => {
|
|
|
- const el = document.getElementById(`section-${sec}`);
|
|
|
- if (el) {
|
|
|
- if (sec === tabName) {
|
|
|
- el.classList.remove('hidden');
|
|
|
- } else {
|
|
|
- el.classList.add('hidden');
|
|
|
- }
|
|
|
+ const pTitle = document.getElementById('page-title');
|
|
|
+ if (pTitle) pTitle.innerText = header.title;
|
|
|
+ const pSub = document.getElementById('page-subtitle');
|
|
|
+ if (pSub) pSub.innerText = header.sub;
|
|
|
+
|
|
|
+ // Toggle sections dynamically for all section elements
|
|
|
+ document.querySelectorAll('main section[id^="section-"]').forEach(el => {
|
|
|
+ if (el.id === `section-${tabName}`) {
|
|
|
+ el.classList.remove('hidden');
|
|
|
+ } else {
|
|
|
+ el.classList.add('hidden');
|
|
|
}
|
|
|
});
|
|
|
|
|
|
@@ -2111,10 +2121,14 @@ async function loadFirewall(populateDropdowns = true) {
|
|
|
if (addrlistRes.ok) state.addressLists = await addrlistRes.json();
|
|
|
|
|
|
// Badges
|
|
|
- document.getElementById('fw-badge-filter').innerText = (state.filterRules || []).length;
|
|
|
- document.getElementById('fw-badge-nat').innerText = (state.natRules || []).length;
|
|
|
- document.getElementById('fw-badge-mangle').innerText = (state.mangleRules || []).length;
|
|
|
- document.getElementById('fw-badge-addrlist').innerText = (state.addressLists || []).length;
|
|
|
+ const bFilter = document.getElementById('fw-badge-filter');
|
|
|
+ if (bFilter) bFilter.innerText = (state.filterRules || []).length;
|
|
|
+ const bNat = document.getElementById('fw-badge-nat');
|
|
|
+ if (bNat) bNat.innerText = (state.natRules || []).length;
|
|
|
+ const bMangle = document.getElementById('fw-badge-mangle');
|
|
|
+ if (bMangle) bMangle.innerText = (state.mangleRules || []).length;
|
|
|
+ const bAddr = document.getElementById('fw-badge-addrlist');
|
|
|
+ if (bAddr) bAddr.innerText = (state.addressLists || []).length;
|
|
|
|
|
|
renderFilterRules();
|
|
|
renderNATRules();
|
|
|
@@ -2981,10 +2995,14 @@ async function loadRoutes() {
|
|
|
if (rulesRes.ok) state.policyRules = await rulesRes.json();
|
|
|
if (tablesRes.ok) state.routingTables = await tablesRes.json();
|
|
|
|
|
|
- document.getElementById('routes-badge-routes').innerText = (state.routes || []).length;
|
|
|
- document.getElementById('routes-badge-rules').innerText = (state.policyRules || []).length;
|
|
|
- document.getElementById('routes-badge-tables').innerText = (state.routingTables || []).length;
|
|
|
- document.getElementById('badge-routes-count').innerText = (state.routes || []).length;
|
|
|
+ const bRoutes = document.getElementById('routes-badge-routes');
|
|
|
+ if (bRoutes) bRoutes.innerText = (state.routes || []).length;
|
|
|
+ const bRules = document.getElementById('routes-badge-rules');
|
|
|
+ if (bRules) bRules.innerText = (state.policyRules || []).length;
|
|
|
+ const bTables = document.getElementById('routes-badge-tables');
|
|
|
+ if (bTables) bTables.innerText = (state.routingTables || []).length;
|
|
|
+ const bRoutesCount = document.getElementById('badge-routes-count');
|
|
|
+ if (bRoutesCount) bRoutesCount.innerText = (state.routes || []).length;
|
|
|
|
|
|
renderRoutesList();
|
|
|
renderPolicyRules();
|