Two changes:
1. _request_with_retry: after a session-error re-login, also re-fetch
sites and refresh the client reference so the retry uses valid state.
2. get_aps: if every site fails with an exception, clear the token and
sites cache so the very next page reload triggers a fresh login.
Previously the broken state was sticky until a container restart.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New "Filter .150–.155" button fetches all connected clients via
GET /api/all-clients (one request per site, grouped by AP MAC),
then hides any AP row that has no client with a last-octet IP
between 150 and 155. Clicking again clears the filter.
The name/site search and IP filter compose (AND logic) via a shared
applyFilters() function. Client data is cached in-memory for the
current page session so repeated toggles don't re-fetch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clicking an AP name opens a modal showing all wireless clients currently
associated with that AP: hostname/MAC, IP, SSID, band, channel, signal
strength with quality label, TX/RX link rate, and connection uptime.
Backend: GET /api/ap-clients?mac=&site_key= calls the Omada clients
endpoint with filters.apMac; falls back to client-side filtering if the
controller doesn't support that query param.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
FastAPI/Jinja2 web app for viewing and rebooting TP-Link Omada APs
across all sites. Authentik OIDC auth, SQLite audit log, Docker deploy.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>