Skip to content

perf(web): sidebar folder headers no longer re-render on every thread visit - #28774

Open
only21mil wants to merge 1 commit into
pingdotgg:mainfrom
only21mil:fix/audit-m197
Open

only21mil wants to merge 1 commit into
pingdotgg:mainfrom
only21mil:fix/audit-m197

Conversation

@only21mil

Copy link
Copy Markdown
Contributor

Problem

In the boring sidebar, every project folder header subscribed to the whole local visit map. Any change to that map re-rendered every folder header, open folders included, even though only a closed folder's own hidden threads can change its dot.

That map changes on Mark unread, on acknowledging a woken thread, and, for environments on older servers without visit tracking, on every update of the open thread. That is several times a second while a reply streams. So with older servers, every folder header re-rendered several times a second during any reply.

Change

The header now selects its derived dot from the store instead of the map. The selector runs the same resolveSidebarFolderDot over the same inputs, and it returns a string or null, so the header re-renders only when its own dot changes. Open folders never re-render from visits. This is the same approach #23124 took for ChatView.

The dot, its screen-reader label, the count and folder state are unchanged.

Scope and approval

This is a narrow internal performance fix in one component with no behavior change, so it should not need prior approval. #28616 (open) changes resolveSidebarFolderDot so that opening a failed thread clears the failed dot. The selector calls that same function, so the two compose. See Verification.

Verification

  • SidebarProjectFolderHeader.browser.test.tsx (new) renders two closed folders in Chromium. An unrelated visit re-renders neither header. A visit to one folder's unread thread clears its "done" dot, and Mark unread on the other folder's thread adds one. Each header re-renders exactly once for its own change. On main the unrelated-visit assertion fails because both headers re-render.

  • Render counts from a wider version of that test, with 6 folders (3 open, 3 closed) and 20 visits to an unrelated thread, the pattern an older server produces while a reply streams:

    Header renders
    main 120 (20 per folder, open ones included)
    this PR 0

    A relevant visit re-rendered only the affected header, once.

  • With fix(web): clear failed badges when threads are opened #28616's Sidebar.logic.ts applied on top: the failed dot showed, an unrelated visit caused no re-render, and visiting the failed thread cleared the dot with one re-render. The same check fails without fix(web): clear failed badges when threads are opened #28616, as expected.

  • vp run check:changed 1d626d02d95f9a2343553f6498037ee82290d304 (format, lint, knip, typecheck, tests, React Compiler) passes.

Not checked:

  • No before/after screenshots. The rendered output is computed by the same function from the same inputs, so nothing on screen changes. Only when the header re-renders changes.
  • No wall-clock timing. The measurement is render counts only.
  • Mobile doesn't use this component. Desktop runs the same web code, and I did not run it separately.

Prior PRs

No earlier PR made this change. #21039 by t3dotgg added the folder headers. #23124 by juliusmarminge applied the same narrowing to ChatView.

Generated with Claude Opus 5.5 and GPT-6.1 Sol in T3 Code Nightly

Each boring-sidebar folder header subscribed to the whole local visit map, so
any thread visit re-rendered every folder header, open ones included. The
header now selects its derived status dot instead, so it re-renders only when
its own dot changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XS 0-9 changed lines (additions + deletions). labels Nov 1, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at b5b69a3

Macroscope's review found this PR approvable — Folder headers now subscribe to their computed status instead of the entire visit-history map, avoiding unnecessary re-renders. This is a localized rendering optimization with unchanged status logic and sidebar actions.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 3fd2b85 and b5b69a3.

Files selected for processing: 2
  • apps/web/src/components/sidebar/SidebarProjectFolderHeader.browser.test.tsx
  • apps/web/src/components/sidebar/SidebarProjectFolderHeader.tsx

Limit details: You’ve used all 10 included reviews currently available.

Walkthrough

SidebarProjectFolderHeader now uses locally stored thread visit timestamps to resolve the dot for collapsed folders. Browser tests check done labels, unrelated visit updates, and renders after relevant visit or unread updates.

Changes: Folder header visit-state updates

Layer / File(s) Summary
Resolve folder dots from local visit state
apps/web/src/components/sidebar/SidebarProjectFolderHeader.tsx, apps/web/src/components/sidebar/SidebarProjectFolderHeader.browser.test.tsx
The header reads threadLastVisitedAtById when resolving the dot for a collapsed folder and keeps the dot null when expanded. Browser tests check done labels from local timestamps and verify render behavior for relevant and unrelated visit updates.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Refactor

Possibly related PRs

Suggested labels: size:S

Suggested reviewers: t3dotgg, juliusmarminge

Merge Risk: Minimal · up to b5b69

No actionable merge-blocking risk was identified for the folder-header change.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title names the main change: sidebar folder headers no longer re-render on every thread visit. The raw summary and objectives confirm that each header now selects its derived dot from the store, s…
Description check Passed The description covers the required template sections. Problem: every folder header subscribed to the whole local visit map, so unrelated visits re-rendered open and closed headers. Change: each heade…
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.
Full details: Title check

Explanation

The title names the main change: sidebar folder headers no longer re-render on every thread visit. The raw summary and objectives confirm that each header now selects its derived dot from the store, so it re-renders only when its own dot changes. The title follows the conventional commit format with a 'perf(web)' scope and is specific enough for a reviewer scanning history. It is 75 characters, which is within a reasonable length.

Full details: Description check

Explanation

The description covers the required template sections. Problem: every folder header subscribed to the whole local visit map, so unrelated visits re-rendered open and closed headers. Change: each header selects its dot through a store selector, and the selector returns a string or null. Scope and approval: the author explains why prior approval is not needed for a narrow internal performance fix and cites related PRs. Verification: the author lists a new browser test, before/after render counts (120 on main versus 0 with the PR), a check with #28616 applied, and a check:changed run. The author also states what was not checked, including screenshots, wall-clock timing, and desktop runs. The description does not link a triaged issue or maintainer approval. The template asks for that link, or for an explanation of why the fix qualifies without one. The author gives that explanation, but it is a self-assessment and not a maintainer sign-off. The description also includes a model attribution line, which the template requests. The description is mostly complete, so it passes.

Finishing Touches
Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Usage-based review receipt

Note

This review was completed with usage-based billing: files reviewed beyond your plan's included limits are billed at $0.25/file. View usage-based billing.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XS 0-9 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant