fix(file-explorer): search folder workspace roots#6567
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthrough
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
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. Comment |
EvidenceRegression guard proves the bug (before/after)The new hook test Before the fix (temporarily reverting the hook to resolve via After the fix (resolving via Focused test run (after fix)Nearby regression suites: Lint / typecheckElectron repro noteI launched the dev build from this worktree over CDP (port 9335, confirmed instance |
The file-explorer name search returned zero results whenever the workspace root was a monorepo parent opened as a FolderWorkspace. useRuntimeFileListForWorktree resolved its worktree via useWorktreeById, which only reads worktreesByRepo, so a folder-workspace key resolved to null and the effect early-returned with setFiles([]). Resolve the Quick Open file-list target through getKnownWorktreeById so folder workspaces supply their root path (folderPath) even when absent from worktreesByRepo, and recompute connectionId from subscribed store state via getConnectionIdFromState so SSH folder roots are not left stale after hydration. Supersedes community PR #6170; adds a dedicated getConnectionIdFromState unit test that asserts resolution from a passed-in state snapshot. Fixes #5939 Co-authored-by: bennewell35 <142949922+bennewell35@users.noreply.github.com>
ddd35be to
3b9a9b5
Compare
🧑🤝🧑 Impact & ELI5
1) What's broken today (ELI5). If you open Orca on the top folder of a "monorepo" (one big folder that holds several sub-projects), the file explorer's name search is completely broken. The full file tree shows up fine — but the moment you type anything into the search box (like
package), the whole list goes blank and shows zero results. Clear the box and everything comes back. So the search isn't filtering, it's just wiping the screen. This hits anyone who opens a workspace at a monorepo root (a "folder" workspace), on any OS; for those people file search simply does not work — a real blocker, not a cosmetic annoyance. People who open one specific sub-folder instead of the whole monorepo were never affected.2) What this PR does (ELI5). When you search, Orca first has to figure out "which folder am I searching in?" There were two address books for that: one for normal git checkouts, and a fuller one that also knows about plain folders opened as workspaces. The search was only consulting the git-only address book, so for a monorepo-root folder it found nothing, decided it had no place to look, and returned an empty list. This PR points the search at the fuller address book that also knows about folder workspaces. Oh, so now searching a monorepo root actually returns matching files instead of going blank. (As a bonus, it also fixes a related case where searching over a remote/SSH folder could stay empty until the app finished loading its data.)
3) Tradeoffs / regressions — honest answer. No regressions — nothing is disabled, no flag is turned off, no new setup, and no behavior is lost. The fix only adds a working lookup path for folder workspaces; the old shared connection-lookup helper that other features rely on (terminal, delete-workspace, tab creation, etc.) is kept untouched and behaves exactly as before. One small implementation detail: the search now "watches" the connection info live (a store subscription) instead of taking a one-time snapshot — this is precisely what fixes the remote/SSH stale case, and it's safe because the watched value is a stable primitive and the synthetic folder entry is cached and reused, so there are no extra re-renders or render loops. One honest scope note (not a regression): this PR fixes "search returns nothing." The issue's secondary wish — surfacing matches buried deep inside nested sub-project directories under the monorepo root — is handled separately in companion PR #6481, so very deeply nested matches remain out of scope here.
Summary
Fixes #5939. The file-explorer name search returned zero results whenever the workspace root was a monorepo parent opened as a
FolderWorkspace(folder-scan), even though the full tree still rendered.Root cause:
useRuntimeFileListForWorktree(src/renderer/src/components/quick-open-file-list.ts) resolved its worktree viauseWorktreeById, which only readsworktreesByRepo(git worktrees). For a folder-workspaceactiveWorktreeId, that key is not inworktreesByRepo, soworktreewasnull,worktreePathbecamenull, and the effect early-returned withsetFiles([]). The tree still rendered becauseuseFileExplorerTreegetsworktreePathseparately.This change:
getKnownWorktreeById, which resolves folder workspaces to a syntheticWorktreewhosepath = folderPath(folderWorkspaceToWorktree), restoring a non-nullworktreePath.getRuntimeFileListTargethelper for the path/exclude resolution so it is directly unit-testable.connectionIda reactive store selector via the newly exportedgetConnectionIdFromState, so SSH folder roots are not left stale after store hydration. The existinggetConnectionIdwrapper is preserved for all other callers (Terminal, DeleteWorktreeDialog, tab-create, pty transport, etc.).This supersedes community PR #6170 (the code becomes ours; original author credited via
Co-authored-by). It does not close #6170.Screenshots
No visual change to chrome/layout. This is a data-loading regression: with the fix, typing a substring in the file-explorer name search now returns matching files for a folder-workspace root instead of an empty list. End-to-end Electron repro was attempted over CDP but the CDP session repeatedly dropped mid-interaction in this environment and
window.__storewas not exposed in the dev build, so visual capture was infeasible; the regression is instead proven deterministically by a hook-level test (see PR comment for evidence).Testing
pnpm lint(scoped:oxlinton the 5 touched files — clean)pnpm typecheck(tsgo -p config/tsconfig.tc.web.jsonandconfig/tsconfig.node.json— clean)pnpm test(focused: see below)pnpm buildFocused tests run:
vitest run src/renderer/src/components/quick-open-file-list.test.ts src/renderer/src/components/quick-open-file-list.react.test.tsx src/renderer/src/lib/connection-context.test.ts— 17 passedvitest run src/renderer/src/lib/worktree-runtime-owner.test.ts src/renderer/src/components/right-sidebar/useFileExplorerVisibleRowProjection.test.ts— 25 passedvitest run --environment happy-dom src/renderer/src/components/right-sidebar/FileExplorer.test.tsx— 31 passedThe new
quick-open-file-list.react.test.tsxrenders the real hook against the real zustand store for a repo-less folder workspace and assertslistRuntimeFilesis invoked with the folder'sworktreePath. Reverting the fix (resolving viaworktreesByRepoonly) makes it fail withlistRuntimeFiles was not called— i.e. it reproduces the bug.AI Review Report
Reviewed for correctness, edge cases, cross-platform behavior, and store-reactivity:
getConnectionIdFromStatereturns a primitive (no new-object churn);getKnownWorktreeByIdreturns cached synthetic worktrees (WeakMap-keyed) and stored worktree objects, so the newuseAppStoreselectors are reference-stable and do not loop.getConnectionIdcallers go through the preserved wrapper (getConnectionIdFromState(useAppStore.getState(), id)); behavior is unchanged.metaKey/ path-separator assumptions introduced; path containment continues to flow through the existing Windows-awareisNestedWorktreePath. macOS/Linux/Windows behavior is identical here.connectionIdreactivity fixes the stale-after-hydration case for SSH folder roots, which is the SSH-relevant path.Pick<AppState, 'folderWorkspaces' | 'projectGroups' | 'repos' | 'worktreesByRepo'>param togetConnectionIdFromStatetypechecks against the store slices.Security Audit
Since this supersedes a community PR, I re-audited the adopted changes assuming the original author was untrusted:
eval, dynamicimport, secret access, or process spawning.listRuntimeFilesIPC; no new path is constructed or de-referenced.listRuntimeFiles({ settings, worktreeId, worktreePath, connectionId }, { rootPath, excludePaths })call shape.Notes
createRoot/act/flushEffectsharness; a lighter@testing-library/reactrenderHookcould simplify it if/when that dependency is standard in the renderer test suite. Left as-is to keep the diff minimal and consistent with the adopted PR.Made with Orca 🐋