Skip to content

Commit a97ff4a

Browse files
feat: Add hotkeys to switch between files in the changes panel (#211)
Co-authored-by: JonathanLab <[email protected]>
1 parent f9bb507 commit a97ff4a

File tree

1 file changed

+49
-1
lines changed

1 file changed

+49
-1
lines changed

apps/array/src/renderer/features/task-detail/components/ChangesPanel.tsx

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { isDiffTabActiveInTree, usePanelLayoutStore } from "@features/panels";
33
import { useTaskData } from "@features/task-detail/hooks/useTaskData";
44
import {
55
ArrowCounterClockwiseIcon,
6+
CaretDownIcon,
7+
CaretUpIcon,
68
CodeIcon,
79
CopyIcon,
810
FileIcon,
@@ -22,7 +24,8 @@ import { useExternalAppsStore } from "@stores/externalAppsStore";
2224
import { useQuery, useQueryClient } from "@tanstack/react-query";
2325
import { showMessageBox } from "@utils/dialog";
2426
import { handleExternalAppAction } from "@utils/handleExternalAppAction";
25-
import { useState } from "react";
27+
import { useCallback, useState } from "react";
28+
import { useHotkeys } from "react-hotkeys-hook";
2629
import {
2730
selectWorktreePath,
2831
useWorkspaceStore,
@@ -344,6 +347,7 @@ export function ChangesPanel({ taskId, task }: ChangesPanelProps) {
344347
const worktreePath = useWorkspaceStore(selectWorktreePath(taskId));
345348
const repoPath = worktreePath ?? taskData.repoPath;
346349
const layout = usePanelLayoutStore((state) => state.getLayout(taskId));
350+
const openDiff = usePanelLayoutStore((state) => state.openDiff);
347351

348352
const { data: changedFiles = [], isLoading } = useQuery({
349353
queryKey: ["changed-files-head", repoPath],
@@ -352,6 +356,40 @@ export function ChangesPanel({ taskId, task }: ChangesPanelProps) {
352356
refetchOnMount: "always",
353357
});
354358

359+
const getActiveIndex = useCallback((): number => {
360+
if (!layout) return -1;
361+
return changedFiles.findIndex((file) =>
362+
isDiffTabActiveInTree(layout.panelTree, file.path, file.status),
363+
);
364+
}, [layout, changedFiles]);
365+
366+
const handleKeyNavigation = useCallback(
367+
(direction: "up" | "down") => {
368+
if (changedFiles.length === 0) return;
369+
370+
const currentIndex = getActiveIndex();
371+
const startIndex =
372+
currentIndex === -1
373+
? direction === "down"
374+
? -1
375+
: changedFiles.length
376+
: currentIndex;
377+
const newIndex =
378+
direction === "up"
379+
? Math.max(0, startIndex - 1)
380+
: Math.min(changedFiles.length - 1, startIndex + 1);
381+
382+
const file = changedFiles[newIndex];
383+
if (file) {
384+
openDiff(taskId, file.path, file.status);
385+
}
386+
},
387+
[changedFiles, getActiveIndex, openDiff, taskId],
388+
);
389+
390+
useHotkeys("up", () => handleKeyNavigation("up"), [handleKeyNavigation]);
391+
useHotkeys("down", () => handleKeyNavigation("down"), [handleKeyNavigation]);
392+
355393
const isFileActive = (file: ChangedFile): boolean => {
356394
if (!layout) return false;
357395
return isDiffTabActiveInTree(layout.panelTree, file.path, file.status);
@@ -381,6 +419,16 @@ export function ChangesPanel({ taskId, task }: ChangesPanelProps) {
381419
isActive={isFileActive(file)}
382420
/>
383421
))}
422+
<Flex align="center" justify="center" gap="1" py="2">
423+
<CaretUpIcon size={12} color="var(--gray-10)" />
424+
<Text size="1" className="text-gray-10">
425+
/
426+
</Text>
427+
<CaretDownIcon size={12} color="var(--gray-10)" />
428+
<Text size="1" className="text-gray-10" ml="1">
429+
to switch files
430+
</Text>
431+
</Flex>
384432
</Flex>
385433
</Box>
386434
);

0 commit comments

Comments
 (0)