Files
GeoLibre/python/tests
Qiusheng Wu 49f083b334 feat(bookmarks): save bookmarks in the project (#3006)
* feat(bookmarks): save bookmarks in the project

Bookmarks lived only in the browser's localStorage, so they did not
travel with a .geolibre.json and the Python package and MCP server
could not author them.

- Project format: optional `bookmarks` and `bookmarkGroups` (folders),
  normalized on load (camera range checks, duplicate ids, bearing wrap,
  dangling folder ids dropped) and omitted when empty.
- Store: `bookmarks`, `bookmarkGroups` and `setBookmarks`; saved,
  autosaved and shared in collaboration like other project sections.
- Bookmarks panel: no longer persists to localStorage. It opens with
  the project's bookmarks, writes every edit (including host-dialog
  imports) back to the project, and rebuilds when a project load or a
  collaborator replaces them. Bookmarks saved by older versions move
  into the first project opened that has none, once.
- Python `Map.add_bookmark` / `remove_bookmark` and MCP tools
  `add_bookmark` / `remove_bookmark` (camera from the saved view by
  default, folder by id or name, layers to show), plus bookmarks in
  `describe_project`. The Python round-trip fixture now carries
  bookmarks through the app's parseProject.
- Docs: project format, Python, MCP, user guide, and the agent skill.

Part of #2869

* Address review feedback

- Trim a bookmark's groupId before matching it to the (trimmed) folder
  ids, so a hand-edited id with spaces is not silently un-filed
  (Claude review).
- Legacy migration no longer deletes the old localStorage bookmarks:
  a marker key records the one-time copy, so bookmarks copied into the
  wrong project stay recoverable from browser storage (Claude review).
- Python add_bookmark refuses a 501st bookmark before changing the
  project, matching the app's MAX_PROJECT_BOOKMARKS (500), with a drift
  test that pins the two together (CodeRabbit).

* Address review feedback

- Write the legacy-bookmark migration marker only once the project that
  received them is saved; a project discarded or replaced unsaved leaves
  it unset so the next empty project gets the copy (CodeRabbit).
- Correct the user guide: the old browser copy is left in place but no
  longer updated, not kept as a backup (Claude).
- Move the bookmarkGroups normalization above the print-layout comment so
  the comment stays attached to its code (Claude).
2026-10-06 18:20:03 -04:00
..