feat: add Syslog configuration to Network Services (v0.10.8 Beta)
New Syslog page under Network Services exposes RouterOS logging actions and routing rules with full CRUD. Logging actions define destinations (remote syslog server, memory, disk, echo); logging rules define which topics route to which action. Single Device and All Devices modes are functionally identical — All Devices applies changes across every online device in parallel and shows per-entry coverage badges indicating which devices have each action or rule. Toggle enable/disable works in both modes. Remote actions display address:port with facility/severity in a single Destination column; memory/disk/echo rows show no irrelevant remote fields. Syslog KPI card added to the Network Services overview.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mikrotik-manager-frontend",
|
||||
"version": "0.10.7-beta",
|
||||
"version": "0.10.8-beta",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -23,6 +23,7 @@ import NetworkServicesDHCPPage from './pages/NetworkServicesDHCPPage';
|
||||
import NetworkServicesDNSPage from './pages/NetworkServicesDNSPage';
|
||||
import NetworkServicesNTPPage from './pages/NetworkServicesNTPPage';
|
||||
import NetworkServicesWireGuardPage from './pages/NetworkServicesWireGuardPage';
|
||||
import NetworkServicesSyslogPage from './pages/NetworkServicesSyslogPage';
|
||||
|
||||
function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
||||
const token = useAuthStore((s) => s.token);
|
||||
@@ -65,6 +66,7 @@ export default function App() {
|
||||
<Route path="network-services/dns" element={<NetworkServicesDNSPage />} />
|
||||
<Route path="network-services/ntp" element={<NetworkServicesNTPPage />} />
|
||||
<Route path="network-services/wireguard" element={<NetworkServicesWireGuardPage />} />
|
||||
<Route path="network-services/syslog" element={<NetworkServicesSyslogPage />} />
|
||||
</Route>
|
||||
<Route path="*" element={<Navigate to="/dashboard" replace />} />
|
||||
</Routes>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import {
|
||||
LayoutDashboard, Router, Users, Bell, GitBranch, HardDrive,
|
||||
Settings, Network, ChevronLeft, ChevronRight, Layers, ChevronDown, SlidersHorizontal, X, Wifi,
|
||||
Server, Globe, Clock, Shield,
|
||||
Server, Globe, Clock, Shield, FileText,
|
||||
} from 'lucide-react';
|
||||
import clsx from 'clsx';
|
||||
import { APP_VERSION } from '../../version';
|
||||
@@ -40,7 +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/wireguard', icon: Shield, label: 'WireGuard' },
|
||||
{ to: '/network-services/syslog', icon: FileText, label: 'Syslog' },
|
||||
];
|
||||
|
||||
interface SidebarProps {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
Server, RefreshCw, CheckCircle, XCircle, MinusCircle,
|
||||
Globe, Clock, Shield, Wifi,
|
||||
Globe, Clock, Shield, Wifi, FileText,
|
||||
} from 'lucide-react';
|
||||
import clsx from 'clsx';
|
||||
import { networkServicesApi } from '../services/api';
|
||||
@@ -16,6 +16,7 @@ interface DeviceServiceRow {
|
||||
dns: { allow_remote: boolean; servers: string } | null;
|
||||
ntp: { server_enabled: boolean; client_enabled: boolean } | null;
|
||||
wireguard: { total: number; running: number } | null;
|
||||
syslog: { remote_count: number } | null;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
@@ -58,7 +59,8 @@ export default function NetworkServicesOverviewPage() {
|
||||
{ key: 'dhcp_v6', label: 'DHCP v6', icon: Server, href: '/network-services/dhcp' },
|
||||
{ key: 'dns', label: 'DNS', icon: Globe, href: '/network-services/dns' },
|
||||
{ key: 'ntp', label: 'NTP', icon: Clock, href: '/network-services/ntp' },
|
||||
{ key: 'wireguard', label: 'WireGuard', icon: Shield, href: '/network-services/wireguard' },
|
||||
{ key: 'wireguard', label: 'WireGuard', icon: Shield, href: '/network-services/wireguard' },
|
||||
{ key: 'syslog', label: 'Syslog', icon: FileText, href: '/network-services/syslog' },
|
||||
] as const;
|
||||
|
||||
// KPI: for each service, how many devices have it active?
|
||||
@@ -72,6 +74,7 @@ export default function NetworkServicesOverviewPage() {
|
||||
if (col.key === 'dns') return (svc as { allow_remote: boolean }).allow_remote;
|
||||
if (col.key === 'ntp') return (svc as { server_enabled: boolean }).server_enabled || (svc as { client_enabled: boolean }).client_enabled;
|
||||
if (col.key === 'wireguard') return (svc as { running: number }).running > 0;
|
||||
if (col.key === 'syslog') return (svc as { remote_count: number }).remote_count > 0;
|
||||
return false;
|
||||
}).length;
|
||||
return { ...col, active, total: data.length };
|
||||
@@ -101,6 +104,10 @@ export default function NetworkServicesOverviewPage() {
|
||||
if (s.total === 0) return <ServiceCell active={null} label="None" />;
|
||||
return <ServiceCell active={s.running > 0} label={`${s.running}/${s.total} up`} />;
|
||||
}
|
||||
if (key === 'syslog') {
|
||||
const s = svc as { remote_count: number };
|
||||
return <ServiceCell active={s.remote_count > 0} label={s.remote_count > 0 ? `${s.remote_count} remote` : 'No remote'} />;
|
||||
}
|
||||
return <ServiceCell active={null} />;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -684,6 +684,24 @@ export const networkServicesApi = {
|
||||
}) =>
|
||||
api.put<{ server: NS; client: NS }>('/network-services/ntp', settings, { params: { deviceId } }),
|
||||
|
||||
// ── Syslog ────────────────────────────────────────────────────────────────
|
||||
getSyslog: (deviceId: number) =>
|
||||
api.get<{ actions: NS[]; rules: NS[] }>('/network-services/syslog', { params: { deviceId } }),
|
||||
addSyslogAction: (deviceId: number, body: NS) =>
|
||||
api.post<NS[]>('/network-services/syslog/action', body, { params: { deviceId } }),
|
||||
updateSyslogAction: (deviceId: number, id: string, body: NS) =>
|
||||
api.put<NS[]>(`/network-services/syslog/action/${encodeURIComponent(id)}`, body, { params: { deviceId } }),
|
||||
deleteSyslogAction: (deviceId: number, id: string) =>
|
||||
api.delete(`/network-services/syslog/action/${encodeURIComponent(id)}`, { params: { deviceId } }),
|
||||
addSyslogRule: (deviceId: number, body: NS) =>
|
||||
api.post<NS[]>('/network-services/syslog/rule', body, { params: { deviceId } }),
|
||||
updateSyslogRule: (deviceId: number, id: string, body: NS) =>
|
||||
api.put<NS[]>(`/network-services/syslog/rule/${encodeURIComponent(id)}`, body, { params: { deviceId } }),
|
||||
deleteSyslogRule: (deviceId: number, id: string) =>
|
||||
api.delete(`/network-services/syslog/rule/${encodeURIComponent(id)}`, { params: { deviceId } }),
|
||||
toggleSyslogRule: (deviceId: number, ruleId: string, disabled: boolean) =>
|
||||
api.put('/network-services/syslog/rule/toggle', { ruleId, disabled }, { params: { deviceId } }),
|
||||
|
||||
// ── WireGuard ─────────────────────────────────────────────────────────────
|
||||
getWireGuard: (deviceId: number) =>
|
||||
api.get<{ interfaces: NS[]; peers: NS[] }>('/network-services/wireguard', { params: { deviceId } }),
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const APP_VERSION = 'v0.10.7 Beta';
|
||||
export const APP_VERSION = 'v0.10.8 Beta';
|
||||
|
||||
Reference in New Issue
Block a user