Skip to content

fix: keep project load, collab sync, and layer cleanup consistent - #1575

Merged
giswqs merged 9 commits into
opengeos:mainfrom
Ayush7614:fix/project-sync-and-load-integrity
Jul 31, 2026
Merged

fix: keep project load, collab sync, and layer cleanup consistent#1575
giswqs merged 9 commits into
opengeos:mainfrom
Ayush7614:fix/project-sync-and-load-integrity

Conversation

@Ayush7614

@Ayush7614 Ayush7614 commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Normalize the primary mapView on parse/apply the same way secondary panes already do, so hand-edited cameras cannot land out of MapLibre range.
  • Align collaboration projectChanged with buildProjectSnapshot so map grid, models, widgets, processing history, and style-library edits broadcast on their own.
  • Scrub storymap chapter enter/exit layer refs when a layer is removed, and clear the external paint-bridge cache in removeLayerFromMap.

Test plan

  • node --import tsx --test tests/core-project.test.ts tests/collaboration-project-changed.test.ts tests/storymap-layer-scrub.test.ts (53 passing)
  • Open a project with an out-of-range primary camera and confirm it clamps on load
  • In a live collab session, change only the map grid / save a processing model and confirm peers receive the snapshot
  • Remove a layer referenced by storymap chapter opacity rows and confirm the dangling refs are gone after save/reload

Summary by CodeRabbit

  • Bug Fixes
    • Improved collaboration project snapshot change detection to ignore camera-only and UI/collaboration-only activity, preventing unnecessary outbound updates.
    • Stabilized project load/apply by clamping and normalizing the primary map view (zoom/pitch/bearing and invalid coordinates).
    • Removed stale Story Map chapter enter/exit references and cleared related secondary-pane visibility overrides when deleting layers or groups.
    • Fixed layer reuse so opacity/visibility updates are re-applied correctly, and ensured join-derived columns refresh/remove appropriately when groups are deleted.
  • Tests
    • Added/expanded coverage for collaboration change detection, primary map view normalization, Story Map scrub behavior, join-column cleanup, and layer-sync reuse behavior.

Ayush7614 and others added 2 commits July 30, 2026 21:35
Normalize the primary mapView on parse/apply, broadcast collaboration
snapshots when map grid/models/widgets/style library change, scrub
storymap chapter layer refs on remove, and clear paint-bridge cache
when a layer leaves the map.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This change centralizes collaboration project-change detection, normalizes persisted map views, removes dangling Story Map and secondary-pane layer references, refreshes join-derived columns, and clears stale map paint-bridge state. Tests cover each behavior.

Changes

Project state consistency

Layer / File(s) Summary
Broadcast change detection
apps/geolibre-desktop/src/hooks/useCollaboration.ts, apps/geolibre-desktop/src/lib/project-broadcast-changed.ts, tests/collaboration-project-changed.test.ts
The collaboration change detector is shared and compares broadcastable project fields while ignoring camera-only and UI-only changes.
Map view normalization
packages/core/src/project.ts, tests/core-project.test.ts
Primary map views are normalized before grid reconciliation and returned project state, with coverage for invalid coordinates, zoom, pitch, and bearing.
Layer removal cleanup
packages/core/src/store.ts, packages/map/src/layer-sync.ts, tests/storymap-layer-scrub.test.ts, tests/layer-joins.test.ts, tests/plugin-owned-paint.test.ts
Layer and group removal scrubs Story Map and secondary-pane references, refreshes join-derived columns, and clears cached external paint-bridge state.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: giswqs

Poem

