fix(web): the Files tree remembers expanded folders#18211

open12
main
GitHub fork: fix/files-tree-remember-expanded
openedOct 11, 2026byFfixfon
View on GitHubTwo-way sync enabledPR last imported 1d ago

The Files tree forgets expanded folders when its panel remounts or the app reloads. This remembers expansion per environment and workspace, restores folders as their listings arrive, and keeps a user’s collapse when a file preview remains open. Missing folders are removed only after their parent lists successfully. Storage failures leave the tree usable, and saved preferences are capped at 500 paths.

Fresh file opens and tab switches still reveal the active file. A retained selection does not reopen a collapsed folder after an explorer remount. Deep search results finish loading their ancestors, and expansion reconciliation and storage writes are coalesced during bulk toggles.

Maintainer takeover of @fixfon’s #18211, preserving the original commits and merging main. Refs #12041; mobile remains outside this PR’s scope.

Publication status: current-head CI jobs that ran passed; the cancelled duplicate native fingerprint job has a successful replacement. CodeRabbit completed with no actionable findings and Macroscope correctness passed. Macroscope approvability is neutral / Needs Human Approval because the persisted, asynchronous Files-tree behavior spans components. Human approval remains outstanding; this PR is unmerged.

Validation on the rebuilt head:

  • 107 focused tests pass: 7 expansion, 10 mounted Files panel, 3 path reconciliation, and 87 right-panel store tests. The original standalone storage tests were consolidated into existing suites; expansion and panel coverage changed from 14 to 17 tests. Regression checks failed before their fixes, including retained-selection collapse, acknowledged tab selection, and deferred deep search loading interrupted by a remount.
  • Scoped lint, formatting, web TypeScript, and diff checks pass.
  • A mounted 500-folder Pierre probe restored in one reconciliation with zero storage writes. Expand all and collapse all each used one reconciliation and one storage write. These are operation counts, not frame-time guarantees.
  • Live Linux web client with real filesystem listings: reopen Files, reload, switch workspaces, preserve a collapse with a selected file, and switch acknowledged file tabs. Matched images below use pinned main and the rebuilt head with the same fixture and viewport.
  • Independent full-diff reviews: five rounds; final Opus and Sol reviews found no confirmed defects or blockers. Earlier findings about late restoration, repeated scans/writes, retained selection, tab selection, and deep search were fixed.

Before — reopening Files loses expansion:

Before: Files reopens with src collapsed

After — reopening Files retains both folder levels:

After: Files restores src and nested with save.txt visible

Reopen, reload, and workspace-isolation recording · Tab selection and retained-collapse recording · Retained selection and collapsed-parent remount recording

Verification limits: delayed listings, pruning, malformed or unavailable storage, and environment-key isolation were covered in focused tests rather than by inducing those failures on a remote server. Electron, macOS, Windows, iOS, and Android were not run. Web and desktop share the changed tree; no mobile behavior is claimed. The interrupted deep-search/remount regression uses the real directory hook with deferred query responses; natural remote latency was not exercised. Multiple windows retain last-writer-wins preferences, and workspace keys are not evicted.

Implemented in T3 Code with the Codex harness: GPT-6.1-Sol implementation and GPT-6-Astra tests. Independent reviews used Claude Opus 5.5 and GPT-6-Sol.

Checks

21 successful · 8 skipped · 1 neutral
All checks passed
2fcd03e
Synced from GitHub

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — This introduces a substantial user-facing Files-tree behavior change involving localStorage persistence, asynchronous parent/child restoration, and persisted reveal state across multiple components. Although focused tests cover key lifecycle and storage cases, the cross-component statefulness and remount behavior warrant human review.

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

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 8fafaf68-71d5-4692-b769-05c2338cc2ba
📥 Commits

Reviewing files that changed from the base of the PR and between 74f3bf5e082feeb70541ca204eeb44ee9b080f70 and 2fcd03ece8ef3de2cb70a3a3d6cc97b13e8bdea8.

📒 Files selected for processing: 7
  • apps/web/src/components/chat/RightPanelSurfaceContent.tsx
  • apps/web/src/components/files/FileBrowserPanel.browser.test.tsx
  • apps/web/src/components/files/FileBrowserPanel.tsx
  • apps/web/src/components/files/FilePreviewPanel.tsx
  • apps/web/src/components/files/fileTreeExpansion.test.ts
  • apps/web/src/components/files/fileTreeExpansion.ts
  • apps/web/src/rightPanelStore.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.

📝 Walkthrough

The file browser now saves and restores expanded directories by environment and working directory. File-surface reveal requests carry handled state through the preview to the browser, which acknowledges reveals and retries when a selected entry is not yet available.

Changes: File explorer state

Layer / File(s)Summary
Expansion storage and restoration
apps/web/src/components/files/fileTreeExpansion.ts, apps/web/src/components/files/useDirectoryEntries.ts, apps/web/src/components/files/FileBrowserPanel.tsx, apps/web/src/components/files/fileTreeExpansion.test.ts, apps/web/src/components/files/FileBrowserPanel.browser.test.tsx
The file browser reads and writes expanded paths scoped to an environment and working directory. It reconciles saved paths with loaded directories, restores nested expansions as listings arrive, and tests persistence, pruning, storage failures, and remount behavior.
Selection reveal acknowledgement
apps/web/src/rightPanelStore.ts, apps/web/src/components/chat/RightPanelSurfaceContent.tsx, apps/web/src/components/files/FilePreviewPanel.tsx, apps/web/src/components/files/FileBrowserPanel.tsx, apps/web/src/components/files/FileBrowserPanel.browser.test.tsx
File surfaces now store whether a reveal request was handled. The preview passes this state to the browser, which acknowledges completed reveals, retries missing selections, and preserves search during retained previews. Browser tests cover surface changes, pending directory listings, and remounts.

Priority: ⬇️ Low

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

Change: Bug fix

Sequence Diagram(s)

mermaid
1sequenceDiagram
2 participant RightPanelSurfaceContent
3 participant FilePreviewPanel
4 participant FileBrowserPanel
5 participant rightPanelStore
6 RightPanelSurfaceContent->>FilePreviewPanel: Pass reveal-handled state and callback
7 FilePreviewPanel->>FileBrowserPanel: Pass selected-path reveal state and callback
8 FileBrowserPanel->>RightPanelSurfaceContent: Acknowledge the reveal request
9 RightPanelSurfaceContent->>rightPanelStore: Mark matching file surface request handled

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to 2fcd0

The change remembers expanded folders in the Files tree and tracks reveal handling. No concrete merge-blocking risk was found.

Security architecture risk: 🔵 Low · up to 2fcd0

The change is primarily browser-state persistence. Restoring folders reuses directory listing in the current environment and workspace rather than granting new file access. Remaining uncertainty concerns workspace identity changes and shared-browser state, not a demonstrated authorization bypass.

Retained concerns No architecture-level concerns identified.

Security review details

Security Blast Radius

  • observed — Restoration can automatically trigger directory listings, but persisted strings do not select an environment connection. Expanded current tree rows call the existing loader, which supplies the panel's current environmentId and cwd to projectEnvironment.listEntries.

Trust Boundaries and Controls

  • observed — Reveal acknowledgement is scoped to a thread, path-derived file surface, and matching request ID. Missing, superseded, and already-handled requests leave state unchanged. The browser acknowledges only after the selected path exists in directory listings, not merely in provisional search results.

Resilience and Maintainability Implications

  • observed — The reused listing loader deduplicates requests and limits execution to four concurrent requests per hook instance. Completion handlers avoid publishing results after unmount, while ancestor loading observes an abort signal. These controls contain restoration work without establishing cancellation of already-running server requests.

Hardening Proposals

  • proposed — Use an unambiguous tuple encoding for the persisted environment/cwd key. The current delimiter concatenation can alias delimiter-bearing identities permitted by the identifier schema. This is namespace hardening; inspected listing calls still use the current panel's environment and cwd, so it is not a demonstrated cross-environment access path.
Pre-merge checks: Passed 4
Check nameStatusExplanation
Title checkPassedThe title clearly identifies the main change: preserving expanded folders in the Files tree.
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
Description checkPassedThe description is complete and directly addresses the problem, implementation, scope, approval status, verification results, limitations, UI evidence, and agent usage. It does not use the template he…
Full details: Description check

Explanation

The description is complete and directly addresses the problem, implementation, scope, approval status, verification results, limitations, UI evidence, and agent usage. It does not use the template headings, and it does not include a direct link to an explicit maintainer approval comment, but the required information is present and the description is otherwise detailed and relevant.

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

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

Added 1 commit

  • fix(web): the Files tree remembers expanded folders74f3bf5

Taking over this one as maintainer for batch web-misc-06. I’ll preserve your commits, consolidate the tests, and verify folder restoration and workspace isolation in the running client. Credit to @fixfon for the fix. Mobile remains out of scope. No merge planned.

Added 11 commits

  • Merge remote-tracking branch 'origin/main' into fix/files-tree-remember-expanded96dbc2a
  • test(web): cover remembered file tree expansiona13a017
  • fix(web): keep collapsed folders closed during restorationb9d1bc4
  • test(web): cover retained file selection across explorer remounts9af9dcc
  • fix(web): preserve collapsed folders across explorer remountsa9c8803
  • test(web): cover file tree search loading and tab selection regressions8c81af2
  • fix(web): keep file reveals active after acknowledgementae67dac
  • test(web): cover retained file selection after remountbb1ce66
  • fix(web): restore retained file selection after remount6264eae
  • test(web): reproduce deep file reveal loss after explorer remount64e28e2
  • fix(web): defer file reveal acknowledgment until listings arrive2fcd03e