From b5fc0ec38853297bb0ced3e44f05329a9c5a96bf Mon Sep 17 00:00:00 2001 From: pe1hvh Date: Wed, 11 Mar 2026 05:54:48 +0100 Subject: [PATCH] v1.13.2 BugFix --- CHANGELOG.md | 39 +++++++++++++++--------- meshcore_gui/gui/dashboard.py | 1 + meshcore_gui/gui/route_page.py | 4 +-- meshcore_gui/static/leaflet_map_panel.js | 10 ++++++ 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4660fda..2c8d339 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,26 +12,37 @@ Format follows [Keep a Changelog](https://keepachangelog.com/) and [Semantic Ver ### Fixed - 🛠 **MAP panel blank when contacts list is empty at startup** — dashboard update loop had two separate conditional map-update blocks that both silently stopped firing after - tick 1 when `data['contacts']` was empty (e.g. device just booted or no contacts - stored). Map panel received no further snapshots and remained blank indefinitely. -- 🛠 **Route map not rendered when no node has GPS coordinates** — `_render_map` in - `route_page.py` returned early before creating the Leaflet container when - `payload['nodes']` was empty. `MeshCoreRouteMapBoot` handles an empty nodes list - correctly (renders map at home area), so the early return was incorrect. + tick 1 when `data['contacts']` was empty. Map panel received no further snapshots and + remained blank indefinitely. +- 🛠 **Leaflet map initialized on hidden (zero-size) container** — `processPending` in + the browser runtime called `L.map()` on the host element while it was still + `display:none` (Vue v-show, panel not yet visible). This produced a broken 0×0 map + that never recovered because `ensureMap` returned the cached broken state on all + subsequent calls. Fixed by adding a `clientWidth/clientHeight` guard in `ensureMap`: + initialization is deferred until the host has real dimensions. +- 🛠 **Route map container had no height** — `route_page.py` used the Tailwind class + `h-96` for the Leaflet host `
`. NiceGUI/Quasar does not include Tailwind CSS, + so `h-96` had no effect and the container rendered at height 0. Leaflet initialized + on a zero-height element and produced a blank map. +- 🛠 **Route map not rendered when no node has GPS coordinates** — `_render_map` + returned early before creating the Leaflet container when `payload['nodes']` was + empty. Fixed: container is always created; a notice label is shown instead. ### Changed +- 🔄 `meshcore_gui/static/leaflet_map_panel.js` — Added size guard in `ensureMap`: + returns `null` when host has `clientWidth === 0 && clientHeight === 0` and no map + state exists yet. `processPending` retries on the next tick once the panel is visible. - 🔄 `meshcore_gui/gui/dashboard.py` — Consolidated two conditional map-update blocks - into a single unconditional `self._map.update(data)` that fires on every timer tick - while the MAP panel is active. The JS runtime coalesces pending payloads so only the - newest snapshot is ever applied; the extra calls are cheap. -- 🔄 `meshcore_gui/gui/route_page.py` — Removed early `return` from `_render_map` when - no GPS nodes are present. The Leaflet container is now always created. A small inline - notice is shown when there is no location data instead of skipping the map entirely. + into a single unconditional update while the MAP panel is active. Added `h-96` to the + DOMCA CSS height overrides for consistency with the route page map container. +- 🔄 `meshcore_gui/gui/route_page.py` — Replaced `h-96` Tailwind class on the route + map host `
` with an explicit inline `style` (height: 24rem). Removed early + `return` guard so the Leaflet container is always created. ### Impact - MAP panel now renders reliably on first open regardless of contact/GPS availability -- Route map now always shows even when route nodes carry no GPS coordinates -- No breaking changes — only the two files above are modified +- Route map now always shows with correct height even when route nodes have no GPS +- No breaking changes outside the three files listed above --- ## [1.13.1] - 2026-03-09 — Message Icon Consistency diff --git a/meshcore_gui/gui/dashboard.py b/meshcore_gui/gui/dashboard.py index e037aa2..6f86e63 100644 --- a/meshcore_gui/gui/dashboard.py +++ b/meshcore_gui/gui/dashboard.py @@ -193,6 +193,7 @@ body.body--light .domca-drawer .q-item { color: #3d6380 !important; } .domca-panel .h-40 { height: calc(100vh - 20rem) !important; min-height: 10rem; } .domca-panel .h-32 { height: calc(100vh - 24rem) !important; min-height: 8rem; } .domca-panel .h-72 { height: calc(100vh - 12rem) !important; min-height: 14rem; } +.domca-panel .h-96 { height: calc(100vh - 8rem) !important; min-height: 16rem; } .domca-panel .max-h-48 { max-height: calc(100vh - 16rem) !important; min-height: 6rem; } /* ── Allow narrow viewports down to 320px ── */ diff --git a/meshcore_gui/gui/route_page.py b/meshcore_gui/gui/route_page.py index 9377866..492346a 100644 --- a/meshcore_gui/gui/route_page.py +++ b/meshcore_gui/gui/route_page.py @@ -251,8 +251,8 @@ class RoutePage: container_id = f'route-map-{uuid4().hex}' ui.html( - f'
' - ).classes('w-full') + f'
' + ).classes('w-full').style('height: 24rem') boot_script = ( '(function bootRouteMap(retries){' diff --git a/meshcore_gui/static/leaflet_map_panel.js b/meshcore_gui/static/leaflet_map_panel.js index 63dc0b0..63c5979 100644 --- a/meshcore_gui/static/leaflet_map_panel.js +++ b/meshcore_gui/static/leaflet_map_panel.js @@ -42,6 +42,16 @@ return null; } + // Do not initialize the Leaflet map while the host container has no + // rendered dimensions. This happens when the map panel is hidden at + // page load (display:none via Vue v-show). Calling L.map() on a + // zero-size element produces a broken map that never recovers. + // processPending will retry on the next scheduled tick once the panel + // becomes visible and the host gains real dimensions. + if (!existing && host.clientWidth === 0 && host.clientHeight === 0) { + return null; + } + if (existing) { if (existing.host !== host) { if (existing.resizeObserver) {