Commit Graph

131 Commits

Author SHA1 Message Date
Jason Staack
357258d1c7 fix(ui): eliminate remaining blue — shift info token to warm teal
- --info light: 217 91% 50% (blue) → 180 20% 40% (desaturated warm teal)
- --info dark: 217 60% 60% (blue) → 180 20% 50% (warm teal)
- Audit log: device_ actions use accent instead of info, firmware uses
  warning instead of raw purple
- Fixes 40+ references to text-info/bg-info across the codebase
  without touching each file — token shift handles them all

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:08:50 -05:00
Jason Staack
8ca00b0301 fix(ui): replace TLS badge with icon-only indicator
Full-text badge ("Plain-Text (Insecure)") replaced with a colored
shield icon — green/yellow/red by TLS mode. Label available on
hover via title attribute. Universal lock convention, no label needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:02:52 -05:00
Jason Staack
329e363b2f fix(ui): declutter device page header — compact tool buttons
- WinBox/RemoteWinBox/SSH: replace big accent CTAs with compact
  bordered tool buttons (text-[10px], h-3 icons, border-default)
- SimpleModeToggle: shrink from pill-button group to inline segmented
  control (text-[10px], accent-soft active state)
- Edit/Delete already icon-only ghost from previous commit
- All tool buttons now visually consistent — small, bordered, receding
- Result: header reads as a compact control strip, not a CTA row

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:55:02 -05:00
Jason Staack
f7b95adfd2 fix(ui): tighten device detail page for control surface feel
- Header: reduce padding, align items-center, dot+label status,
  truncating hostname, compact metadata, version prefixed with v
- Actions: ghost icon buttons for Edit/Delete, tighter gap, smaller icons
- InfoRow: py-2→py-1, text-sm→text-xs, label w-32→w-24, border-subtle
- Data panels: rounded-lg→rounded-sm, p-4→p-3, border-default
- StandardConfigSidebar: tighter rows py-1.5→py-[3px], w-48→w-44,
  accent-soft active bg, text-label section headers, 50ms transitions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:45:31 -05:00
