@@ -3,6 +3,8 @@ import { isDiffTabActiveInTree, usePanelLayoutStore } from "@features/panels";
33import { useTaskData } from "@features/task-detail/hooks/useTaskData" ;
44import {
55 ArrowCounterClockwiseIcon ,
6+ CaretDownIcon ,
7+ CaretUpIcon ,
68 CodeIcon ,
79 CopyIcon ,
810 FileIcon ,
@@ -22,7 +24,8 @@ import { useExternalAppsStore } from "@stores/externalAppsStore";
2224import { useQuery , useQueryClient } from "@tanstack/react-query" ;
2325import { showMessageBox } from "@utils/dialog" ;
2426import { handleExternalAppAction } from "@utils/handleExternalAppAction" ;
25- import { useState } from "react" ;
27+ import { useCallback , useState } from "react" ;
28+ import { useHotkeys } from "react-hotkeys-hook" ;
2629import {
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