Skip to content

fix(trees): sync tree conformation with URL cache#8263

Merged
grantfitzsimmons merged 6 commits into
mainfrom
issue-8262
Jul 10, 2026
Merged

fix(trees): sync tree conformation with URL cache#8263
grantfitzsimmons merged 6 commits into
mainfrom
issue-8262

Conversation

@grantfitzsimmons

@grantfitzsimmons grantfitzsimmons commented Jul 6, 2026

Copy link
Copy Markdown
Member

Fixes #8262

Note

More DeepSeek suggestions 🤖. This has been quite thoroughly tested and I made adjustments, however they were minor.

The tree viewer was writing its expanded/collapsed state to browser local storage at render-cycle frequency (over 30 times per 500 milliseconds). Each write to localStorage is synchronous and blocks Chrome's main thread. Since it gets to 60 writes per second + cascading React re-renders memory usage climbs until the browser tab becomes unresponsive. I experienced a kernel panic once and had my system become so unresponsive I couldn't even kill the browser. Theoretically multiple tabs amplified the effect exponentially as each tab echoes state changes to every other tab.

Two big issues:

  1. The tree conformation was stored in two places (URL query parameter and localStorage cache) with effects that synced them to each other. Every setConformation call triggered writes to both, and effects from child TreeRow components cascaded multiple writes per user click.
  2. When a storage event arrived from another tab, the handler wrote the value back to localStorage, firing another storage event in the originating tab, creating a ping-pong echo.

Solution

  1. During a session, the URL is the source of truth for the tree state. Local storage is only used to remember the state when you close and reopen the tab. On first opening the tree, it reads from the URL (or falls back to local storage if the URL is empty). After that, user interactions are saved to both, but changes no longer reactively bounce back and forth between the two.
  2. When another tab updates local storage, the receiving tab no longer writes that same value right back. It updates its own display to match but doesn't echo the write, which stops the back-and-forth between tabs.
no_more_looping.mp4

Checklist

  • Self-review the PR after opening it to make sure the changes look good and
    self-explanatory (or properly documented)
  • Add relevant issue to release milestone
  • Add pr to documentation list
  • Add automated tests
  • Add a reverse migration if a migration is present in the PR

Testing instructions

Summary by CodeRabbit

  • Bug Fixes
    • Tree view state now restores more reliably from the URL on first load, while still honoring cached/non-default saved state when applicable.
    • Updates made in one tab now propagate to other open tabs more consistently, avoiding redundant persistence work.
  • Tests
    • Corrected a minor test block terminator to keep automated coverage aligned.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0b4a4729-43a0-4b7e-bd53-506b270b1664

📥 Commits

Reviewing files that changed from the base of the PR and between d0835b3 and 483288e.

📒 Files selected for processing (2)
  • specifyweb/frontend/js_src/lib/components/DataModel/tables.ts
  • specifyweb/frontend/js_src/lib/components/QueryComboBox/__tests__/biostratConditions.test.ts
✅ Files skipped from review due to trivial changes (2)
  • specifyweb/frontend/js_src/lib/components/QueryComboBox/tests/biostratConditions.test.ts
  • specifyweb/frontend/js_src/lib/components/DataModel/tables.ts

📝 Walkthrough

Walkthrough

TreeView now hydrates conformation from the URL on first render, otherwise from cache, and only syncs later changes back to the URL. Cache storage-event handling now updates in-memory state without writing the same value back to localStorage.

Changes

Conformation sync and cache write suppression

Layer / File(s) Summary
TreeView conformation/URL sync effects
specifyweb/frontend/js_src/lib/components/TreeView/index.tsx
Two independent effects syncing conformation and URL are replaced with a first-render guarded pair: on mount, conformation is hydrated from the URL or promoted from cache; on subsequent renders, the URL is updated only when conformation changes.
Cache genericSet skipStorageWrite support and cross-tab handler
specifyweb/frontend/js_src/lib/utils/cache/index.ts
genericSet gains an optional skipStorageWrite parameter guarding its localStorage.setItem call, and the cross-tab storage event handler now calls genericSet with flags that update the in-memory cache and trigger change events while skipping the redundant write back to localStorage.