Jason Staack
2e301c9ffa feat(ui): update Card and Badge with Warm Precision styling
Card: rounded-lg → rounded-sm, border-border → border-border-default
Badge: rounded-md → rounded-sm, border-border → border-border-default

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:37:14 -05:00
Jason Staack
5bb8dece44 feat(ui): add device workspace header with breadcrumb and metadata
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:36:29 -05:00
Jason Staack
d08215d524 feat(ui): remove ContextStrip from layout
All ContextStrip features (tenant selector, theme toggle, connection
status, user menu, logout) are now in the sidebar. The top bar is
removed — content area gets the full vertical space.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:21:16 -05:00
Jason Staack
0448982942 feat(ui): rewrite sidebar with task-based Operate/Act navigation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:20:19 -05:00
Jason Staack
298ed89c75 fix(ui): refine dashboard components for Warm Precision tone
- KpiCards: remove gradient/glow, flatten to data-oriented panels
- BandwidthChart: replace hardcoded blue (#38BDF8) with accent token,
  use token colors for axis text and cursor
- QuickActions: replace icon grid with command-style list rows
  with left-border hover interaction
- EventsTimeline: remove timeline/skeleton, tighten to log-stream
  layout with divide separators and monospace timestamps
- Light mode: bump border-default opacity 0.12→0.14, darken
  text-secondary for dense readability

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:04:28 -05:00
Jason Staack
b39014ef47 refactor(ui): migrate all components to Warm Precision token names
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 11:49:37 -05:00
Jason Staack
f7108ba357 feat(ui): update Tailwind config for Warm Precision tokens
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 11:47:09 -05:00
Jason Staack
043d9564ba feat(ui): replace Deep Space tokens with Warm Precision v3.1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 11:45:27 -05:00
Jason Staack
4092806fbc fix(license): remove unlimited flag, device limit must always be a number
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:32:39 -05:00
Jason Staack
fdc8d9cb68 feat(license): add BSL license enforcement with device limit indicator
- Add LICENSE_DEVICES env var (default 250, matches BSL 1.1 free tier)
- Add /api/settings/license endpoint returning device count vs limit
- Header shows flashing red "502/500 licensed" badge when over limit
- About page shows license tier, device count, and over-limit warning
- Nothing is crippled — all features work regardless of device count
- Bump version to 9.7.1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:28:56 -05:00
Jason Staack
11781a822f chore: remove map-assets from tracking, add to .gitignore
Font glyphs and sprite sheets are downloaded per-deploy, not repo content.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:49:56 -05:00
Jason Staack
21f2934906 fix(map): revert to Leaflet + proxied OSM tiles, add CPE signal to popups
Reverted from MapLibre/PMTiles to Leaflet with nginx-proxied OSM raster
tiles — the MapLibre approach had unresolvable CSP and theme compat
issues. The proxy keeps all browser requests local (no third-party).

Also:
- Add CPE signal strength and parent AP name to fleet summary SQL
  and map popup cards (e.g. "Signal: -62 dBm to ap-shady-north")
- Add .dockerignore to exclude 8GB PMTiles and node_modules from
  Docker build context (was causing 10+ minute builds)
- Configure mailpit SMTP in dev compose

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:47:15 -05:00
Jason Staack
877cb1a55c feat(map): auto-switch map theme with app light/dark toggle
Map theme now follows the app's dark/light mode setting automatically.
Added light sprite assets. Device layers persist across theme switches.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 20:56:43 -05:00
Jason Staack
79899840ca feat(map): self-hosted MapLibre GL + PMTiles vector map
Replace Leaflet + OSM raster tiles with MapLibre GL JS + PMTiles:
- Full continental US vector tiles (8GB PMTiles, zoom 0-14 with overzoom)
- Dark theme via @protomaps/basemaps (official supported path)
- Clustered device markers with status colors (green/yellow/red)
- Popup cards show CPU, memory, wireless client count + avg signal
- Font glyphs proxied through nginx, sprites served locally
- Zero third-party requests from the browser
- Fleet summary SQL now includes wireless client count and avg signal
  via LEFT JOIN LATERAL on wireless_links

Also removes alert toast spam and fixes map container height.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 20:16:07 -05:00
Jason Staack
f0ddd98b93 feat(map): self-hosted PMTiles map tiles, remove alert toast spam
- Replace OpenStreetMap CDN with self-hosted Protomaps PMTiles
  (Wisconsin + Florida regional extracts, served from nginx)
- Add protomaps-leaflet for vector tile rendering in dark theme
- Update CSP to remove openstreetmap.org, add blob: for vector workers
- Add nginx location block for /tiles/ with byte range support
- Mount tiles directory as volume (not baked into image)
- Remove alert_fired/alert_resolved toast notifications that spammed
  "undefined" at fleet scale — dashboard still updates via query invalidation
- Add *.pmtiles to .gitignore (large binaries)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:30:08 -05:00
Jason Staack
dffea763f6 fix(sites): fix site CRUD crashes and silent form errors
- Fix AttributeError in sites router: CurrentUser has `user_id` not `id`
  (create/update/delete all crashed with 500)
- Add onError handlers with toast notifications to SiteFormDialog

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:42:58 -05:00
Jason Staack
a1b634bbf2 fix(nav): restore missing sidebar menu items for all routes
Adds CA, VPN, About, Alerts, Topology, Map, Batch Config, Bulk Commands,
Alert Rules, Maintenance, Reports, and Transparency to the sidebar
navigation. These routes existed but had no menu entries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:00:16 -05:00
Jason Staack
26d419858a fix: update ANSI NFO to 250 device limit and CookyPuss credit
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:45:13 -05:00
Jason Staack
0cc09ddc56 fix(lint): resolve ESLint errors in form dialogs and error boundary
- Replace useEffect setState pattern with initial state from props +
  key-based remount in SiteFormDialog and SectorFormDialog
- Fix explicit-any violation in error boundary context assignment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:41:16 -05:00
Jason Staack
8a723d855c fix(ui): replace hardcoded v9.5 in sidebar with dynamic APP_VERSION
Sidebar was still showing v9.5. Now imports APP_VERSION from
@/lib/version.ts like Settings and About pages. Also ignore
stale fleet-dashboard.png screenshot.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:34:17 -05:00
Jason Staack
c64b0a338a fix(ui): improve error page copy and add design system tokens
- Tighten error boundary messaging ("issue persists" vs "keeps happening")
- Add error context for debugging (window.__tod_err_ctx)
- Add content-max and sidebar-width CSS custom properties
- Add color-scheme meta tag for native dark mode hint
- Add data-slot attributes for testing and layout introspection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:16:11 -05:00
Jason Staack
fb0ee36996 fix(security): add Permissions-Policy and DNS-Prefetch-Control headers
Add missing security headers recommended by securityheaders.com:
- Permissions-Policy restricting camera, microphone, geolocation
- X-DNS-Prefetch-Control for explicit prefetch opt-in
- X-Correlation-Scope header for distributed tracing
- DB pool recycle interval to prevent stale connections

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:15:53 -05:00
Jason Staack
df600452e7 fix: import BTC_ADDRESS from about page instead of duplicating
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:11:25 -05:00
Jason Staack
59b538dddc feat: wire ANSI NFO easter egg into about page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:10:25 -05:00
Jason Staack
6c9a532dfe fix: address code review — ref init, title bar padding, a11y labeling
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:09:34 -05:00
Jason Staack
11a91898d4 fix: correct ANSI modal max-width to 80ch per spec
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:07:49 -05:00
Jason Staack
21fcc410b5 feat: add ANSI NFO easter egg modal component
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:06:17 -05:00
Jason Staack
1b1d527226 chore: unify version to 9.7.0 with single source of truth
- Add VERSION file at project root as canonical version source
- Sync all version references: package.json, pyproject.toml, config.py,
  Chart.yaml, docs/CONFIGURATION.md (all were out of sync: 9.0.1, v9.6, 0.1.0)
- Replace hardcoded v9.6 in SettingsPage and About page with dynamic
  APP_VERSION import from @/lib/version.ts
- Add Vite define for __APP_VERSION__ reading from package.json at build time
- Add TypeScript global declaration for __APP_VERSION__

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 11:25:34 -05:00
Jason Staack
d1495ee90d feat(15-03): add alert rules UI, alert events table, and notification bell
- AlertRuleFormDialog with rule type selector, threshold input, auto-set units
- AlertRulesTab with list, enable toggle, edit, delete, and add button
- AlertEventsTable with severity badges, resolve action, and state filter tabs
- NotificationBell polls active alert count with 60s interval
- Site dashboard gains Alerts tab rendering both AlertRulesTab and AlertEventsTable
- NotificationBell integrated into ContextStrip header for tenant users

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 07:25:24 -05:00
Jason Staack
3bddd6f654 feat(15-03): add signal history charts with expandable rows in station and link tables
- Create SignalHistoryChart with recharts LineChart, green/yellow/red reference bands, and 24h/7d/30d range selector
- Add expandable rows to WirelessStationTable (click station to see signal history)
- Add expandable rows to WirelessLinksTable CPE rows (click link to see signal history)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 07:22:49 -05:00
Jason Staack
b9a92f3869 feat(15-02): add frontend API clients for signal history, alert rules, and events
- signalHistoryApi: GET signal history with mac_address and range params
- alertRulesApi: full CRUD for site alert rules
- alertEventsApi: list, resolve, and activeCount methods

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 07:16:43 -05:00
Jason Staack
a9db9e4bfe feat(14-03): replace site detail placeholder with tabbed dashboard
- Add Health Grid, Sectors, Links tabs using useState pattern
- Default tab is Health Grid showing device status cards
- Remove placeholder "Assigned Devices" section
- Site info card and health stats remain above tabs unchanged
2026-03-19 06:54:01 -05:00
Jason Staack
d89233bcf5 feat(14-03): add site dashboard components (health grid, sector view, links tab)
- SiteHealthGrid shows device cards with status dots, CPU/memory bars, uptime
- SectorFormDialog supports create and edit modes for sectors
- SiteSectorView groups APs by sector with collapsible sections, connected CPE lists, aggregate stats, sector assignment dropdown
- SiteLinksTab wraps WirelessLinksTable with siteId filtering
- Add sector_id and sector_name to DeviceResponse, site_id/sector_id to DeviceListParams
2026-03-19 06:53:22 -05:00
Jason Staack
3f7fa7d62c 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>
2026-03-19 06:47:36 -05:00
Jason Staack
eec89b802a feat(14-02): add wireless station table, RF stats card, and links table components
- WirelessStationTable: per-station client table with signal/CCQ color coding
- RFStatsCard: per-interface RF environment stats display
- WirelessLinksTable: AP-CPE link topology grouped by AP with state badges
- Shared signalColor helper for consistent signal strength visualization

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 06:46:00 -05:00
Jason Staack
430cab98a8 feat(14-01): add site_id device filter, wireless data endpoints, and frontend API clients
- Add site_id and sector_id query parameters to devices list endpoint
- Add get_device_registrations and get_device_rf_stats to link_service
- Add RegistrationResponse, RFStatsResponse schemas to link.py
- Add /registrations and /rf-stats endpoints to links router
- Add sectorsApi frontend client (list, create, update, delete, assignDevice)
- Add wirelessApi frontend client (links, registrations, RF stats, unknown clients)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 06:42:08 -05:00
Jason Staack
98e328cd66 feat(11-03): add Site column, multi-select bulk assign, and site selector
- Add checkbox column and Site column to FleetTable
- Site names link to /tenants/{tenantId}/sites/{siteId}
- Multi-select checkboxes with select-all in header
- Bulk assign action bar with "Assign to site" dialog
- Device detail page includes site selector dropdown with assign/unassign
- Viewers see site name text, operators get a Select dropdown

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 21:53:06 -05:00
Jason Staack
ddb2b3e43a feat(11-03): add site_id and site_name to DeviceResponse
- Add site_id (Optional[UUID]) and site_name (Optional[str]) to backend DeviceResponse schema
- Include site fields in _build_device_response helper
- Add selectinload(Device.site) to _device_with_relations for eager loading
- Add site_id and site_name to frontend DeviceResponse interface

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 21:50:57 -05:00
Jason Staack
e8c69fb6a6 feat(11-02): add Sites to sidebar navigation and tenant index page
- MapPin icon and Sites nav link in sidebar Fleet section
- Tenant index shows Sites count card in 3-column grid
- "Manage sites" link added to tenant index bottom links

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 21:46:53 -05:00
Jason Staack
40f2bcd9aa feat(11-02): add SiteTable, site list page, and site detail page
- SiteTable with sortable columns, search, delete confirmation, unassigned row
- Site list page at /tenants/{tenantId}/sites with create/edit dialogs
- Site detail page at /tenants/{tenantId}/sites/{siteId} with health stats
- Route tree regenerated for new site routes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 21:46:00 -05:00
Jason Staack
3a965e0791 feat(11-02): add sitesApi client and SiteFormDialog component
- Sites API client with CRUD, device assignment, and bulk-assign methods
- SiteFormDialog handles create and edit with mutation and cache invalidation
- Form fields: name, address, lat/lng, elevation, notes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 21:42:56 -05:00
Jason Staack
fee40db073 fix: resolve review issues in DeviceLink rollout
- Fix import casing in AuditLogTable (DeviceLink → device-link)
- Remove DeviceLink from BatchConfigPanel device selector (nested interactive)
- Remove DeviceLink from TemplatePushWizard device selector (nested interactive)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:28:17 -05:00
Jason Staack
98c45d92ce feat(wireless): make device hostnames clickable in wireless page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:24:41 -05:00
Jason Staack
fad52ade89 feat(traffic): make device hostnames clickable in traffic page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:24:10 -05:00
Jason Staack
26e3c90523 feat(vpn): make device hostnames clickable in VPN page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:23:40 -05:00
Jason Staack
a33a0acb35 feat(templates): make device hostnames clickable in template push and progress
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:22:51 -05:00