Each alert toast had a 5-second auto-dismiss timer that fired even
while the user was reading the card. This adds pause-on-hover: the
dismiss timer stops while the mouse is over a toast and restarts (full
lifetime) on mouse leave. The progress bar animation pauses with it,
so the visual matches the actual remaining time.
All other behavior is preserved: same cyber/mono styling, same spring
slide-in, same risk-color border + glow, same warning icon, same
LVL X/10 readout, same title/source layout, same click-to-fly + dismiss
on body click, same × dismiss button.
Implementation notes:
- Extract a ToastCard sub-component so each card can own its own
paused state (useState can't be array-indexed in the parent).
- Move the auto-dismiss timer out of useAlertToasts.ts and into
ToastCard. The hook previously scheduled the dismiss itself, which
meant the UI couldn't pause it — only the component knows whether
the user is interacting.
- Add tests covering: title/source/severity render, auto-dismiss
fires at 5s, hover pauses indefinitely, mouse-leave restarts the
full lifetime, × dismisses without flying, body-click flies +
dismisses.
This implements the genuine UX improvement that PR #234 was reaching
for, without #234's broken syntax, missing-field bug, duplicate
timer logic, or design regression.
Refs: #234
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Allow local-operator DM invite import without requiring a full admin session.
Prioritize bundled/bootstrap seed peers and shorten stale seed cooldowns for faster Infonet recovery.
Replace raw DM invite dumps with copyable signed-address controls, contact request handling, and safer sealed-send behavior while the private delivery route connects.
Ship the v0.9.79 runtime refresh with transport lane isolation, Infonet secure-message address management, MeshChat MQTT controls, selected asset trail behavior, telemetry panel refinements, onboarding updates, and desktop/package metadata alignment.
Also ignore local graphify work products so analysis folders do not leak into future commits.
Add Tor/onion runtime wiring and faster Infonet node status refresh.
Keep node bootstrap state clearer across Docker and local runtimes.
Use selected aircraft trail history for cumulative tracked-aircraft emissions.
Reduce cold-start stalls by raising the default backend memory limit, bounding heavy feed concurrency, preserving non-empty startup caches, and refreshing working news feeds. Fix the Next API proxy for Docker control-plane writes by stripping unsupported hop/body headers and forwarding small request bodies safely. Keep the dashboard dynamic so production users do not get stuck on a cached startup shell.
Let fresh Docker and local installs enter OpenSky, AIS, and other provider keys directly in onboarding or Settings without manually creating .env files. Persist keys server-side in the backend data store, keep them write-only from the browser, reload runtime settings, and retain local-operator access controls.
Allow the bundled Docker frontend proxy to reach local-operator endpoints through the private compose bridge without trusting LAN clients. This restores Time Machine, MeshChat key creation, AI pins/layers, and related local controls in Docker installs. Refresh first-run guidance so Docker users know to configure OpenSky and AIS keys through .env.
Render the app shell dynamically so Next can attach per-request CSP nonces to its production scripts, preventing Docker from serving a static shell that cannot hydrate. Also gives the first-contact warmup test enough time in CI.
Skip the Secure flag on the session cookie when the request comes from
a loopback address (localhost, 127.0.0.1, ::1). The Docker image sets
NODE_ENV=production which always enabled Secure, but browsers silently
drop Secure cookies on plain HTTP — breaking the admin panel for
self-hosted users accessing http://localhost:3000.
Fixes#129
- Increase gap between alert boxes from 6px to 12px
- Use weighted repulsion so high-risk alerts stay closer to true position
- Reduce grid cell height for better overlap detection (100→80px)
- Double max iterations (30→60) for dense clusters
- Increase max offset from 350→500px for more spread room
- Fix box height estimate to match actual rendered dimensions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Server-Sent Events endpoint at GET /api/mesh/gate/stream that
broadcasts ALL gate events to connected frontends (privacy: no
per-gate subscriptions, clients filter locally)
- Hook SSE broadcast into all gate event entry points: local append,
peer push receiver, and pull loop
- Reduce push/pull intervals from 30s to 10s for faster relay sync
- Add useGateSSE hook for frontend EventSource integration
- GateView + MeshChat use SSE for instant refresh, polling demoted
to 30s fallback
Latency: same-node instant, cross-node ~10s avg (was ~34s)
- Add FINNHUB_API_KEY to docker-compose.yml so financial ticker works
in Docker deployments
- Update default layer config: planes/ships ON, satellites only for
space, no fire hotspots, military bases + internet outages for infra,
all SIGINT except HF digital spots
- Add MapLibre native clustering to APRS markers (matches Meshtastic)
with cluster radius 42, breaks apart at zoom 8
- Derive gate envelope AES key from gate ID via HKDF so all nodes
sharing a gate can decrypt each other's messages (was node-local)
- Preserve gate_envelope/reply_to in chain payload normalization
- Bump Wormhole modal text from 9-10px to 12-13px
- Add aircraft icon zoom interpolation (0.8→2.0 across zoom 5-12)
- Reduce Mesh Chat panel text sizes for tighter layout
paho-mqtt was missing from pyproject.toml, causing the Meshtastic MQTT
bridge to silently disable itself in Docker — no live chat messages
could be received. Also improve Infonet node status labels: show
RETRYING when sync fails instead of misleading SYNCING, and WAITING
when node is enabled but no sync has run yet.
- require_local_operator now recognizes Docker bridge network IPs
(172.x, 192.168.x, 10.x) as local, fixing "Forbidden — local operator
access only" when frontend container calls wormhole/mesh endpoints
- Bumped all changelog modal text from 8-9px to 11-13px for readability
The self-updater extracted files inside the container but Docker restarts
from the original image, discarding all changes. Now detects Docker via
/.dockerenv and returns pull commands for the user to run on their host.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>