chore(dashboard): remove orphaned route, redirect 5 legacy routes, fix a misleading docstring (#143)

* chore(dashboard): remove orphaned /adapter-config route

AdapterConfig is already embedded directly in Environment.tsx
(excludeKeys={CURATED_KEYS} hideLlmToggle); no in-app <Link> ever
targeted the standalone /adapter-config route. Drop the route, its
App.tsx import, the extraTitleItems entry in Layout.tsx, and the
now-unused Sliders icon import. pages/AdapterConfig.tsx itself is
kept — it's imported directly by Environment.tsx.

* chore(dashboard): redirect 5 orphaned legacy routes to their tabbed homes

/gauge-sites, /town-anchors, /mesh, /meshtastic/sources, and
/meshcore/companion each duplicate content now tabbed inside Places,
MeshtasticNodes, and MeshCoreContactsCompanion, and have no in-app
<Link> pointing at them (verified with rg). Convert them to
<Navigate replace> redirects, matching the existing /notifications
and /data-sources precedent.

/town-anchors, /meshtastic/sources, and /meshcore/companion land on
their host's first tab rather than deep-linking to the second tab
(no ?tab= support exists) — same accepted trade-off as the existing
/notifications and /data-sources redirects.

Drop the now-dead extraTitleItems entries and the redundant
'/meshcore/companion' pathTitles entry, plus the Radio, Droplets,
Layers, and Bot icon imports that were only used by those entries
(MapPin is kept — still used by the /places nav item). These 5
routes were never nav entries (extraTitleItems only), so the sidebar
stays at 17 items with 5 Meshtastic / 5 MeshCore — MT/MC symmetry
unchanged.

* docs(dashboard-api): fix misleading refresh_toggles docstring

The docstring claimed this endpoint was "kept for backwards-compat
with the dashboard's manual ping path," but rg turns up no frontend
call site for /notifications/refresh-toggles anywhere in
dashboard-frontend. The auto-refresh middleware
(_auto_refresh_toggle_filter, registered via
register_config_routes_hooks) already refreshes the ToggleFilter on
every successful notifications config PUT, covering the normal case.
Endpoint is untouched -- comment only, kept for ops/debug use.

---------

Co-authored-by: Matt Johnson <mj@k7zvx.com>
This commit is contained in:
malice 2026-07-17 14:06:12 -06:00 committed by GitHub
commit ec973b606a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 15 additions and 29 deletions

View file

@ -1,20 +1,14 @@
import { Routes, Route, Navigate } from 'react-router-dom' import { Routes, Route, Navigate } from 'react-router-dom'
import Layout from './components/Layout' import Layout from './components/Layout'
import Dashboard from './pages/Dashboard' import Dashboard from './pages/Dashboard'
import Mesh from './pages/Mesh'
import Environment from './pages/Environment' import Environment from './pages/Environment'
import Config from './pages/Config' import Config from './pages/Config'
import ActivityLog from './pages/ActivityLog' import ActivityLog from './pages/ActivityLog'
import Notifications from './pages/Notifications' import Notifications from './pages/Notifications'
import Reference from './pages/Reference' import Reference from './pages/Reference'
import AdapterConfig from './pages/AdapterConfig'
import GaugeSites from './pages/GaugeSites'
import TownAnchors from './pages/TownAnchors'
import MeshCoreRouting from './pages/MeshCoreRouting' import MeshCoreRouting from './pages/MeshCoreRouting'
import MeshCoreConnection from './pages/MeshCoreConnection' import MeshCoreConnection from './pages/MeshCoreConnection'
import MeshCoreCompanion from './pages/MeshCoreCompanion'
import MeshtasticConnection from './pages/MeshtasticConnection' import MeshtasticConnection from './pages/MeshtasticConnection'
import MeshtasticSources from './pages/MeshtasticSources'
import Places from './pages/Places' import Places from './pages/Places'
import MeshtasticNodes from './pages/MeshtasticNodes' import MeshtasticNodes from './pages/MeshtasticNodes'
import MeshCoreContactsCompanion from './pages/MeshCoreContactsCompanion' import MeshCoreContactsCompanion from './pages/MeshCoreContactsCompanion'
@ -41,7 +35,6 @@ function App() {
{/* Legacy /notifications -> Meshtastic Routing */} {/* Legacy /notifications -> Meshtastic Routing */}
<Route path="/notifications" element={<Navigate to="/meshtastic/routing" replace />} /> <Route path="/notifications" element={<Navigate to="/meshtastic/routing" replace />} />
<Route path="/reference" element={<Reference />} /> <Route path="/reference" element={<Reference />} />
<Route path="/adapter-config" element={<AdapterConfig />} />
{/* New aggregated pages */} {/* New aggregated pages */}
<Route path="/places" element={<Places />} /> <Route path="/places" element={<Places />} />
@ -49,14 +42,17 @@ function App() {
{/* Custom sources folded into Data Feeds; keep old bookmark working */} {/* Custom sources folded into Data Feeds; keep old bookmark working */}
<Route path="/data-sources" element={<Navigate to="/environment" replace />} /> <Route path="/data-sources" element={<Navigate to="/environment" replace />} />
{/* De-navved routes still work */} {/* Legacy /gauge-sites -> Places (Gauge Sites tab) */}
<Route path="/gauge-sites" element={<GaugeSites />} /> <Route path="/gauge-sites" element={<Navigate to="/places" replace />} />
<Route path="/town-anchors" element={<TownAnchors />} /> {/* Legacy /town-anchors -> Places (lands on first tab, no ?tab= deep-link) */}
<Route path="/mesh" element={<Mesh />} /> <Route path="/town-anchors" element={<Navigate to="/places" replace />} />
{/* Legacy /mesh -> Meshtastic Nodes & Health (Nodes tab) */}
<Route path="/mesh" element={<Navigate to="/meshtastic/nodes" replace />} />
{/* Meshtastic routes */} {/* Meshtastic routes */}
<Route path="/meshtastic/connection" element={<MeshtasticConnection />} /> <Route path="/meshtastic/connection" element={<MeshtasticConnection />} />
<Route path="/meshtastic/sources" element={<MeshtasticSources />} /> {/* Legacy /meshtastic/sources -> Nodes & Health (lands on first tab, no ?tab= deep-link) */}
<Route path="/meshtastic/sources" element={<Navigate to="/meshtastic/nodes" replace />} />
<Route path="/meshtastic/scheduled" element={<ScheduledBroadcasts family="meshtastic" />} /> <Route path="/meshtastic/scheduled" element={<ScheduledBroadcasts family="meshtastic" />} />
<Route path="/meshtastic/nodes" element={<MeshtasticNodes />} /> <Route path="/meshtastic/nodes" element={<MeshtasticNodes />} />
<Route path="/meshtastic/danger-zones" element={<MeshtasticDangerZones />} /> <Route path="/meshtastic/danger-zones" element={<MeshtasticDangerZones />} />
@ -66,7 +62,8 @@ function App() {
<Route path="/meshcore/routing" element={<MeshCoreRouting />} /> <Route path="/meshcore/routing" element={<MeshCoreRouting />} />
<Route path="/meshcore/scheduled" element={<ScheduledBroadcasts family="meshcore" />} /> <Route path="/meshcore/scheduled" element={<ScheduledBroadcasts family="meshcore" />} />
<Route path="/meshcore/contacts" element={<MeshCoreContactsCompanion />} /> <Route path="/meshcore/contacts" element={<MeshCoreContactsCompanion />} />
<Route path="/meshcore/companion" element={<MeshCoreCompanion />} /> {/* Legacy /meshcore/companion -> Contacts & Companion (lands on first tab, no ?tab= deep-link) */}
<Route path="/meshcore/companion" element={<Navigate to="/meshcore/contacts" replace />} />
<Route path="/meshcore/danger-zones" element={<MeshCoreDangerZones />} /> <Route path="/meshcore/danger-zones" element={<MeshCoreDangerZones />} />
</Routes> </Routes>
</Layout> </Layout>

View file

@ -3,19 +3,14 @@ import { Link, useLocation, useNavigate } from 'react-router-dom'
import { useDirty } from '@/context/DirtyContext' import { useDirty } from '@/context/DirtyContext'
import { import {
LayoutDashboard, LayoutDashboard,
Radio,
Cloud, Cloud,
BellRing, BellRing,
BookOpen, BookOpen,
Sliders,
Droplets,
MapPin, MapPin,
Map, Map,
Wifi, Wifi,
Layers,
Network, Network,
Users, Users,
Bot,
Settings, Settings,
Calendar, Calendar,
Activity, Activity,
@ -85,14 +80,7 @@ const navGroups: NavGroup[] = [
// Flattened view of every nav item for title lookup. // Flattened view of every nav item for title lookup.
// Also include de-navved routes so they still resolve a title. // Also include de-navved routes so they still resolve a title.
const extraTitleItems: NavItem[] = [ const extraTitleItems: NavItem[] = []
{ path: '/adapter-config', label: 'Adapter Config', icon: Sliders },
{ path: '/gauge-sites', label: 'Gauge Sites', icon: Droplets },
{ path: '/town-anchors', label: 'Town Anchors', icon: MapPin },
{ path: '/mesh', label: 'Mesh', icon: Radio },
{ path: '/meshtastic/sources', label: 'Sources', icon: Layers },
{ path: '/meshcore/companion', label: 'Companion', icon: Bot },
]
const allNavItems: NavItem[] = [ const allNavItems: NavItem[] = [
...navGroups.flatMap((g) => g.items), ...navGroups.flatMap((g) => g.items),
@ -108,7 +96,6 @@ const pathTitles: Record<string, string> = {
'/meshtastic/danger-zones': 'Danger Zones', '/meshtastic/danger-zones': 'Danger Zones',
'/meshcore/danger-zones': 'Danger Zones', '/meshcore/danger-zones': 'Danger Zones',
'/meshcore/contacts': 'Contacts & Companion', '/meshcore/contacts': 'Contacts & Companion',
'/meshcore/companion': 'Contacts & Companion',
} }
function formatUptime(seconds: number): string { function formatUptime(seconds: number): string {

View file

@ -411,8 +411,10 @@ def _refresh_mesh_context(app, new_ctx_cfg) -> bool:
@router.post("/notifications/refresh-toggles") @router.post("/notifications/refresh-toggles")
async def refresh_toggles(request: Request): async def refresh_toggles(request: Request):
"""Explicit refresh endpoint (kept for backwards-compat with the """Explicit refresh endpoint. Not called by the dashboard frontend --
dashboard's manual ping path).""" the _auto_refresh_toggle_filter middleware below already refreshes the
ToggleFilter automatically on every successful notifications config PUT.
Kept for ops/debug use (manually forcing a refresh outside that path)."""
bus = getattr(request.app.state, "bus", None) bus = getattr(request.app.state, "bus", None)
config = getattr(request.app.state, "config", None) config = getattr(request.app.state, "config", None)
if bus is None or config is None: if bus is None or config is None: