Skip to content

Add double-click to open file in editor - #1021

Merged
Kitenite merged 1 commit into
ParadevAI:mainfrom
GateauXD:feature/file-item-double-click
Jan 28, 2026
Merged

Kitenite merged 1 commit into
ParadevAI:mainfrom
GateauXD:feature/file-item-double-click

Conversation

@GateauXD

@GateauXD GateauXD commented Jan 28, 2026 •

Copy link
Copy Markdown
Contributor

Description

Added double-click functionality to file items in the Changes View sidebar. Users can now double-click a file to open it directly in the editor, while single-click continues to work as before (selecting/highlighting the file).

The implementation uses a timeout-based approach to distinguish between single and double clicks:

  • Single click: Executes after a 300ms delay (allows time for double-click detection)
  • Double click: Immediately opens the file in the editor and cancels the pending single-click action

Related Issues

#1020

Type of Change

  • Bug fix
  • New feature
  • Documentation
  • Refactor
  • Other (please describe):

Testing

  1. Navigate to a workspace with changed files in the Changes View sidebar
  2. Single-click a file → File should be selected/highlighted (existing behavior)
  3. Double-click a file → File should open in the editor immediately
  4. Verify that double-clicking doesn't trigger the single-click action
  5. Test with different file types (modified, added, deleted, untracked)

Screenshots (if applicable)

Screen.Recording.2026-01-27.at.9.41.41.PM.mov

Summary by CodeRabbit

  • New Features
    • Enhanced file interaction: Single-click and double-click events on files now perform distinct operations. Single-click actions are debounced to differentiate from double-click, which immediately opens files in the editor. Existing file operations remain unchanged.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 28, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

A single file modification introduces single-click versus double-click differentiation to the FileItem component. A 300ms timeout mechanism debounces single-click actions while double-click events immediately trigger open-in-editor functionality, with proper cleanup on component unmount.

Changes

Cohort / File(s) Summary
Click event handling enhancement
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx
Added single-click vs double-click distinction with 300ms debounce timeout. Introduced clickTimeoutRef to track pending clicks, handleClick to execute after delay, handleDoubleClick to cancel timeout and trigger immediate action. Memoized handleOpenInEditor with useCallback and added cleanup via useEffect. Event handlers wired to file item button; existing discard/stage/unstage logic preserved.

Estimated Code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 A single click, a double tap,
With timers set upon the map,
The FileItem now knows the way,
Which action wins the light of day!
Hopping through the editor's door,
Double-click, we ask no more! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Title check ✅ Passed The title clearly and concisely describes the main change: adding double-click functionality to open files in the editor, which is the primary focus of the changeset.
Description check ✅ Passed The description includes all key template sections with complete information: clear change description, related issue link, type of change marked, detailed testing steps, and a screenshot link.

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

