Skip to content

feat: Enable alt/option + click to expand and collapse subdirectories recursively in the file browser#738

Merged
pedramamini merged 3 commits intoRunMaestro:rcfrom
scriptease:alt-click-expand
Apr 25, 2026
Merged

feat: Enable alt/option + click to expand and collapse subdirectories recursively in the file browser#738
pedramamini merged 3 commits intoRunMaestro:rcfrom
scriptease:alt-click-expand

Conversation

@scriptease
Copy link
Copy Markdown

@scriptease scriptease commented Apr 6, 2026

Just adding a small shortcut in the middle of the collapse and expand all button

Summary by CodeRabbit

  • New Features
    • Hold Alt and click a folder to recursively expand or collapse that folder and all descendant subfolders.
    • Recursive toggle is available from the file explorer and the right-side panel for faster navigation of deep directories.
    • Regular click still toggles a single folder; Alt‑click performs the recursive action.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 6, 2026

📝 Walkthrough

Walkthrough

Added a recursive folder-toggle handler and threaded it through the UI: Alt+clicking a folder now calls toggleFolderRecursive, which expands or collapses that folder and all descendant folders. The handler is implemented in app hooks and passed App → RightPanel → FileExplorerPanel.

Changes

Cohort / File(s) Summary
Handler Implementation
src/renderer/hooks/ui/useAppHandlers.ts
Added toggleFolderRecursive to the hook return; computes subtree descendant folder paths and updates fileExplorerExpanded to expand or collapse target plus descendants.
Props & Wiring
src/renderer/hooks/props/useRightPanelProps.ts, src/renderer/components/RightPanel.tsx, src/renderer/components/FileExplorerPanel.tsx
Added toggleFolderRecursive to deps/interfaces and prop lists; passed through useRightPanelPropsRightPanelFileExplorerPanel. FileExplorerPanel checks e.altKey in row onClick to call recursive handler; onClick now receives the mouse event.
App Entry & Tests
src/renderer/App.tsx, src/__tests__/integration/AutoRunRightPanel.test.tsx
Destructured and forwarded toggleFolderRecursive from useAppHandlers into RightPanel props. Updated tests to include a stub toggleFolderRecursive prop where RightPanel is rendered.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant FE as FileExplorerPanel
    participant RP as RightPanel
    participant Hook as useAppHandlers
    participant State as FileTreeState

    User->>FE: Click folder (Alt key)
    FE->>FE: detect e.altKey = true
    FE->>RP: toggleFolderRecursive(path, sessionId, setSessions)
    RP->>Hook: forward toggleFolderRecursive(...)
    Hook->>State: traverse fileTree, collect descendant folder paths
    Hook->>State: update fileExplorerExpanded with collected paths
    State-->>Hook: updated sessions/state
    Hook-->>FE: sessions/state changed (re-render)
    FE-->>User: folder and descendants expanded/collapsed
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Suggested labels

ready to merge

Suggested reviewers

  • reachrazamair

Poem

🐰 Alt-click I nudge a tree,
Roots and branches wake with glee.
One small hop, the burrows spread,
Leaves applaud where I have tread.
Hooray — the forest turns its head. 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 accurately describes the main feature: enabling recursive expand/collapse of subdirectories via alt+click in the file browser.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 6, 2026

Greptile Summary

This PR adds alt/option+click support to recursively expand or collapse subdirectories in the file browser. When a user holds Alt and clicks a folder, the target folder and all of its descendant folders are toggled together (expand all or collapse all), complementing the existing single-folder toggle and the global expand/collapse-all buttons.

The implementation is clean and consistent with existing patterns:

  • toggleFolderRecursive is added to useAppHandlers and wired through App.tsx → useRightPanelProps → RightPanel → FileExplorerPanel
  • The recursive tree traversal (findSubtreeFolders + collectDescendantFolders) is correct and handles nested paths properly
  • The fallback || [path] when the node isn't found in the tree is a sensible safety net

Two minor style suggestions:

  • Discoverability: There is no tooltip or visual hint indicating that alt+click does anything special. Users who don't already know about the feature are unlikely to discover it organically.
  • Helper function placement: The two recursive helper functions are defined inside the setSessionsFn state-updater callback, causing them to be recreated on each invocation. This works correctly but is unconventional and slightly less efficient for large trees.

Confidence Score: 4/5

Safe to merge — the new feature is additive and does not affect existing click behaviour.

The recursive tree traversal logic is correct; expand and collapse paths are both handled; the fallback is sensible; and the prop-drilling chain is complete. Minor concerns are limited to UX discoverability and a cosmetic code-structure point, neither of which affects correctness.

