Skip to content

perf(web): mount session row dialogs only while they are open - #1233

Merged
tiann merged 1 commit into
tiann:mainfrom
hqhq1025:perf/mount-session-dialogs-on-demand
Jul 29, 2026
Merged

perf(web): mount session row dialogs only while they are open#1233
tiann merged 1 commit into
tiann:mainfrom
hqhq1025:perf/mount-session-dialogs-on-demand

Conversation

@hqhq1025

Copy link
Copy Markdown
Collaborator

Problem

Every SessionItem renders its rename dialog and both confirm dialogs unconditionally, passing isOpen to keep them closed (SessionList.tsx). With 28 sessions that is 84 mounted Radix dialogs the user cannot see, and each carries a Presence / DialogProvider / DialogContent / DialogPortal subtree that re-renders whenever the row does.

Measured against a live hub, those dialogs were roughly half of the entire fiber tree — 1680 nodes before, 886 after. Profiling a single machine-updated event (arrives every 20s per machine, carries only changed CPU/memory numbers) showed it re-rendering 1600+ dialog-internal components:

Presence               3360
Dialog                 1680
DialogProvider         1680
DialogContent          1680
DialogPortal           1680
ConfirmDialog           848
RenameSessionDialog     416

Fix

Mount them on demand. The same file already does this for SessionExportDialog and the reopen-error ConfirmDialog, so this only brings the remaining three in line with the pattern sitting right next to them.

dialog.tsx has no open/close transition (its only transition-* is the close button's hover color), so nothing animates on unmount.

Measured effect

Real Chromium against a live hub, 70s steady state, stacked on top of the activeAt patch fix (#1232). The fiber-tree number is attributable to this change alone:

before after
fiber tree 1680 886
components re-rendered 54k 15.5k
long tasks 26 / 2713ms 0 / 0ms
main thread blocked 3.6% 0.0%
frame rate 58.4 fps 59.8 fps

Long tasks disappear entirely.

Verification

Driven interactively in a real browser with real pointer events, not synthetic clicks:

  • idle: 0 dialogs in the DOM (was 84)
  • long-press a row → menu opens with Rename / Copy reference / Export conversation / Archive
  • click Rename → dialog opens, input prefilled with the current session name
  • Escape → dialog closes, back to 0 in the DOM

Testing

  • tsc --noEmit -p web/tsconfig.json clean
  • Full web suite: 1598 pass, 0 fail

Every SessionItem rendered its rename dialog and both confirm dialogs
unconditionally, passing isOpen to keep them closed. With 28 sessions
that is 84 mounted Radix dialogs that the user cannot see, and each one
carries a Presence/DialogProvider/DialogContent/DialogPortal subtree that
re-renders whenever the row re-renders.

Measured against a live hub, dialogs accounted for roughly half of the
whole fiber tree: 1680 nodes before, 886 after. A single machine-updated
event - which arrives every 20s per machine and only carries changed CPU
and memory numbers - was re-rendering over 1600 dialog-internal
components.

The same file already mounts SessionExportDialog and the reopen-error
ConfirmDialog on demand, so this only makes the remaining three
consistent with the pattern next to them. dialog.tsx has no open/close
transition, so nothing animates on unmount.

Steady-state effect, real Chromium, 70s, stacked on top of the activeAt
patch fix:

  fiber tree            1680  ->  886
  components re-rendered  54k ->  15.5k
  long tasks          26 / 2713ms  ->  0 / 0ms
  main thread blocked    3.6%  ->  0.0%
  frame rate             58.4  ->  59.8 fps

Verified interactively: long-press opens the menu, Rename opens the
dialog prefilled with the current name, Escape closes it, and no dialog
is in the DOM while idle.
@tiann
tiann force-pushed the perf/mount-session-dialogs-on-demand branch from 12c9d0b to 53c21d4 Compare July 29, 2026 11:58

@github-actions github-actions 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.

Findings

  • None.

Summary

  • Review mode: initial
  • No correctness, security, regression, data-loss, performance, or maintainability issue found in the added/modified lines.
  • Residual risk: no automated SessionItem coverage asserts that rename/archive/delete dialogs remain unmounted while closed and still complete their open/close flows.

Testing

  • Not run (automation); PR code was not executed under the review security policy. The PR reports web typecheck and 1,598 passing web tests; the GitHub test check was still in progress when reviewed.

HAPI Bot

@tiann
tiann merged commit e3ca31d into tiann:main Jul 29, 2026
2 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