From 3f7fa7d62ca584e342659331d7f04dc95592be70 Mon Sep 17 00:00:00 2001 From: Jason Staack Date: Thu, 19 Mar 2026 06:47:36 -0500 Subject: [PATCH] feat(14-02): integrate wireless tabs into device detail and add wireless links page - Add Stations tab to StandardConfigSidebar (Monitor section) - Render WirelessStationTable + RFStatsCard in stations tab - Create standalone wireless-links route page - Update Sidebar nav to point Wireless Links to tenant-scoped page Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/src/components/layout/Sidebar.tsx | 17 ++++++++---- .../simple-config/SimpleConfigView.tsx | 8 ++++++ .../simple-config/StandardConfigSidebar.tsx | 1 + frontend/src/routeTree.gen.ts | 23 ++++++++++++++++ .../tenants/$tenantId/wireless-links.tsx | 26 +++++++++++++++++++ 5 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 frontend/src/routes/_authenticated/tenants/$tenantId/wireless-links.tsx diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx index 899ade3..4f86665 100644 --- a/frontend/src/components/layout/Sidebar.tsx +++ b/frontend/src/components/layout/Sidebar.tsx @@ -120,11 +120,18 @@ export function Sidebar() { }, ] : []), - { - label: 'Wireless', - href: '/wireless', - icon: Wifi, - }, + ...(!isSuperAdmin(user) && user?.tenant_id + ? [{ + label: 'Wireless Links', + href: `/tenants/${user.tenant_id}/wireless-links`, + icon: Wifi, + }] + : [{ + label: 'Wireless Links', + href: '/wireless', + icon: Wifi, + }] + ), { label: 'Traffic', href: '/traffic', diff --git a/frontend/src/components/simple-config/SimpleConfigView.tsx b/frontend/src/components/simple-config/SimpleConfigView.tsx index c82d4f1..df64f72 100644 --- a/frontend/src/components/simple-config/SimpleConfigView.tsx +++ b/frontend/src/components/simple-config/SimpleConfigView.tsx @@ -54,6 +54,8 @@ import { SnmpPanel } from '@/components/config/SnmpPanel' import { ClientsTab } from '@/components/network/ClientsTab' import { VpnTab } from '@/components/network/VpnTab' import { LogsTab } from '@/components/network/LogsTab' +import { WirelessStationTable } from '@/components/wireless/WirelessStationTable' +import { RFStatsCard } from '@/components/wireless/RFStatsCard' interface SimpleConfigViewProps { tenantId: string @@ -107,6 +109,12 @@ export function SimpleConfigView({ {activeTab === 'wireless' && ( )} + {activeTab === 'stations' && ( +
+ + +
+ )} {activeTab === 'interfaces' && ( )} diff --git a/frontend/src/components/simple-config/StandardConfigSidebar.tsx b/frontend/src/components/simple-config/StandardConfigSidebar.tsx index e989498..5422347 100644 --- a/frontend/src/components/simple-config/StandardConfigSidebar.tsx +++ b/frontend/src/components/simple-config/StandardConfigSidebar.tsx @@ -36,6 +36,7 @@ const STANDARD_GROUPS: SidebarGroup[] = [ { id: 'health', label: 'Health' }, { id: 'traffic', label: 'Traffic' }, { id: 'wireless', label: 'Wireless' }, + { id: 'stations', label: 'Stations' }, ], }, { diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index aab3666..02804e8 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -39,6 +39,7 @@ import { Route as AuthenticatedAboutRouteImport } from './routes/_authenticated/ import { Route as AuthenticatedTenantsIndexRouteImport } from './routes/_authenticated/tenants/index' import { Route as AuthenticatedSettingsApiKeysRouteImport } from './routes/_authenticated/settings.api-keys' import { Route as AuthenticatedTenantsTenantIdIndexRouteImport } from './routes/_authenticated/tenants/$tenantId/index' +import { Route as AuthenticatedTenantsTenantIdWirelessLinksRouteImport } from './routes/_authenticated/tenants/$tenantId/wireless-links' import { Route as AuthenticatedTenantsTenantIdUsersRouteImport } from './routes/_authenticated/tenants/$tenantId/users' import { Route as AuthenticatedTenantsTenantIdSitesIndexRouteImport } from './routes/_authenticated/tenants/$tenantId/sites/index' import { Route as AuthenticatedTenantsTenantIdDevicesIndexRouteImport } from './routes/_authenticated/tenants/$tenantId/devices/index' @@ -206,6 +207,12 @@ const AuthenticatedTenantsTenantIdIndexRoute = path: '/tenants/$tenantId/', getParentRoute: () => AuthenticatedRoute, } as any) +const AuthenticatedTenantsTenantIdWirelessLinksRoute = + AuthenticatedTenantsTenantIdWirelessLinksRouteImport.update({ + id: '/tenants/$tenantId/wireless-links', + path: '/tenants/$tenantId/wireless-links', + getParentRoute: () => AuthenticatedRoute, + } as any) const AuthenticatedTenantsTenantIdUsersRoute = AuthenticatedTenantsTenantIdUsersRouteImport.update({ id: '/tenants/$tenantId/users', @@ -285,6 +292,7 @@ export interface FileRoutesByFullPath { '/settings/api-keys': typeof AuthenticatedSettingsApiKeysRoute '/tenants/': typeof AuthenticatedTenantsIndexRoute '/tenants/$tenantId/users': typeof AuthenticatedTenantsTenantIdUsersRoute + '/tenants/$tenantId/wireless-links': typeof AuthenticatedTenantsTenantIdWirelessLinksRoute '/tenants/$tenantId/': typeof AuthenticatedTenantsTenantIdIndexRoute '/tenants/$tenantId/devices/$deviceId': typeof AuthenticatedTenantsTenantIdDevicesDeviceIdRoute '/tenants/$tenantId/devices/add': typeof AuthenticatedTenantsTenantIdDevicesAddRoute @@ -324,6 +332,7 @@ export interface FileRoutesByTo { '/settings/api-keys': typeof AuthenticatedSettingsApiKeysRoute '/tenants': typeof AuthenticatedTenantsIndexRoute '/tenants/$tenantId/users': typeof AuthenticatedTenantsTenantIdUsersRoute + '/tenants/$tenantId/wireless-links': typeof AuthenticatedTenantsTenantIdWirelessLinksRoute '/tenants/$tenantId': typeof AuthenticatedTenantsTenantIdIndexRoute '/tenants/$tenantId/devices/$deviceId': typeof AuthenticatedTenantsTenantIdDevicesDeviceIdRoute '/tenants/$tenantId/devices/add': typeof AuthenticatedTenantsTenantIdDevicesAddRoute @@ -365,6 +374,7 @@ export interface FileRoutesById { '/_authenticated/settings/api-keys': typeof AuthenticatedSettingsApiKeysRoute '/_authenticated/tenants/': typeof AuthenticatedTenantsIndexRoute '/_authenticated/tenants/$tenantId/users': typeof AuthenticatedTenantsTenantIdUsersRoute + '/_authenticated/tenants/$tenantId/wireless-links': typeof AuthenticatedTenantsTenantIdWirelessLinksRoute '/_authenticated/tenants/$tenantId/': typeof AuthenticatedTenantsTenantIdIndexRoute '/_authenticated/tenants/$tenantId/devices/$deviceId': typeof AuthenticatedTenantsTenantIdDevicesDeviceIdRoute '/_authenticated/tenants/$tenantId/devices/add': typeof AuthenticatedTenantsTenantIdDevicesAddRoute @@ -406,6 +416,7 @@ export interface FileRouteTypes { | '/settings/api-keys' | '/tenants/' | '/tenants/$tenantId/users' + | '/tenants/$tenantId/wireless-links' | '/tenants/$tenantId/' | '/tenants/$tenantId/devices/$deviceId' | '/tenants/$tenantId/devices/add' @@ -445,6 +456,7 @@ export interface FileRouteTypes { | '/settings/api-keys' | '/tenants' | '/tenants/$tenantId/users' + | '/tenants/$tenantId/wireless-links' | '/tenants/$tenantId' | '/tenants/$tenantId/devices/$deviceId' | '/tenants/$tenantId/devices/add' @@ -485,6 +497,7 @@ export interface FileRouteTypes { | '/_authenticated/settings/api-keys' | '/_authenticated/tenants/' | '/_authenticated/tenants/$tenantId/users' + | '/_authenticated/tenants/$tenantId/wireless-links' | '/_authenticated/tenants/$tenantId/' | '/_authenticated/tenants/$tenantId/devices/$deviceId' | '/_authenticated/tenants/$tenantId/devices/add' @@ -716,6 +729,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthenticatedTenantsTenantIdIndexRouteImport parentRoute: typeof AuthenticatedRoute } + '/_authenticated/tenants/$tenantId/wireless-links': { + id: '/_authenticated/tenants/$tenantId/wireless-links' + path: '/tenants/$tenantId/wireless-links' + fullPath: '/tenants/$tenantId/wireless-links' + preLoaderRoute: typeof AuthenticatedTenantsTenantIdWirelessLinksRouteImport + parentRoute: typeof AuthenticatedRoute + } '/_authenticated/tenants/$tenantId/users': { id: '/_authenticated/tenants/$tenantId/users' path: '/tenants/$tenantId/users' @@ -812,6 +832,7 @@ interface AuthenticatedRouteChildren { AuthenticatedIndexRoute: typeof AuthenticatedIndexRoute AuthenticatedTenantsIndexRoute: typeof AuthenticatedTenantsIndexRoute AuthenticatedTenantsTenantIdUsersRoute: typeof AuthenticatedTenantsTenantIdUsersRoute + AuthenticatedTenantsTenantIdWirelessLinksRoute: typeof AuthenticatedTenantsTenantIdWirelessLinksRoute AuthenticatedTenantsTenantIdIndexRoute: typeof AuthenticatedTenantsTenantIdIndexRoute AuthenticatedTenantsTenantIdDevicesDeviceIdRoute: typeof AuthenticatedTenantsTenantIdDevicesDeviceIdRoute AuthenticatedTenantsTenantIdDevicesAddRoute: typeof AuthenticatedTenantsTenantIdDevicesAddRoute @@ -847,6 +868,8 @@ const AuthenticatedRouteChildren: AuthenticatedRouteChildren = { AuthenticatedTenantsIndexRoute: AuthenticatedTenantsIndexRoute, AuthenticatedTenantsTenantIdUsersRoute: AuthenticatedTenantsTenantIdUsersRoute, + AuthenticatedTenantsTenantIdWirelessLinksRoute: + AuthenticatedTenantsTenantIdWirelessLinksRoute, AuthenticatedTenantsTenantIdIndexRoute: AuthenticatedTenantsTenantIdIndexRoute, AuthenticatedTenantsTenantIdDevicesDeviceIdRoute: diff --git a/frontend/src/routes/_authenticated/tenants/$tenantId/wireless-links.tsx b/frontend/src/routes/_authenticated/tenants/$tenantId/wireless-links.tsx new file mode 100644 index 0000000..e9abccb --- /dev/null +++ b/frontend/src/routes/_authenticated/tenants/$tenantId/wireless-links.tsx @@ -0,0 +1,26 @@ +import { createFileRoute } from '@tanstack/react-router' +import { Wifi } from 'lucide-react' +import { WirelessLinksTable } from '@/components/wireless/WirelessLinksTable' + +export const Route = createFileRoute( + '/_authenticated/tenants/$tenantId/wireless-links', +)({ + component: WirelessLinksPage, +}) + +function WirelessLinksPage() { + const { tenantId } = Route.useParams() + + return ( +
+ {/* Header */} +
+ +

Wireless Links

+
+ + {/* Links table */} + +
+ ) +}