No files require special attention beyond the style suggestions already noted.

Important Files Changed

Filename Overview
src/renderer/hooks/ui/useAppHandlers.ts Adds toggleFolderRecursive with correct recursive subtree traversal; helper functions defined inside state updater (minor style concern)
src/renderer/components/FileExplorerPanel.tsx Alt+click correctly dispatches to toggleFolderRecursive; no discoverability hint (tooltip) for the new shortcut
src/renderer/hooks/props/useRightPanelProps.ts Cleanly plumbs toggleFolderRecursive through the props object and memoization dependency array
src/renderer/components/RightPanel.tsx Correctly passes toggleFolderRecursive down to FileExplorerPanel
src/renderer/App.tsx Destructures and forwards toggleFolderRecursive from useAppHandlers to right-panel props without issues

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User Alt+Clicks a folder] --> B{isFolder && e.altKey?}
    B -- Yes --> C[toggleFolderRecursive called]
    B -- No --> D[toggleFolder called — single toggle]
    C --> E[findSubtreeFolders traverses file tree]
    E --> F{Target node found?}
    F -- Yes --> G[Collect target + all descendant folder paths]
    F -- No --> H[Fallback: use only the clicked path]
    G --> I{Currently expanded?}
    H --> I
    I -- Yes --> J[Delete all collected paths from expanded set — collapse]
    I -- No --> K[Add all collected paths to expanded set — expand]
    J --> L[Update session state]
    K --> L
    L --> M[File tree re-renders with new expansion state]
Loading

Comments Outside Diff (1)

  1. src/renderer/components/FileExplorerPanel.tsx, line 1000-1014 (link)

    P2 No discoverability hint for alt+click behavior

    The alt+click recursive expand/collapse feature is completely invisible to users — there's no tooltip, visual cue, or cursor change to hint at it. Consider adding a title attribute to the folder row (or the chevron icon) so users hovering over a folder see something like 'Alt+click to expand/collapse all subfolders'.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Reviews (1): Last reviewed commit: "feat: Enable alt/option + click to expan..." | Re-trigger Greptile

