Commit Graph

539 Commits

Author SHA1 Message Date
Louis King 8dc6ccdad0 feat: change default nodes sort to last_seen DESC and add mobile sort controls
- Change API and frontend default sort from name/asc to last_seen/desc
- Add mobileSortSelect() shared component for native select dropdown
- Add mobile sort select to nodes, advertisements, and messages pages
- Add i18n sort labels for all three list pages
- Update sort tests for new default with staggered timestamps
2026-05-05 19:28:28 +01:00
JingleManSweep 73469b714f Merge pull request #191 from ipnet-mesh/renovate/esbuild-0.x
chore(deps): update dependency esbuild to ^0.28.0
2026-05-05 18:43:41 +01:00
renovate[bot] 3bcf691a5a chore(deps): update dependency esbuild to ^0.28.0 2026-05-05 17:41:36 +00:00
JingleManSweep 8cb5253b68 Merge pull request #192 from ipnet-mesh/renovate/node-24.x
chore(deps): update node.js to v24
2026-05-05 18:40:56 +01:00
renovate[bot] a83a228a34 chore(deps): update node.js to v24 2026-05-05 17:32:29 +00:00
JingleManSweep 8b148d2d69 Merge pull request #190 from ipnet-mesh/chore/caching-and-bundling
feat: add esbuild bundling with content-hash cache busting
2026-05-05 18:31:44 +01:00
Louis King 3057a4841b feat: add esbuild bundling with content-hash cache busting
Bundle SPA JavaScript with esbuild for production builds, generating
content-hashed filenames for immutable caching. Vendor assets (Leaflet,
Chart.js, QRCode.js) get SHA256-based query params. Locale JSON files
get a combined hash version. Falls back to unbuiltsources when dist/
is absent.
2026-05-05 18:27:41 +01:00
JingleManSweep cdc4f1810f Merge pull request #189 from ipnet-mesh/chore/sort-nodes-alpha
feat: add clickable sort controls to list pages + alpha sort default for nodes
2026-05-05 17:25:28 +01:00
Louis King 160ba6d5bf feat: add clickable sort controls to list pages with alpha default for nodes
Add sort/order query parameters to Nodes, Advertisements, and Messages
API endpoints. Nodes default to alpha-by-name (via COALESCE of name tag,
node name, public key). Ads and Messages default to newest-first.

Frontend adds sortableTableHeader() component with asc/desc toggle
indicators. Sort state is preserved in URL params, surviving
auto-refresh and pagination.
2026-05-05 17:05:54 +01:00
JingleManSweep 2e41f182be Merge pull request #188 from ipnet-mesh/chore/docs-update-v0.10
fix: correct NODE_CLEANUP_DAYS default and add missing env vars to docs
2026-05-05 14:30:35 +01:00
Louis King 28255261fb fix: correct NODE_CLEANUP_DAYS default from 7 to 30 and add missing env vars to docs
NODE_CLEANUP_DAYS source of truth in Pydantic Settings is 30, not 7. Fixed in README, .env.example, docker-compose.yml, and docker-source-guide.md. Also added missing OIDC_POST_LOGOUT_REDIRECT_URI, WEB_AUTO_REFRESH_SECONDS, NETWORK_DOMAIN to docker-compose.yml web service. Added WEB_LOCALE and WEB_DATETIME_LOCALE to AGENTS.md env vars list.
2026-05-05 14:27:52 +01:00
JingleManSweep 800c67bb1f Merge pull request #187 from ipnet-mesh/chore/ui-fixes-and-daisycss-build
fix: migrate form classes to DaisyUI v5 and redesign home hero buttons
2026-05-05 13:22:29 +01:00
Louis King 9718df3f97 fix: migrate form classes to DaisyUI v5 and redesign home hero buttons
- Replace removed form-control/label-text/label-text-alt with DaisyUI v5
  fieldset/fieldset-label equivalents in node-detail.js and map.js
- Switch JS error display from innerHTML+label-text-alt to
  textContent+classList hidden toggling
- Redesign home hero navigation buttons as square cards with section
  colors, border hover animation, and centered icons
