Skip to content

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

Open
scriptease wants to merge 2 commits intoRunMaestro:rcfrom
scriptease:alt-click-expand
Open

feat: Enable alt/option + click to expand and collapse subdirectories recursively in the file browser#738
scriptease wants to merge 2 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
    • Added recursive folder expand/collapse: hold Alt and click a folder to expand or collapse that folder and all descendant subfolders at once.
    • This behavior is available from the file explorer and right-side panel, making navigation of deeply nested directories faster.

… recursively in the file browser

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d19cf024-7a44-4c50-8073-89319b898aab

📥 Commits

Reviewing files that changed from the base of the PR and between 7b53a00 and c5c4291.

📒 Files selected for processing (1)
  • src/renderer/hooks/ui/useAppHandlers.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/renderer/hooks/ui/useAppHandlers.ts

📝 Walkthrough

Walkthrough

A new recursive folder toggle was added: pressing Alt while clicking a folder calls toggleFolderRecursive, which expands or collapses the target folder and all descendant folders. The handler is implemented in the app hooks and wired through props to the right-panel and file-explorer UI.

Changes

Cohort / File(s) Summary
Handler Implementation
src/renderer/hooks/ui/useAppHandlers.ts
Added toggleFolderRecursive that traverses the file tree to collect descendant folder paths and updates fileExplorerExpanded to toggle the target folder plus all descendants.
Props Composition
src/renderer/hooks/props/useRightPanelProps.ts, src/renderer/components/RightPanel.tsx, src/renderer/components/FileExplorerPanel.tsx
Added toggleFolderRecursive to props/interfaces, threaded it through useRightPanelPropsRightPanelFileExplorerPanel. FileExplorerPanel now inspects e.altKey on folder clicks to call the recursive handler.
App Wiring
src/renderer/App.tsx
Destructured toggleFolderRecursive from useAppHandlers and passed it to RightPanel, completing the handler wiring from hook to UI.

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: invoke prop -> toggleFolderRecursive(path, sessionId, setSessions)
    RP->>Hook: forward toggleFolderRecursive(...)
    Hook->>State: traverse fileTree, collect descendant folder paths
    Hook->>State: update fileExplorerExpanded with all collected paths
    State-->>Hook: updated
    Hook-->>FE: sessions/state changed (re-render)
    FE-->>User: folder and descendants expanded/collapsed
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I nudge a branch with Alt held tight,
Descendants wake and dance in light.
One hop, one call, the forest sings,
Folders open on rabbit wings.
Recursive joy — a tidy spring! 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 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 (2 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 Alt/Option + click to recursively expand/collapse subdirectories in the file browser, which matches the core changes across all modified files.

✏️ 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! 👍

…scope

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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