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) <noreply@anthropic.com>
This commit is contained in:
Jason Staack
2026-03-19 06:47:36 -05:00
parent eec89b802a
commit 3f7fa7d62c
5 changed files with 70 additions and 5 deletions

View File

@@ -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',

View File

@@ -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' && (
<WirelessTab tenantId={tenantId} deviceId={deviceId} active />
)}
{activeTab === 'stations' && (
<div className="space-y-4">
<WirelessStationTable tenantId={tenantId} deviceId={deviceId} active />
<RFStatsCard tenantId={tenantId} deviceId={deviceId} active />
</div>
)}
{activeTab === 'interfaces' && (
<InterfacesPanel tenantId={tenantId} deviceId={deviceId} active />
)}

View File

@@ -36,6 +36,7 @@ const STANDARD_GROUPS: SidebarGroup[] = [
{ id: 'health', label: 'Health' },
{ id: 'traffic', label: 'Traffic' },
{ id: 'wireless', label: 'Wireless' },
{ id: 'stations', label: 'Stations' },
],
},
{

View File

@@ -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:

View File

@@ -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 (
<div className="space-y-4">
{/* Header */}
<div className="flex items-center gap-2">
<Wifi className="h-5 w-5 text-text-muted" />
<h1 className="text-lg font-semibold text-text-primary">Wireless Links</h1>
</div>
{/* Links table */}
<WirelessLinksTable tenantId={tenantId} />
</div>
)
}