I’m a bunny with a tidy state,
Camera wiggles now can wait.
Layers leave no trails behind,
Joins refresh and refs unwind.
Clean projects hop along just right!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main areas changed: project loading, collaboration sync, and layer cleanup.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Ayush7614
Ayush7614 force-pushed the fix/project-sync-and-load-integrity branch from bbc63b6 to 266cfdb Compare July 30, 2026 16:29

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/store.ts`:
- Around line 1384-1386: Update removeLayerGroup, specifically the
removeChildren path that filters s.layers, to collect all deleted layer IDs and
pass them through the shared Story Map reference scrub/removal helper used by
scrubStorymapLayerRefs instead of only removing the group layer. Preserve
existing group-deletion behavior while ensuring onChapterEnter/onChapterExit
references to every removed child are cleared, and add a regression test
covering grouped deletion.

In `@tests/collaboration-project-changed.test.ts`:
- Around line 11-35: Expand the tests around projectChanged to cover every
broadcast-relevant field compared by buildProjectSnapshot, including processing
history, widgets, style library, metadata, layers, and plugins, plus a
collaboration/UI-only update that must remain false. Add focused assertions for
each change and preserve the existing map-grid, model, and camera cases; ensure
the added coverage meets the stated frontend coverage thresholds.

In `@tests/core-project.test.ts`:
- Around line 1289-1294: Update the mapView assertions in the core project test
to verify exact normalization outputs: assert bearing equals 270 and assert the
fallback longitude equals its expected exact value, rather than only checking
finiteness or a bearing range. Keep the existing zoom, pitch, and latitude
assertions unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7b557703-ee16-46fc-b54b-330d37ccc23f

📥 Commits

Reviewing files that changed from the base of the PR and between 28032d0 and bbc63b6.

📒 Files selected for processing (8)
  • apps/geolibre-desktop/src/hooks/useCollaboration.ts
  • apps/geolibre-desktop/src/lib/project-broadcast-changed.ts
  • packages/core/src/project.ts
  • packages/core/src/store.ts
  • packages/map/src/layer-sync.ts
  • tests/collaboration-project-changed.test.ts
  • tests/core-project.test.ts
  • tests/storymap-layer-scrub.test.ts

Comment thread packages/core/src/store.ts
Comment thread tests/collaboration-project-changed.test.ts Outdated
Comment thread tests/core-project.test.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
packages/core/src/store.ts (1)

1384-1386: 🗄️ Data Integrity & Integration | 🟠 Major

Scrub Story Map references when deleting groups.

This fixes direct removeLayer calls, but removeLayerGroup(..., { removeChildren: true }) still removes child layers via filtering without calling this helper. Group deletion can therefore leave onChapterEnter/onChapterExit entries referencing deleted layer IDs. Reuse a shared multi-ID scrub path for all removed children.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/store.ts` around lines 1384 - 1386, Update
removeLayerGroup’s removeChildren path to collect all child layer IDs and scrub
Story Map references through a shared multi-ID helper, rather than only
filtering layers. Reuse that helper from removeLayer for single-ID deletion so
both direct layer removal and group deletion remove matching
onChapterEnter/onChapterExit entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/map/src/layer-sync.ts`:
- Around line 3505-3507: Add a regression test covering the paint-bridge cache
invalidation around appliedBridgeState.delete: apply bridge state, remove the
map layer, recreate it with the same layerId and a new bridge, then verify
opacity and visibility are applied again.

In `@tests/core-project.test.ts`:
- Around line 1275-1295: The existing test only validates normalization through
parseProject; add a regression test that invokes applyProjectToStore directly
with invalid mapView center, zoom, bearing, and pitch values, then assert the
store’s resulting camera values are finite and clamped to the expected bounds.

---

Duplicate comments:
In `@packages/core/src/store.ts`:
- Around line 1384-1386: Update removeLayerGroup’s removeChildren path to
collect all child layer IDs and scrub Story Map references through a shared
multi-ID helper, rather than only filtering layers. Reuse that helper from
removeLayer for single-ID deletion so both direct layer removal and group
deletion remove matching onChapterEnter/onChapterExit entries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 95ba8d98-2a21-4a3e-9ae4-bae87c5b24a7

📥 Commits

Reviewing files that changed from the base of the PR and between bbc63b6 and 266cfdb.

📒 Files selected for processing (8)
  • apps/geolibre-desktop/src/hooks/useCollaboration.ts
  • apps/geolibre-desktop/src/lib/project-broadcast-changed.ts
  • packages/core/src/project.ts
  • packages/core/src/store.ts
  • packages/map/src/layer-sync.ts
  • tests/collaboration-project-changed.test.ts
  • tests/core-project.test.ts
  • tests/storymap-layer-scrub.test.ts

Comment thread packages/map/src/layer-sync.ts
Comment thread tests/core-project.test.ts
@giswqs

giswqs commented Jul 30, 2026

Copy link
Copy Markdown
Member

/claude-review

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

🔍 Cloudflare PR preview

Item Value
Site https://f2ef0a00.geolibre-preview.pages.dev
Demo app https://f2ef0a00.geolibre-preview.pages.dev/demo/
Commit 57330c6

Comment thread apps/geolibre-desktop/src/hooks/useCollaboration.ts Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs: None found. Traced all four fixes against their call sites and existing tests:

  • mapView normalization now applied in both parseProject and applyProjectToStore (packages/core/src/project.ts) — math checked (clamp/wrap for center/zoom/bearing/pitch) and matches the new test expectations. High confidence, correct.
  • projectChanged field list (apps/geolibre-desktop/src/lib/project-broadcast-changed.ts) now mirrors every field buildProjectSnapshot reads from the store except the intentionally-excluded mapView. Verified each new field (models, processingHistory, widgets, dashboardColumns, mapLayout, secondaryMapViews, primaryMapLabel, projectStyleLibrary) exists on AppState. High confidence, correct.
  • scrubStorymapLayerRefs (packages/core/src/store.ts) correctly returns the same object reference when no chapter references the removed layer, avoiding unnecessary re-renders, and correctly rebuilds only changed chapters otherwise. High confidence, correct.
  • appliedBridgeState.delete(layerId) in removeLayerFromMap (packages/map/src/layer-sync.ts) is a reasonable defensive addition; the existing bridge-identity check in applyExternalNativePaintBridge already covers most reuse cases, but explicit cleanup on removal is safe and matches the stated intent. Medium confidence this fully closes the described bug, but no regression risk either way.

Security: None found — no new untrusted input handling, injection surface, or secret exposure in this diff.

Performance: None found — the new comparisons and array filters are all O(n) over already-small collections (chapters, layers), consistent with the existing code's style.

Quality:

  • useCollaboration.ts:25 re-exports projectChanged from the new module, but nothing in the repo imports it from useCollaboration anymore (the new test imports directly from project-broadcast-changed.ts, and useCollaboration.ts already imports it for its own internal use). Looks like leftover from the refactor — flagged inline. Medium confidence (verified via repo-wide grep, but an external consumer outside this checkout can't be ruled out).

CLAUDE.md: No violations — no new external map/tile hosts, no touched whitebox-menu-catalog.ts or mirrored-constant files, no user-facing strings needing i18n, and no uv.lock-relevant changes.

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

🔍 GitHub Pages PR preview

Item Value
Site Deploy failed. See the job log.
Demo app Unavailable
Commit 57330c6

Ayush7614 and others added 2 commits July 31, 2026 01:37
Scrub storymap refs when deleting a group with its children, drop the
unused projectChanged re-export, and tighten mapView/collaboration/
group-deletion regression coverage.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/store.ts`:
- Around line 1658-1660: Update the group-child deletion path around
scrubStorymapLayerRefs to reuse or extract a bulk layer-removal helper
equivalent to removeLayer. Ensure it cleans secondary-pane visibility overrides
and invokes cascadeLayerJoinRefresh for every removedIds member before
completing deletion. Add coverage verifying stale joined attributes and
secondary-pane overrides are removed for deleted child layers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e106fc74-c801-4610-8665-402069df3048