- Move custom page links to a separate row with compact btn-outline style
- Remove deprecated btn-outline CSS overrides from app.css
2026-05-05 13:19:44 +01:00
JingleManSweep d994047203 Merge pull request #186 from ipnet-mesh/chore/improve-filter-options
feat: add observer multi-select and collapsible filters to list pages
2026-05-05 12:25:21 +01:00
Louis King 9af90efee4 feat: add observer multi-select and collapsible filters to list pages
- Add observer multi-select (<select multiple size=2>) to Advertisements and
  Messages filter bars, populated from /api/v1/nodes?observer=true
- Make all filter sections collapsible via <details> on Nodes, Advertisements,
  and Messages pages; collapsed by default, auto-expands when active filters
  exist, preserves open state across auto-refresh ticks
- Add backend observer=true|false query param to GET /api/v1/nodes for
  observer-only or non-observer-only node filtering via subquery
- Change observed_by in Advertisements/Messages API from single public_key
  to list[str] with .in_() for multi-select support
- Fix router.js and api.js to handle array query params (duplicate keys
  promoted to arrays, .append() per element)
- Fix createFilterHandler to use FormData.getAll() for multi-value support
- Replace DaisyUI form-control/label/label-text classes with Tailwind-native
  equivalents (flex flex-col gap-1, flex items-center py-1, opacity-80 text-sm)
  since DaisyUI CSS is tree-shaken from the build output
- Thicker collapsible border (border-2 border-base-content/25) visible in
  both light and dark themes
- Bottom-align Filter/Clear buttons via two-row form layout
- Move Observer filter to last position on Advertisements page
- Add filter_observer_label i18n key
- Add tests for observer=true node filtering and multi observer params
2026-05-05 12:22:52 +01:00
JingleManSweep 98efc9dd06 Merge pull request #185 from ipnet-mesh/chore/ui-fixes
fix: resolve mobile UI issues on members page and node detail
2026-05-04 11:02:35 +01:00
Louis King b84cc8894f fix: resolve mobile UI issues on members page and node detail
- Replace nested <a> tags in member cards with @click handlers to fix
  invalid HTML causing missing badge styles and double-navigation
  race conditions (NS_BINDING_ABORT) on mobile
- Add e.preventDefault() to @click handlers to prevent parent <a>
  activation
- Bump mobile dropdown z-index from z-[1] to z-50 so menu items
  render above QR code wrapper (z-20) on node detail hero section
- Blur active element after SPA navigation to dismiss DaisyUI
  :focus-within dropdown state
- Fix dashboard channel messages to show short date+time format
- Add overflow-x-auto to custom pages and node detail panels for
  mobile overflow
- Fix tag editor: hide type column on mobile, truncate key/value
  cells, show key in modal title instead of disabled input field
- Fix delete tag dialog using innerHTML for <strong> in i18n strings
- Fix tag add form not resetting after successful submit
- Add break-word and overflow-x-auto to prose tables in app.css
2026-05-04 11:00:04 +01:00
JingleManSweep ddbbe05e54 Merge pull request #184 from ipnet-mesh/feature/inline-node-tag-editor
feat: replace admin tag page with inline node tag editor
2026-05-03 21:28:29 +01:00
Louis King 27b9ec21f2 feat: replace admin tag page with inline editor on node detail
Replace the dedicated admin tag management page with inline tag editing
on the node detail page. Operators can now edit tags directly on nodes
they've adopted; admins retain unrestricted access.

Key changes:
- Remove admin SPA page (admin/index.js, admin/node-tags.js)
- Add inline tag editor to node-detail.js with add/edit/delete modals
- Replace RequireAdmin with RequireOperatorOrAdmin for tag API routes
- Add ownership check: operators restricted to adopted nodes only
- Add validate_and_coerce_tag_value for number/boolean coercion
- Remove unused bulk endpoints (copy, move, replace all)
- Use AbortController for event listeners to prevent accumulation
  on lit-html DOM reuse across re-renders