Unassigned formatting/test-only changes

Layer / File(s) Summary
specifyweb/frontend/js_src/lib/components/DataModel/tables.ts, specifyweb/frontend/js_src/lib/components/QueryComboBox/__tests__/biostratConditions.test.ts Formatting-only edits adjust destructuring/array formatting in tables.ts and the closing brace placement in the QueryComboBox test file.

Sequence Diagram(s)

sequenceDiagram
  participant TabA
  participant LocalStorage
  participant TabB
  TabA->>LocalStorage: setItem(cacheKey, value)
  LocalStorage->>TabB: storage event
  TabB->>TabB: genericSet(triggerChange=true, skipStorageWrite=true)
  TabB->>TabB: update in-memory cache, trigger change event
Loading

Suggested reviewers: emenslin, CarolineDenis, g1rly-c0d3r

🚥 Pre-merge checks | ✅ 4 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR also includes unrelated edits in DataModel/tables.ts and a QueryComboBox test file that are not part of the tree-sync fix. Move unrelated formatting/test changes to a separate PR or revert them so this patch stays focused on the tree cache fix.
Automatic Tests ⚠️ Warning The only test-related change is a newline in an existing test file; there’s no new automated coverage for the behavioral fix. Add automated tests for the tree conformation sync behavior, especially URL-first initialization and no localStorage echo on storage events.
✅ 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 clearly states the main change: syncing tree conformation with the URL cache.
Linked Issues check ✅ Passed The URL-first restore, cached fallback, and storage-event deduplication address the reported localStorage thrashing and cross-tab ping-pong.
Testing Instructions ✅ Passed The testing section points to issue #8262 and asks for main-vs-branch repro of the tree-viewer memory leak, matching the TreeView/cache changes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-8262

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.

coderabbitai[bot]

This comment was marked as outdated.

@github-project-automation github-project-automation Bot moved this from 📋Back Log to Dev Attention Needed in General Tester Board Jul 7, 2026
@grantfitzsimmons grantfitzsimmons requested a review from a team July 9, 2026 15:43
@grantfitzsimmons grantfitzsimmons marked this pull request as ready for review July 9, 2026 15:43
@grantfitzsimmons grantfitzsimmons added this to the 7.12.1 milestone Jul 9, 2026
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Warning

One or more dependencies are approaching or past End-of-Life.
Please plan upgrades accordingly.

STATUS=WARNING
NODE_VERSION=20
NODE_CYCLE=20
EOL_DATE=2026-04-30
DAYS_REMAINING=-70

--- Node.js ---
Version: 20
EOL: 2026-04-30
Status: WARNING

STATUS=OK
PYTHON_VERSION=3.12
PYTHON_CYCLE=3.12
EOL_DATE=2028-10-31
DAYS_REMAINING=845

--- Python ---
Version: 3.12
EOL: 2028-10-31
Status: OK

STATUS=WARNING
DJANGO_VERSION=4.2
DJANGO_CYCLE=4.2
EOL_DATE=2026-04-07
DAYS_REMAINING=-93

--- Django ---
Version: 4.2
EOL: 2026-04-07
Status: WARNING


Triggered by d0835b3 on branch refs/heads/issue-8262

@emenslin emenslin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  • Test in both main and in this branch, following the steps to recreate in #8262

Looks good, it no longer crashes in the issue branch!

@emenslin emenslin requested a review from a team July 9, 2026 17:10

@lexiclevenger lexiclevenger left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Testing instructions

  • Test in both main and in this branch, following the steps to recreate in #8262

Looks good!

@grantfitzsimmons grantfitzsimmons merged commit 50560c6 into main Jul 10, 2026
20 checks passed
@grantfitzsimmons grantfitzsimmons deleted the issue-8262 branch July 10, 2026 16:38
@github-project-automation github-project-automation Bot moved this from Dev Attention Needed to ✅Done in General Tester Board Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅Done

Development

Successfully merging this pull request may close these issues.

Syncing node selection causes runaway memory usage and browser unresponsiveness

4 participants