✨ 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.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx`:
- Around line 122-165: The single-click handler uses a hardcoded 300ms timeout
so slower double-clicks can still trigger the single-click action; extract the
timeout into a named constant (e.g. DEFAULT_DOUBLE_CLICK_DELAY) and make it
configurable (prop or config) and update handleClick/handleDoubleClick to use
that constant. Also add a lastClickTimeRef (or similar) and compare Date.now()
against it in handleClick/handleDoubleClick to detect double-clicks reliably (if
now - lastClickTimeRef.current < DELAY treat as double, cancel single click) and
ensure clickTimeoutRef is cleared in all paths; update references in
handleClick, handleDoubleClick, and the unmount effect accordingly.

Comment on lines +122 to +165
const handleOpenInEditor = useCallback(() => {
if (absolutePath && worktreePath) {
openInEditorMutation.mutate({ path: absolutePath, cwd: worktreePath });
}
};
}, [absolutePath, worktreePath, openInEditorMutation]);

const handleClick = useCallback(() => {
// Clear any pending single-click timeout
if (clickTimeoutRef.current) {
clearTimeout(clickTimeoutRef.current);
clickTimeoutRef.current = null;
}

// Set a timeout for single-click action
clickTimeoutRef.current = setTimeout(() => {
clickTimeoutRef.current = null;
onClick();
}, 300);
}, [onClick]);

const handleDoubleClick = useCallback(
(e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();

if (clickTimeoutRef.current) {
clearTimeout(clickTimeoutRef.current);
clickTimeoutRef.current = null;
}

// Execute double-click action (open in editor)
handleOpenInEditor();
},
[handleOpenInEditor],
);

// Cleanup timeout on unmount
useEffect(() => {
return () => {
if (clickTimeoutRef.current) {
clearTimeout(clickTimeoutRef.current);
}
};
}, []);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Double-click can still trigger single-click for slower double-clicks.
With a fixed 300 ms delay, users who double-click within the browser’s double‑click interval but slower than 300 ms will get both actions. Consider using a longer/configurable detection window and extract the delay into a named constant.

🛠️ Suggested fix
+const DOUBLE_CLICK_DETECTION_DELAY_MS = 500;
+
 const handleClick = useCallback(() => {
   // Clear any pending single-click timeout
   if (clickTimeoutRef.current) {
     clearTimeout(clickTimeoutRef.current);
     clickTimeoutRef.current = null;
   }

   // Set a timeout for single-click action
   clickTimeoutRef.current = setTimeout(() => {
     clickTimeoutRef.current = null;
     onClick();
-  }, 300);
+  }, DOUBLE_CLICK_DETECTION_DELAY_MS);
 }, [onClick]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleOpenInEditor = useCallback(() => {
if (absolutePath && worktreePath) {
openInEditorMutation.mutate({ path: absolutePath, cwd: worktreePath });
}
};
}, [absolutePath, worktreePath, openInEditorMutation]);
const handleClick = useCallback(() => {
// Clear any pending single-click timeout
if (clickTimeoutRef.current) {
clearTimeout(clickTimeoutRef.current);
clickTimeoutRef.current = null;
}
// Set a timeout for single-click action
clickTimeoutRef.current = setTimeout(() => {
clickTimeoutRef.current = null;
onClick();
}, 300);
}, [onClick]);
const handleDoubleClick = useCallback(
(e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
if (clickTimeoutRef.current) {
clearTimeout(clickTimeoutRef.current);
clickTimeoutRef.current = null;
}
// Execute double-click action (open in editor)
handleOpenInEditor();
},
[handleOpenInEditor],
);
// Cleanup timeout on unmount
useEffect(() => {
return () => {
if (clickTimeoutRef.current) {
clearTimeout(clickTimeoutRef.current);
}
};
}, []);
const DOUBLE_CLICK_DETECTION_DELAY_MS = 500;
const handleOpenInEditor = useCallback(() => {
if (absolutePath && worktreePath) {
openInEditorMutation.mutate({ path: absolutePath, cwd: worktreePath });
}
}, [absolutePath, worktreePath, openInEditorMutation]);
const handleClick = useCallback(() => {
// Clear any pending single-click timeout
if (clickTimeoutRef.current) {
clearTimeout(clickTimeoutRef.current);
clickTimeoutRef.current = null;
}
// Set a timeout for single-click action
clickTimeoutRef.current = setTimeout(() => {
clickTimeoutRef.current = null;
onClick();
}, DOUBLE_CLICK_DETECTION_DELAY_MS);
}, [onClick]);
const handleDoubleClick = useCallback(
(e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
if (clickTimeoutRef.current) {
clearTimeout(clickTimeoutRef.current);
clickTimeoutRef.current = null;
}
// Execute double-click action (open in editor)
handleOpenInEditor();
},
[handleOpenInEditor],
);
// Cleanup timeout on unmount
useEffect(() => {
return () => {
if (clickTimeoutRef.current) {
clearTimeout(clickTimeoutRef.current);
}
};
}, []);
🤖 Prompt for AI Agents
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx`
around lines 122 - 165, The single-click handler uses a hardcoded 300ms timeout
so slower double-clicks can still trigger the single-click action; extract the
timeout into a named constant (e.g. DEFAULT_DOUBLE_CLICK_DELAY) and make it
configurable (prop or config) and update handleClick/handleDoubleClick to use
that constant. Also add a lastClickTimeRef (or similar) and compare Date.now()
against it in handleClick/handleDoubleClick to detect double-clicks reliably (if
now - lastClickTimeRef.current < DELAY treat as double, cancel single click) and
ensure clickTimeoutRef is cleared in all paths; update references in
handleClick, handleDoubleClick, and the unmount effect accordingly.

@Kitenite Kitenite left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Amazing! I was thinking about adding this myself. And thanks for handling the cooldown edgecase

@Kitenite
Kitenite merged commit 00bf93d into ParadevAI:main Jan 28, 2026
5 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