- Track Leaflet map instance at module scope for defensive cleanup
- Fix checkAuthResponse to only redirect on 401 (not 403)
- Update tests for new OIDC-based auth model
- Update en.json locale, i18n.md, upgrading.md, AGENTS.md
2026-05-03 21:25:53 +01:00
JingleManSweep 3b99aa1daf Merge pull request #183 from ipnet-mesh/chore/refactor-infra-node-handling
feat: replace role=infra tag with adoption-based infrastructure detection
2026-05-03 19:05:17 +01:00
Louis King 560eb0796a feat: replace role=infra tag with adoption-based infrastructure detection
Replace the role=infra NodeTag convention with UserProfileNode adoption
as the canonical infrastructure indicator across map, Prometheus metrics,
and alerting. Renames is_infra to is_adopted, infra_center to
adopted_center. Map icons change to blue (adopted) / green (normal),
with all adoption UI gated on OIDC_ENABLED. Adds meshcore_nodes_adopted
gauge and Alembic migration to clean up obsolete tags.
2026-05-03 19:02:05 +01:00
JingleManSweep c05518c7b9 Merge pull request #182 from ipnet-mesh/chore/ui-tweaks
feat: user profile description/url + members hero link + profile layout fix
2026-05-03 00:08:49 +01:00
Louis King 2309428ce7 fix: remove btn-bg override so members hero button hover matches border color 2026-05-03 00:04:04 +01:00
Louis King c1e27fe63e feat: add members link to homepage hero, fix profile callsign layout
- Add Members button to homepage hero after Messages, using
  --color-members palette for icon and border color
- Gated by features.members !== false (auto-disabled when
  OIDC_ENABLED=false via existing server-side override)
- Move callsign badge inline with name in profile view,
  matching Members card layout
2026-05-02 23:58:29 +01:00
JingleManSweep a450531270 Merge pull request #181 from ipnet-mesh/chore/ui-tweaks
feat: add description and url fields to user profiles, fix nullable field clearing
2026-05-02 23:35:45 +01:00
Louis King f2ea530c0f feat: add description and url fields to user profiles, fix nullable field clearing
- Add description (Text) and url (String 2048) columns to user_profiles
- Expose in all API schemas (Read, Public, Update, ListItem) and list/get/profile endpoints
- Update profile.js form: add description/url inputs, render on view page
- Update members.js: render description and URL link in member tiles
- Fix update handler: use model_dump(exclude_unset=True) for nullable fields
  while protecting name (set by IdP) from being cleared
- AnyUrl validation on update, converted to str for SQLite compatibility
- Add i18n keys (description_label/placeholder, url_label/placeholder)
- 7 new API tests covering description/url CRUD, URL validation, null-clearing,
  and name non-nullability
2026-05-02 23:33:25 +01:00
Louis King db1a6aa3d5 Link adopted-by user name to profile page on node detail
Add profile_id to AdoptedByUser API schema and populate it from
the backend so the SPA can link the adopter's name to their
/profile/{id} page. Style the link with text-primary to stand out
from the surrounding opacity-70 text.
2026-05-02 19:06:50 +01:00
JingleManSweep a358363c2f Merge pull request #180 from ipnet-mesh/chore/ui-refactoring
Refactor SPA frontend: eliminate inline SVGs, extract shared components
2026-05-02 16:55:31 +01:00
Louis King 5a8160da0e Refactor SPA frontend: eliminate inline SVGs, extract shared components and templates
- Add 4 missing icons to icons.js (iconSettings, iconLogout, iconPause, iconPlay)
- Replace 13 inline SVGs with icons.js functions across 5 files
- Remove 3 raw-string SVG helpers from components.js
- Rewrite renderAuthSection() to lit-html (was innerHTML)
- Add renderFilterCard() and renderStatCard() to components.js
- Adopt renderFilterCard() in nodes, messages, advertisements pages
- Extract sub-renderers from home.js (hero, stats, activity chart)
- Extract 5 modal dialogs from admin/node-tags.js
- Use renderStatCard() in home.js and dashboard.js
- Extract renderChartCards() helper from dashboard.js
2026-05-02 16:52:09 +01:00
JingleManSweep 4c4c2b4823 Merge pull request #179 from ipnet-mesh/feature/auth-improvements
Auth improvements: OIDC-gated member filter, profile page fixes, members refactor
2026-05-02 14:48:25 +01:00
Louis King 486178a471 Add OIDC-gated member filter to Nodes/Advertisements/Map pages, fix profile page issues
- Add member filter dropdown to Nodes, Advertisements, and Map pages
  (visible only when OIDC is enabled), showing profiles as
  "Name (Callsign)" format
- Add adopted_by query param to /map/data endpoint for server-side
  member filtering on the map
- Fix members feature flag: auto-disables when OIDC is disabled
- Fix profile page: remove duplicate adopted nodes section,
  extract renderMemberSince(), align form labels with fixed-width
  label column