Comment on lines +315 to +388
const toggleFolderRecursive = useCallback(
(
path: string,
sessionId: string,
setSessionsFn: React.Dispatch<React.SetStateAction<Session[]>>
) => {
setSessionsFn((prev) =>
prev.map((s) => {
if (s.id !== sessionId) return s;
if (!s.fileExplorerExpanded || !s.fileTree) return s;
const expanded = new Set(s.fileExplorerExpanded);
const isCurrentlyExpanded = expanded.has(path);

// Find the node at this path and collect all descendant folder paths
const collectDescendantFolders = (
nodes: typeof s.fileTree,
currentPath: string
): string[] => {
const result: string[] = [];
for (const node of nodes!) {
const fullPath = currentPath ? `${currentPath}/${node.name}` : node.name;
if (node.type === 'folder') {
result.push(fullPath);
if (node.children) {
result.push(...collectDescendantFolders(node.children, fullPath));
}
}
}
return result;
};

// Find the subtree starting at the target path
const findSubtreeFolders = (
nodes: typeof s.fileTree,
currentPath: string
): string[] | null => {
for (const node of nodes!) {
const fullPath = currentPath ? `${currentPath}/${node.name}` : node.name;
if (fullPath === path && node.type === 'folder') {
// Found the target - collect all descendants
const descendants = node.children
? collectDescendantFolders(node.children, fullPath)
: [];
return [fullPath, ...descendants];
}
if (node.type === 'folder' && node.children && path.startsWith(fullPath + '/')) {
// Recurse into this folder
const found = findSubtreeFolders(node.children, fullPath);
if (found) return found;
}
}
return null;
};

const allPaths = findSubtreeFolders(s.fileTree, '') || [path];

if (isCurrentlyExpanded) {
// Collapse: remove the folder and all descendants
for (const p of allPaths) {
expanded.delete(p);
}
} else {
// Expand: add the folder and all descendants
for (const p of allPaths) {
expanded.add(p);
}
}

return { ...s, fileExplorerExpanded: Array.from(expanded) };
})
);
},
[]
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Helper functions defined inside state updater

Both collectDescendantFolders and findSubtreeFolders are declared inside the setSessionsFn state-updater callback. They are recreated on every invocation of the updater. While this is functionally correct and unlikely to be a noticeable bottleneck for most file trees, it is an unusual pattern. Moving them outside the useCallback (as module-level helpers or into useCallback's body before the setSessionsFn call) would be cleaner and avoids any potential issue if the state updater were ever called in rapid succession on a very large tree.

// Suggested: lift helpers out of the updater callback
const collectDescendantFolders = (nodes: FileNode[], currentPath: string): string[] => { ... };
const findSubtreeFolders = (nodes: FileNode[], currentPath: string, targetPath: string): string[] | null => { ... };

const toggleFolderRecursive = useCallback(
  (path, sessionId, setSessionsFn) => {
    setSessionsFn((prev) =>
      prev.map((s) => {
        // ... use the lifted helpers
      })
    );
  },
  []
);

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@pedramamini
Copy link
Copy Markdown
Collaborator

Thanks for the contribution, @scriptease! This is a nice quality-of-life improvement.

The implementation is clean — prop threading follows the existing toggleFolder pattern exactly, the recursive tree traversal is correct, and the fallback when a node isn't found in the tree is a sensible safety net. The alt+click dispatch in FileExplorerPanel.tsx is minimal and doesn't affect existing click behavior.

Looks good to merge! 👍

… recursively in the file browser

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…scope

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Alt+click unit test for recursive folder toggle in FileExplorerPanel.
- Thread toggleFolderRecursive into existing test fixtures so new prop
  doesn't break RightPanel and AutoRunRightPanel integration tests.
- Add title tooltip on folder rows to hint at Alt/Option+click behavior.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/__tests__/integration/AutoRunRightPanel.test.tsx (1)

270-291: Optional: extract a default-props factory to reduce duplication across 11 render sites.

Each new required RightPanel prop currently has to be threaded through ~11 nearly identical call sites in this file, which is what this PR illustrates. The sibling test src/__tests__/renderer/components/RightPanel.test.tsx already uses a createDefaultProps factory (per the cross-file context snippet) for exactly this reason. Adopting the same pattern here would make future prop additions a one-line change and reduce drift between render sites. Safe to defer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/__tests__/integration/AutoRunRightPanel.test.tsx` around lines 270 - 291,
Extract a default-props factory function (e.g., createDefaultRightPanelProps) in
this test file that returns the common RightPanel props object (including
toggleFolderRecursive, handleFileClick, expandAllFolders, collapseAllFolders,
updateSessionWorkingDirectory, refreshFileTree, setSessions, showHiddenFiles,
setShowHiddenFiles, autoRunDocumentList, autoRunDocumentTree, autoRunContent,
autoRunContentVersion, autoRunIsLoadingDocuments, onAutoRunContentChange,
onAutoRunModeChange, onAutoRunStateChange, onAutoRunSelectDocument,
onAutoRunCreateDocument, onAutoRunRefresh, onAutoRunOpenSetup), and then replace
the inline prop lists at each render site with <RightPanel
{...createDefaultRightPanelProps({ overrides })}>, passing only overrides for
test-specific props like autoRunContent or handlers (e.g., autoRunContent,
handleContentChange, handleModeChange, handleStateChange) so future prop
additions are centralized and each of the ~11 render calls becomes a one-line
change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/__tests__/integration/AutoRunRightPanel.test.tsx`:
- Around line 270-291: Extract a default-props factory function (e.g.,
createDefaultRightPanelProps) in this test file that returns the common
RightPanel props object (including toggleFolderRecursive, handleFileClick,
expandAllFolders, collapseAllFolders, updateSessionWorkingDirectory,
refreshFileTree, setSessions, showHiddenFiles, setShowHiddenFiles,
autoRunDocumentList, autoRunDocumentTree, autoRunContent, autoRunContentVersion,
autoRunIsLoadingDocuments, onAutoRunContentChange, onAutoRunModeChange,
onAutoRunStateChange, onAutoRunSelectDocument, onAutoRunCreateDocument,
onAutoRunRefresh, onAutoRunOpenSetup), and then replace the inline prop lists at
each render site with <RightPanel {...createDefaultRightPanelProps({ overrides
})}>, passing only overrides for test-specific props like autoRunContent or
handlers (e.g., autoRunContent, handleContentChange, handleModeChange,
handleStateChange) so future prop additions are centralized and each of the ~11
render calls becomes a one-line change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 20a764ae-afab-4ca5-bda9-73efc498348d

📥 Commits

Reviewing files that changed from the base of the PR and between a2c0907 and 605ad62.

📒 Files selected for processing (1)
  • src/__tests__/integration/AutoRunRightPanel.test.tsx

@pedramamini
Copy link
Copy Markdown
Collaborator

Thanks again, @scriptease — appreciate the contribution!

I rebased onto rc, addressed Greptile's discoverability suggestion with a title tooltip on folder rows, and added test coverage for the Alt+click path. All checks are green. Merging now. 🚀

@pedramamini pedramamini merged commit 9d0dfc3 into RunMaestro:rc Apr 25, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants