Skip to content

Commit 41ed015

Browse files
authored
🤖 Cmd+2 returns focus to Review tab (#338)
## Summary Pressing Cmd+2 (Ctrl+2 on Windows/Linux) while already on the Code Review tab now returns keyboard focus to the panel, enabling immediate keyboard navigation without clicking. ## Implementation Uses a simple prop trigger pattern: - `RightSidebar` increments `focusTrigger` counter when Cmd+2 is pressed on active Review tab - `ReviewPanel` watches trigger and calls `.focus()` on panel ref - Hunk selection is preserved (doesn't jump to first hunk) ## Behavior - **Cmd+1**: Switch to Costs tab - **Cmd+2**: Switch to Review tab (or refocus if already active) - **j/k/↑/↓**: Navigate between hunks (after panel has focus) - **m**: Toggle hunk read/unread - **Space**: Expand/collapse hunk ## Why This Matters Code review with keyboard is faster when you can instantly return focus from chat input to the review panel. Previously, you had to click on the panel or tab through UI elements. _Generated with `cmux`_
1 parent 5aefd57 commit 41ed015

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

src/components/RightSidebar.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
179179
// Global tab preference (not per-workspace)
180180
const [selectedTab, setSelectedTab] = usePersistedState<TabType>("right-sidebar-tab", "costs");
181181

182+
// Trigger for focusing Review panel (preserves hunk selection)
183+
const [focusTrigger, setFocusTrigger] = React.useState(0);
184+
182185
// Notify parent (AIView) of tab changes so it can enable/disable resize functionality
183186
React.useEffect(() => {
184187
onTabChange?.(selectedTab);
@@ -192,13 +195,18 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
192195
setSelectedTab("costs");
193196
} else if (matchesKeybind(e, KEYBINDS.REVIEW_TAB)) {
194197
e.preventDefault();
195-
setSelectedTab("review");
198+
// If already on Review tab, focus the panel
199+
if (selectedTab === "review") {
200+
setFocusTrigger((prev) => prev + 1);
201+
} else {
202+
setSelectedTab("review");
203+
}
196204
}
197205
};
198206

199207
window.addEventListener("keydown", handleKeyDown);
200208
return () => window.removeEventListener("keydown", handleKeyDown);
201-
}, [setSelectedTab]);
209+
}, [setSelectedTab, selectedTab]);
202210

203211
const usage = useWorkspaceUsage(workspaceId);
204212
const [use1M] = use1MContext();
@@ -337,6 +345,7 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
337345
workspaceId={workspaceId}
338346
workspacePath={workspacePath}
339347
onReviewNote={onReviewNote}
348+
focusTrigger={focusTrigger}
340349
/>
341350
</div>
342351
)}

src/components/RightSidebar/CodeReview/ReviewPanel.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ interface ReviewPanelProps {
2525
workspaceId: string;
2626
workspacePath: string;
2727
onReviewNote?: (note: string) => void;
28+
/** Trigger to focus panel (increment to trigger) */
29+
focusTrigger?: number;
2830
}
2931

3032
const PanelContainer = styled.div`
@@ -274,7 +276,9 @@ export const ReviewPanel: React.FC<ReviewPanelProps> = ({
274276
workspaceId,
275277
workspacePath,
276278
onReviewNote,
279+
focusTrigger,
277280
}) => {
281+
const panelRef = useRef<HTMLDivElement>(null);
278282
const [hunks, setHunks] = useState<DiffHunk[]>([]);
279283
const [selectedHunkId, setSelectedHunkId] = useState<string | null>(null);
280284
const [isLoadingHunks, setIsLoadingHunks] = useState(true);
@@ -322,6 +326,13 @@ export const ReviewPanel: React.FC<ReviewPanelProps> = ({
322326
includeUncommitted: includeUncommitted,
323327
});
324328

329+
// Focus panel when focusTrigger changes (preserves current hunk selection)
330+
useEffect(() => {
331+
if (focusTrigger && focusTrigger > 0) {
332+
panelRef.current?.focus();
333+
}
334+
}, [focusTrigger]);
335+
325336
// Load file tree - when workspace, diffBase, or refreshTrigger changes
326337
useEffect(() => {
327338
let cancelled = false;
@@ -633,6 +644,7 @@ export const ReviewPanel: React.FC<ReviewPanelProps> = ({
633644

634645
return (
635646
<PanelContainer
647+
ref={panelRef}
636648
tabIndex={0}
637649
onFocus={() => setIsPanelFocused(true)}
638650
onBlur={() => setIsPanelFocused(false)}

0 commit comments

Comments
 (0)