- Add i18n keys: common.all_members, common.filter_member_label
- Add map endpoint adopted_by tests, update features tests
2026-05-02 14:43:55 +01:00
Louis King f42cf92664 Fixed map JS error 2026-05-01 00:22:24 +01:00
Louis King d37b30a05b Replace Member model with UserProfile-backed data
Remove the static Member model/table, CRUD API, YAML seed files, and
admin UI. Replace with UserProfile-driven members page that reads roles
from OIDC identity provider. Key changes:

- Drop members table, add roles column to user_profiles (Alembic migration)
- Add GET /api/v1/user/profiles (paginated, no user_id exposed)
- Add GET /api/v1/user/profile/me (auto-creates profile for current user)
- Replace member_id node tag filter with adopted_by (profile UUID)
- Members page now shows profiles grouped by operator/member roles
- Profile page supports public view (/profile/:id) and owner edit (/profile)
- Node detail page shows adoption card side-by-side with public key card
- Auto-create user profile during OIDC login callback
- Hide Adopted Nodes section for non-operator/admin users
- Add member since date to profile cards
- Add role badges and adopted node badges to member tiles
- Add antenna/users icons to Members page group headers
2026-04-30 20:57:26 +01:00
Louis King 378f04d183 Hide admin UI when OIDC is disabled 2026-04-30 00:56:55 +01:00
Louis King 38c792196f Auto-populate user profile name from IdP on first access
Proxy now injects X-User-Name header from session. Profile auto-creation
uses it as the initial name value. Existing profile names are never
overwritten.
2026-04-30 00:23:16 +01:00
Louis King 31418e6847 Add user profiles with node adoption via /v1/adoptions endpoint
Move adopt/release from profile routes to dedicated /v1/adoptions endpoint.
Node API now returns adopted_by field. Profile page shows read-only adopted
nodes. Node detail page has adopt/release buttons (operator adopts, admin
can release any). Admin release bypasses ownership check.
2026-04-30 00:07:49 +01:00
JingleManSweep 6a5a23845f Merge pull request #178 from ipnet-mesh/feature/oidc-oauth-support
Add OIDC/OAuth2 authentication for web dashboard
2026-04-29 12:57:58 +01:00
Louis King a14dbaec45 Add OIDC authentication section to README before Webhooks 2026-04-29 12:55:40 +01:00
Louis King a37971b05c Add docs/auth.md and update documentation cross-references
- Create docs/auth.md covering OIDC architecture, login flow, configuration,
  local development setup, and LogTo provider guide
- Remove direnv-specific quoting note from .env.example
- Clarify OIDC_DISCOVERY_URL auto-appends .well-known/openid-configuration
- Fix admin route references from /a/ to /admin/
- Add auth.md links to README.md and AGENTS.md doc lists
- Add docs/auth.md to AGENTS.md documentation sync rule
2026-04-29 12:50:50 +01:00
Louis King 2cb7a96294 Use replace mode for admin form handler navigations to prevent stale page
When form handlers navigate to the same URL (e.g. adding two tags in a row
produces the same &message=... URL), the router's same-URL check skipped
the re-render. Using replace=true bypasses the check and avoids polluting
browser history with repeated flash-message entries.
2026-04-29 00:50:55 +01:00
Louis King 2af8b281ea Add OPTIONS to API proxy, fix admin event listener accumulation, rename admin routes from /a/ to /admin/
- Add OPTIONS to the web API proxy route methods for CORS preflight support
- Fix event listener accumulation in admin/node-tags.js and admin/members.js
  using AbortController with cleanup functions returned to the SPA router.
  lit-html reuses DOM elements across re-renders, causing addEventListener
  calls to accumulate and fire multiple times per form submission.
- Rename admin routes from /a/ prefix to /admin/ for clarity
- Add debug logging for admin route access and OIDC role checks
- Move auth section in navbar after theme toggle
- Update tests and AGENTS.md accordingly
2026-04-29 00:45:45 +01:00
Louis King d1b6f0d0a7 Fix OIDC logout redirect and username display for LogTo
- Pass client_id in logout redirect so LogTo can validate post_logout_redirect_uri
- Add OIDC_POST_LOGOUT_REDIRECT_URI config option with fallback derivation
- Move session.clear() after logout_redirect() to allow state data save
- Add 'username' to strip_userinfo() name fallback chain (LogTo uses this)
- Strip quotes from OIDC_SCOPES and pass as list to Authlib (fixes direnv
  quoting issue where literal quotes were sent in the authorization URL)
- Add OIDC_POST_LOGOUT_REDIRECT_URI to config, app state, and docs
- Add INFO-level logging to callback and logout handlers for diagnostics
- Update .env.example, README.md, AGENTS.md, docs/upgrading.md
2026-04-28 22:44:01 +01:00
Louis King 02c0a8f1b7 Add OIDC/OAuth2 authentication via Authlib
Replace WEB_ADMIN_ENABLED with full OIDC support using Authlib.
Admin access now requires authenticated sessions with IdP-assigned
roles instead of an open toggle.

- Add authlib and itsdangerous dependencies
- Add OIDC settings to WebSettings (13 env vars)
- Create web/oidc.py module (OAuth registry, session helpers)
- Add /auth/login, /auth/callback, /auth/logout, /auth/user routes
- Gate API proxy writes to admin sessions when OIDC enabled
- Protect /a/ routes with session check (redirect to login)
- Add SessionMiddleware for signed session cookies
- Add renderAuthSection navbar component (login/avatar dropdown)
- Add 401/403 interceptor in api.js for auto-redirect
- Exclude /auth/ from SPA client-side router interception
- Render auth section after translations load (fixes raw key display)
- Add custom error pages for 500s (standalone HTML, no JS deps)
- Update docker-compose.yml to pass OIDC_* env vars to web container
- Update .env.example, README, AGENTS.md, upgrading.md, i18n.md
- Add auth.* and errors.* i18n keys
- Add 200 tests (OIDC, admin, error pages)
2026-04-28 17:36:44 +01:00
JingleManSweep 963dabbbd5 Merge pull request #177 from ipnet-mesh/chore/remove-header-auth-pattern
Remove header-based auth (ProxyHeadersMiddleware, is_authenticated config, OAuth2 SPA flows)
2026-04-28 13:36:47 +01:00
Louis King 9873aa202b Remove header-based auth (ProxyHeadersMiddleware, is_authenticated config, OAuth2 SPA flows)
Remove the reverse-proxy header authentication pattern (X-Forwarded-User,
X-Auth-Request-User, Basic auth forwarding) from the web dashboard. Admin
access is now controlled solely by the WEB_ADMIN_ENABLED flag.

- Remove web_trusted_proxy_hosts config field and ProxyHeadersMiddleware
- Remove _is_authenticated_proxy_request() and api_proxy() 401 guard
- Remove is_authenticated from SPA config JSON
- Remove OAuth2 login/sign-out UI from admin pages and router
- Remove auth_required i18n keys (en, nl)
- Remove auth-related tests and fixtures
- Delete docs/hosting/nginx-proxy-manager.md
- Update README, AGENTS.md, .env.example, docs/i18n.md, agents docs-sync refs

572 tests pass, pre-commit clean.
2026-04-28 13:33:52 +01:00
JingleManSweep 2cc76b853b Merge pull request #176 from ipnet-mesh/chore/observer-ux-tweaks
Update observer table: SNR/Path headers and value suffix cleanup
v0.9.2
2026-04-26 14:53:07 +01:00
Louis King 51d7de9d88 Update observer table: SNR/Path headers and value suffix cleanup
- Rename SNR header to 'SNR (dB)', Path header to 'Hops'
- Remove ' dB' and ' hop/s' suffixes from column values
- Add i18n keys for snr_db and hops to en.json and docs/i18n.md
- Fix README ARM note: only 32-bit ARM unsupported, RPi 3/4/5 work
2026-04-26 14:50:28 +01:00
JingleManSweep 8139cbc17e Merge pull request #175 from ipnet-mesh/chore/fix-network-error-display
Preserve table content on API errors with header warning badge
2026-04-26 14:05:37 +01:00
Louis King 8dec688917 Preserve table content on API errors with header warning badge
Instead of replacing the entire table with an error alert on network
failures, the previous data now stays visible and a warning icon with
tooltip appears in the sub-header bar. The warning clears automatically
on the next successful poll.

Restructured page headers into title row + sub-header row (count,
auto-refresh, warning) for better mobile layout.
2026-04-26 14:03:26 +01:00
JingleManSweep e4655a6b59 Merge pull request #174 from ipnet-mesh/feature/improve-snr-path-visibility
Add observer detail rows with SNR/path data and UI polish
2026-04-26 13:05:10 +01:00