📥 Commits

Reviewing files that changed from the base of the PR and between 266cfdb and f4932b0.

📒 Files selected for processing (5)
  • apps/geolibre-desktop/src/hooks/useCollaboration.ts
  • packages/core/src/store.ts
  • tests/collaboration-project-changed.test.ts
  • tests/core-project.test.ts
  • tests/storymap-layer-scrub.test.ts
💤 Files with no reviewable changes (1)
  • apps/geolibre-desktop/src/hooks/useCollaboration.ts

Comment thread packages/core/src/store.ts Outdated
Cascade join refresh and scrub secondary-pane visibility the same way
removeLayer does, so group delete cannot leave stale joins or overrides.
@Ayush7614
Ayush7614 force-pushed the fix/project-sync-and-load-integrity branch from f4932b0 to 9e78d74 Compare July 30, 2026 20:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/collaboration-project-changed.test.ts`:
- Around line 6-18: Extract the duplicate geojsonLayer helper into a shared
test-fixtures module and update collaboration-project-changed.test.ts,
core-project.test.ts, and storymap-layer-scrub.test.ts to import and reuse it.
Preserve the existing GeoLibreLayer construction and helper call behavior across
all three test files.
- Around line 40-98: Split the combined test around projectChanged into separate
it() blocks for processing history, widgets, style library, metadata, layers,
and plugins. Keep each scenario’s newProject setup, mutation, and assertion
intact so one failing field does not prevent the remaining coverage from
running.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b1cb0b1f-8e90-4840-862e-c17fd7f7d3cf

📥 Commits

Reviewing files that changed from the base of the PR and between f4932b0 and 9e78d74.

📒 Files selected for processing (6)
  • apps/geolibre-desktop/src/hooks/useCollaboration.ts
  • packages/core/src/store.ts
  • tests/collaboration-project-changed.test.ts
  • tests/core-project.test.ts
  • tests/layer-joins.test.ts
  • tests/storymap-layer-scrub.test.ts
💤 Files with no reviewable changes (1)
  • apps/geolibre-desktop/src/hooks/useCollaboration.ts

Comment thread tests/collaboration-project-changed.test.ts Outdated
Comment thread tests/collaboration-project-changed.test.ts Outdated
Lock the removeLayerFromMap appliedBridgeState delete so a reused layer
id with the same bridge still gets a fresh opacity apply.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/plugin-owned-paint.test.ts`:
- Around line 211-232: Extend the “re-applies after removeLayerFromMap when the
same layer id is reused” test to include a setVisibility callback and visibility
assertions alongside the existing opacity checks. Register and verify visibility
before removal, clear the recorded calls, then reuse the layer ID and assert
visibility is applied again, covering the shared cache behavior for both
operations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c27b64f3-71f8-4fa1-a64e-5b6f467f00f9

