mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-09-26 17:27:57 +00:00
## Summary Fixes #1709 — implements deep-link viewport restoration on the Live page so `#/live?lat=43.0731&lon=-89.4012&zoom=12` (and the `node=` combo) center+zoom the map identically to how `/#/map?lat=...&lon=...&zoom=...` already worked. ## Approach Extracted a shared `parseViewportHash(hashOrSearch, opts)` helper in `public/app.js` (next to existing `getHashParams()`) and wired it into BOTH call sites — Live and Map — so the parse/validate logic is DRY and unit-testable. ### `parseViewportHash` contract - Accepts a full hash (`#/live?lat=...`) OR a bare query string (`lat=...&lon=...`). - Returns `{lat, lon, zoom}` only if BOTH `lat` and `lon` parse to finite numbers within bounds (`lat ∈ [-90, 90]`, `lon ∈ [-180, 180]`). Partial lat-only or lon-only is rejected — the issue explicitly forbids partial application of a center. - `zoom` defaults to 12 when missing, must be numeric when present, and is clamped to `[minZoom, maxZoom]` (defaults `[1, 20]` — sensible Leaflet fallback when the tile-provider config isn't supplied). - Returns `null` for any null/empty/invalid input. ### Precedence chain (Live) 1. **URL hash `lat`/`lon`/`zoom`** — highest priority. Applied BEFORE the initial `setView()` so the very first render lands at the requested viewport (no visible recenter from default → URL), AND in the localStorage-restore block so URL overrides `live-map-view`. 2. `live-map-view` localStorage (existing fallback, preserved). 3. `/api/config/map` defaults (existing default, preserved). ### Node-filter URL preservation The existing node-filter URL update logic at `public/live.js:1634` / `1650` already seeds `params` from `getHashParams()`, so unrelated keys (including `lat`/`lon`/`zoom`) already survive node filter changes. Added two source-grep regression tests to guard against future regressions (catches the anti-pattern `const params = new URLSearchParams(); params.set('node', ...)` which would silently clobber the viewport). ## Files changed - `public/app.js` — `+47/-0` — new `parseViewportHash()` helper + window expose. - `public/map.js` — `+8/-4` — replaces inline `parseFloat`/`parseInt` block with helper call. - `public/live.js` — `+22/-3` — applies helper at init (`setView` line) AND in the localStorage-restore block so URL overrides both fallbacks. - `test-frontend-helpers.js` — `+105/-0` — 14 `parseViewportHash` unit tests + 2 live.js source-grep regression tests for the node-filter URL flow. ## TDD red→green - **Red commit** `e6baf935` (FIRST commit on branch): adds tests + a stub `parseViewportHash` returning `null`. 10 of the 14 unit tests fail on assertion (not import error); 2 live.js source-grep tests already pass against current master (regression guards). - **Green commit** `43b3cb5f`: implements the helper + wires both call sites. All 16 new tests pass. ## Test output (`node test-frontend-helpers.js`, last 15 lines) ``` ✅ #825: deep link to unencrypted #channel falls through to REST and renders messages ✅ deriveKey: SHA256("#test")[:16] matches known value ✅ deriveKey: returns 16 bytes ✅ #815 preserved: deep link to #channel with stored key triggers decrypt path (no lock) ✅ invalidateApiCache causes api to re-fetch after cache bust ✅ computeChannelHash: SHA256(key)[0] ✅ verifyMAC: valid MAC passes ✅ verifyMAC: invalid MAC fails ✅ invalidateApiCache with no prefix busts all entries ✅ invalidateApiCache with prefix only busts matching ════════════════════════════════════════ Frontend helpers: 625 passed, 2 failed ════════════════════════════════════════ ``` The 2 failures (`favStar returns filled star for favorite`, `favStar returns empty star for non-favorite`) are **pre-existing on master** and unrelated to this PR — confirmed by running on `origin/master` before any changes. ## Acceptance criteria (issue #1709) 1. ✅ `#/live?lat=43.0731&lon=-89.4012&zoom=12` centers Live map at that lat/lon/zoom. 2. ✅ `#/live?node=ABC123&lat=43.0731&lon=-89.4012&zoom=12` applies BOTH node filter AND viewport (`getHashParams().get('node')` already feeds `setNodeFilter`; helper independently parses lat/lon/zoom). 3. ✅ URL viewport params override `live-map-view` localStorage (URL check runs first AND overrides the savedView branch). 4. ✅ Invalid viewport params ignored safely (`parseViewportHash` returns `null` on any out-of-range / NaN input). 5. ✅ Missing `lat` or `lon` does NOT partially apply a center (helper requires both). 6. ✅ Live node-filter URL update preserves unrelated params — existing `getHashParams()` seeding + new regression tests. 7. ✅ No backend endpoint changes (`grep -l '\.go$' diff` → empty). ## Preflight `bash ~/.openclaw/skills/pr-preflight/scripts/run-all.sh origin/master` → **clean** (all 12 gates pass, no warnings). --------- Co-authored-by: Kpa-clawbot <bot@kpabap.dev> Co-authored-by: Kpa-clawbot <bot@openclaw.local>