Click an empty part of the map to add a place there #120
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/map-click-add-place"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Task 176. Clicking an empty part of the map starts adding a place there, pre-filled with the clicked coordinates.
LeafletMap.OnMapClicked(newMapCoordinatescallback), independent ofEnablePickingso the home map's existing markers stay fixed rather than becoming draggable.bubblingMouseEvents: false. Leaflet defaults it totrue, so without this a click on an existing marker also fires a map click and opens the add-place form. Confirmed necessary rather than assumed, and proved byMapClickAddPlaceJourneyTests, which clicks the map, adds a place, then clicks the resulting marker and asserts only the detail panel opens. Reverting the flag reddens that journey.PlaceForm.InitialCoordinates/DefaultGroupId(both optional) reuse the existing form rather than adding a second one. Default group is the expanded accordion group if the caller may add to it, else their personal group; a view-only group is never preselected.PlaceFormPanelkeeps the form mounted across clicks andPlaceForm's@keyis null for every add, so the instance is reused — without this the panel silently kept the first click's coordinates and would have saved a place at the wrong spot.PlaceFormnow tracks the value it last seeded from and reseeds inOnParametersSetwhen a genuinely new one arrives, comparing against the last-seeded value rather than the live fields so a manually picked pin survives an unrelated re-render. Coordinates only — name, description and group are left intact, since a second click relocates the pin rather than restarting the form. Recorded in ADR-0105.inertbinding prevents a click landing while a panel is open or closing, verified in review with real forced-click races rather than accepted on argument.Review raised two findings, both fixed and mutation-tested — the reseed defect above, and a missing regression test for the view-only default-group fallback. Full suite, architecture tests, coverage ratchet (WebUI → 90.1%),
dotnet formatand the E2E suite all clean on the pinned SDK.Verdict: changes needed
Reviewed at
e8dc9c0(unchanged since PR creation, mergeable, CI run #529 green).Central claim verified. Reverted
bubblingMouseEvents: falseto Leaflet's own default (true) and reranMapClickAddPlaceJourneyTestsagainst a real browser: it goes red, with a second "Add a place" panel visibly opening alongside the detail panel a marker click should only have selected. The journey genuinely discriminates.Regression risk (PR #117's duplicate-id shape) — tested directly, not accepted on argument, and it holds. Built two E2E races against the real app: (1) start the drawer's own add-panel closing (200 ms animation) and fire a forced map click before it completes; (2) fire a forced map click immediately after opening the drawer's add-panel, before any settling wait. Both were run several times. Neither ever produced a second
#place-form-name.inert(a real browser semantic, not merely a Playwright actionability checkForce: truebypasses) blocks the click outright in both windows.But there is a real gap in the field-level defence the PR describes as belt-and-braces, and it's reachable if
HandleMapClickedis ever invoked twice for the same open panel.Home's own@keyfor the map-click panel is a fixed sentinel, andPlaceFormPanel's own<PlaceForm @key="Place?.Id">isnullfor every add (Placeis always null), so the samePlaceForminstance is reused across repeat clicks to the same panel —OnInitializednever re-runs, soInitialCoordinatesis never re-seeded. Confirmed by bUnit: callLeafletMap.OnMapAreaClickedonce, then again at different coordinates without closing the panel in between — the form keeps showing the first click's coordinates. A second, independent bUnit check confirms this is fine once the panel is genuinely closed and reopened (full unmount, freshOnInitialized) — the bug is specific to a second call landing while the same instance is still live. Todayinertis the only thing standing between a stray click and this — which the two race tests above show is currently solid — but the PR's own words ("nulls … defensively … rather than relying only on the browser argument") describe a second line of defence that doesn't actually cover this case: the null-guard only prevents edit and add fighting each other, not a second add landing on the same open add. Ifinertis ever weakened by an unrelated future change, this reseeds silently — no error, just a place saved at the wrong coordinates. Worth a guard (e.g. ignore a click while_addingPlaceAtCoordinatesis already set, matching the eligibility-check early return already there) or, at minimum, a named, deliberate limit in ADR-0105 rather than the current "defensively" phrasing.Minor: the viewer-only-expanded-group default is correct but untested.
DefaultGroupIdForMapClick's{ Role: GroupRole.Owner or GroupRole.Editor }pattern correctly excludes a Viewer-only expanded group and falls back to the personal group — confirmed by bUnit — but no test in this PR exercises that specific combination (every existing case is either no group expanded, or the expanded group is one the caller can add to). Worth a regression test given it's the one branch this ticket's own reasoning depends on for not preselecting a group the caller can't use.Everything else checked out: the two "Add a place" routes don't diverge beyond the two new optional parameters (
PlaceFormPanel/PlaceFormdiffs are a clean, symmetric pass-through), no@codeblocks, ADR-0105 numbered and indexed cleanly, coverage ratchet holds (WebUI 87.9% → 90%, reproduced independently), anddotnet formatis clean.Verdict: changes needed
Re-reviewed only
3794b3d's diff overe8dc9c0. Both prior findings are fixed and independently mutation-tested by me, not just read: disablingOnParametersSetreddensPlaceForm_InitialCoordinatesChangesOnAnAlreadyMountedForm_ReseedsTheCoordinateFields; changing the guard to compare against live_latitude/_longitudeinstead of_seededInitialCoordinatesreddensPlaceForm_RerenderedWithTheSameInitialCoordinatesAfterAManualPick_DoesNotOverwriteThePick— that second one is the test that actually proves the risky part (comparing against the last-seeded value, not the current fields), and it holds.MapCoordinatesis areadonly record struct, so the!=guard is genuine value equality, not reference — confirmed, not assumed. Traced the "Add a place" button path separately:InitialCoordinatesstays null throughout that route, so the reseed condition never fires and there's nothing to clobber there. CI green on3794b3d(build 614, e2e 615, bothsuccess, run #446).Only outstanding item: "coordinates only, not name/description/group" is a real product decision, well-argued in the
OnParametersSetXML doc, but it's not in ADR-0105 — the ADR wasn't touched by this commit. Every other consequential call in this file (thedouble?fix, the group-default fallback, thebubblingMouseEventsfix) got an ADR paragraph; this one should too, as an addendum to ADR-0105 rather than living only in a doc comment and a commit message.