Commit Graph
13 Commits
Author SHA1 Message Date
cgasserandClaude Sonnet 4.6 8af2fe75a6 Fix M365 summary: per-product totals row and QWE Client-based missing assignments
- Total row now sums each license column individually instead of using colspan
- Missing Assignment warning now flags licensed users with no QWE Client set,
  replacing the previous department-based company check

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 16:15:56 +02:00
cgasserandClaude Sonnet 4.6 1ec63844ce Add M365 mapping/prices export-import, license pricing, and PDF summary export
- Mapping (Username/QWE Client/IsRestaurant): CSV export and import via new routes
- License prices: persistent DB table (M365LicensePrice), editable price card with auto-save, CSV export/import
- Summary table: Monthly Cost column per client + grand-total row, calculated live in JS from current prices
- PDF export: client-side jsPDF/autotable, landscape A4, includes cost column when prices are set

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 16:05:26 +02:00
cgasserandClaude Sonnet 4.6 adf303ad53 Add M365 License Calculator feature
New top-nav section with a CSV-based license calculator. Upload an Azure AD
user export to see license counts (M365 Standard/Basic, Defender P1, PBI Pro,
PBI Premium) grouped by QWE Client. QWE Client and IsRestaurant are editable
per user, saved to SQLite, and restored on the next upload. Department-based
defaults pre-populate QWE Client (AT→QWE AT, SK→QWE SK) when no saved value
exists.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 15:40:19 +02:00
cgasserandClaude Sonnet 4.6 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
cgasserandClaude Sonnet 4.6 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
cgasserandClaude Sonnet 4.6 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
cgasserandClaude Sonnet 4.6 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
cgasserandClaude Sonnet 4.6 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
cgasserandClaude Sonnet 4.6 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
cgasserandClaude Sonnet 4.6 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
cgasserandClaude Sonnet 4.6 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
cgasserandClaude Sonnet 4.6 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
cgasserandClaude Sonnet 4.6 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