📥 Commits

Reviewing files that changed from the base of the PR and between 9e78d74 and 1c8a530.

📒 Files selected for processing (1)
  • tests/plugin-owned-paint.test.ts

Comment thread tests/plugin-owned-paint.test.ts
giswqs added 2 commits July 31, 2026 18:35
Resolve the removeLayerGroup conflict with the nested layer groups work
(opengeos#1593): keep main's recursive descendant-group collection and parent
re-linking, and layer this branch's cleanup on top so join refresh,
secondary-pane visibility scrubbing, and storymap ref scrubbing run over
every layer in the removed group *subtree*, not just its direct children.
- tests/plugin-owned-paint.test.ts: the layer-id-reuse regression test now
  registers a `setVisibility` callback and asserts visibility alongside
  opacity, since `removeLayerFromMap` clears the cache both setters share
  (CodeRabbit).
- tests/helpers/layer-fixtures.ts: extract the `geojsonLayer` skeleton that
  was duplicated in three suites into one shared fixture, so the required
  `GeoLibreLayer` fields cannot drift apart (CodeRabbit).
- tests/core-project.test.ts, tests/storymap-layer-scrub.test.ts,
  tests/collaboration-project-changed.test.ts: use the shared fixture.
- tests/collaboration-project-changed.test.ts: split the six-scenario
  broadcast-field test into one `it()` per field, so a failure in the first
  no longer hides regressions in the rest (CodeRabbit).
@giswqs
giswqs merged commit 16ad4c4 into opengeos:main Jul 31, 2026
17 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants