10 Commits

Author SHA1 Message Date
b6082e2c60 Fix stale session causing persistent empty AP list
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>
2026-04-28 09:11:55 +02:00
d7d2af7b9b Default sort: AP list by Name, client popup by IP
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 16:22:52 +02:00
d61347e998 Default sort by IP address on page load
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 16:17:58 +02:00
ae8c07b759 Add sortable columns for Name, Site, IP Address
Clicking a column header sorts ascending; clicking again reverses to
descending. Active column shows ↑/↓ in blue; inactive columns show ↕
in gray. IP addresses are compared numerically (octet by octet) so
.9 sorts before .10. Sort composes with the name filter and IP filter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 16:00:00 +02:00
139499839f Fix IP filter to check connected client IPs
Fetches clients for every AP in parallel using the existing /api/ap-clients
endpoint, then keeps only APs where at least one client has an IP with last
octet 150–155. Shows a loading spinner while fetching.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:55:49 +02:00
b455b2fd15 Fix IP filter to check AP's own IP from DOM
Previous implementation fetched connected client IPs via API (which was
returning empty data). The filter now checks the AP's own management IP
directly from the data already in the table — no network request, instant.

An AP is shown when its IP last octet is between 150 and 155 inclusive.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:51:43 +02:00
d693321ba1 Add IP range filter button (.150–.155)
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>
2026-04-27 15:48:50 +02:00
1041777b9a Lock reboot button permanently after confirm
After confirming a reboot (single or bulk), the row button and checkbox
are immediately disabled and can't be re-triggered in the current session.
Button text changes to "Rebooting…" while the request is in flight, then
"Rebooted" on success or "Failed" on error — but stays disabled either way.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:43:41 +02:00
47f553f410 Add connected clients popup per AP
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>
2026-04-27 15:13:05 +02:00
284924e86d Initial release — Salus by Stranto v1.6.1.0
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>
2026-04-27 14:36:02 +02:00