From b195a7c25db624d117f1ed106ac5d8e4dfc63797 Mon Sep 17 00:00:00 2001 From: Test Date: Tue, 4 Nov 2025 17:17:57 -0500 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=A4=96=20feat:=20add=20l/h=20keybinds?= =?UTF-8?q?=20to=20mark=20hunks=20as=20read/unread?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add vim-style keybindings for marking hunks in code review panel: - l: mark selected hunk as read (reviewed) - h: mark selected hunk as unread (unreviewed) Includes auto-navigation logic to maintain keyboard flow when hunks are filtered out after marking as read (when showReadHunks is false). Follows existing patterns from handleToggleRead for consistent UX. Change-Id: I0f9a9ece1d7678af6e4214e98a71f2f8d0d2073a Signed-off-by: Test --- .../RightSidebar/CodeReview/ReviewPanel.tsx | 45 ++++++++++++++++++- src/utils/ui/keybinds.ts | 6 +++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/components/RightSidebar/CodeReview/ReviewPanel.tsx b/src/components/RightSidebar/CodeReview/ReviewPanel.tsx index 2b1357130..706847f1b 100644 --- a/src/components/RightSidebar/CodeReview/ReviewPanel.tsx +++ b/src/components/RightSidebar/CodeReview/ReviewPanel.tsx @@ -167,7 +167,7 @@ export const ReviewPanel: React.FC = ({ ); // Initialize review state hook - const { isRead, toggleRead } = useReviewState(workspaceId); + const { isRead, toggleRead, markAsRead, markAsUnread } = useReviewState(workspaceId); const [filters, setFilters] = useState({ showReadHunks: showReadHunks, @@ -419,6 +419,39 @@ export const ReviewPanel: React.FC = ({ [isRead, toggleRead, filters.showReadHunks, hunks, selectedHunkId] ); + // Handle marking hunk as read with auto-navigation + const handleMarkAsRead = useCallback( + (hunkId: string) => { + const wasRead = isRead(hunkId); + markAsRead(hunkId); + + // If marking the selected hunk as read and it will be filtered out, navigate + if (hunkId === selectedHunkId && !wasRead && !filters.showReadHunks) { + // Hunk will be filtered out - move to next visible hunk + const currentFiltered = hunks.filter((h) => !isRead(h.id)); + const currentIndex = currentFiltered.findIndex((h) => h.id === hunkId); + if (currentIndex !== -1) { + if (currentIndex < currentFiltered.length - 1) { + setSelectedHunkId(currentFiltered[currentIndex + 1].id); + } else if (currentIndex > 0) { + setSelectedHunkId(currentFiltered[currentIndex - 1].id); + } else { + setSelectedHunkId(null); + } + } + } + }, + [isRead, markAsRead, filters.showReadHunks, hunks, selectedHunkId] + ); + + // Handle marking hunk as unread (no navigation needed - unread hunks are always visible) + const handleMarkAsUnread = useCallback( + (hunkId: string) => { + markAsUnread(hunkId); + }, + [markAsUnread] + ); + // Stable callbacks for HunkViewer (single callback shared across all hunks) const handleHunkClick = useCallback((e: React.MouseEvent) => { const hunkId = e.currentTarget.dataset.hunkId; @@ -496,6 +529,14 @@ export const ReviewPanel: React.FC = ({ // Toggle read state of selected hunk e.preventDefault(); handleToggleRead(selectedHunkId); + } else if (matchesKeybind(e, KEYBINDS.MARK_HUNK_READ)) { + // Mark selected hunk as read + e.preventDefault(); + handleMarkAsRead(selectedHunkId); + } else if (matchesKeybind(e, KEYBINDS.MARK_HUNK_UNREAD)) { + // Mark selected hunk as unread + e.preventDefault(); + handleMarkAsUnread(selectedHunkId); } else if (matchesKeybind(e, KEYBINDS.TOGGLE_HUNK_COLLAPSE)) { // Toggle expand/collapse state of selected hunk e.preventDefault(); @@ -508,7 +549,7 @@ export const ReviewPanel: React.FC = ({ window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); - }, [isPanelFocused, selectedHunkId, filteredHunks, handleToggleRead]); + }, [isPanelFocused, selectedHunkId, filteredHunks, handleToggleRead, handleMarkAsRead, handleMarkAsUnread]); // Global keyboard shortcuts (Ctrl+R / Cmd+R for refresh, Ctrl+F / Cmd+F for search) useEffect(() => { diff --git a/src/utils/ui/keybinds.ts b/src/utils/ui/keybinds.ts index 27a4acb27..b9ad50c2e 100644 --- a/src/utils/ui/keybinds.ts +++ b/src/utils/ui/keybinds.ts @@ -270,6 +270,12 @@ export const KEYBINDS = { /** Mark selected hunk as read/unread in Code Review panel */ TOGGLE_HUNK_READ: { key: "m" }, + /** Mark selected hunk as read in Code Review panel */ + MARK_HUNK_READ: { key: "l" }, + + /** Mark selected hunk as unread in Code Review panel */ + MARK_HUNK_UNREAD: { key: "h" }, + /** Toggle hunk expand/collapse in Code Review panel */ TOGGLE_HUNK_COLLAPSE: { key: " " }, } as const; From f4830dcc4c31f003c1e5a87c334f56d9041bae84 Mon Sep 17 00:00:00 2001 From: Test Date: Tue, 4 Nov 2025 17:21:26 -0500 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=A4=96=20fix:=20format=20code=20with?= =?UTF-8?q?=20prettier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I4744166633851256bd816785e3c4bdb661b8d7ac Signed-off-by: Test --- src/components/RightSidebar/CodeReview/ReviewPanel.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/RightSidebar/CodeReview/ReviewPanel.tsx b/src/components/RightSidebar/CodeReview/ReviewPanel.tsx index 706847f1b..98050c0b5 100644 --- a/src/components/RightSidebar/CodeReview/ReviewPanel.tsx +++ b/src/components/RightSidebar/CodeReview/ReviewPanel.tsx @@ -549,7 +549,14 @@ export const ReviewPanel: React.FC = ({ window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); - }, [isPanelFocused, selectedHunkId, filteredHunks, handleToggleRead, handleMarkAsRead, handleMarkAsUnread]); + }, [ + isPanelFocused, + selectedHunkId, + filteredHunks, + handleToggleRead, + handleMarkAsRead, + handleMarkAsUnread, + ]); // Global keyboard shortcuts (Ctrl+R / Cmd+R for refresh, Ctrl+F / Cmd+F for search) useEffect(() => {