({ workingDir })
| 120 | ) |
| 121 | } |
| 122 | |
| 123 | /** History Tab main component */ |
| 124 | export const HistoryView: React.FC<{ workingDir?: string }> = ({ workingDir }) => { |
| 125 | const { t } = useI18n() |
| 126 | const visibleContext = useGitVisibilityStore((state) => state.visibleContext) |
| 127 | const refreshInterval = getGitHistoryRefreshInterval(workingDir, visibleContext) |
| 128 | const { |
| 129 | data, isLoading, isError, fetchNextPage, hasNextPage, isFetchingNextPage, |
| 130 | } = useInfiniteQuery({ |
| 131 | queryKey: queryKeys.git.log(workingDir || ''), |
| 132 | queryFn: ({ pageParam = 0 }) => |
| 133 | apiClient.get<GitLogResponse>('/git/log', { |
| 134 | params: { workingDir: workingDir || '', limit: String(PAGE_SIZE), skip: String(pageParam) }, |
| 135 | }), |
| 136 | initialPageParam: 0, |
| 137 | getNextPageParam: (lastPage, allPages) => |
| 138 | lastPage.commits.length < PAGE_SIZE ? undefined : allPages.length * PAGE_SIZE, |
| 139 | enabled: !!workingDir, |
| 140 | refetchInterval: refreshInterval, |
| 141 | refetchIntervalInBackground: false, |
| 142 | refetchOnWindowFocus: refreshInterval ? 'always' : false, |
| 143 | refetchOnReconnect: refreshInterval ? 'always' : false, |
| 144 | }) |
| 145 | |
| 146 | const commits = data?.pages.flatMap(p => p.commits) || [] |
| 147 | |
| 148 | const [selectedHash, setSelectedHash] = useState<string | null>(null) |
| 149 | const [selectedFile, setSelectedFile] = useState<string | null>(null) |
| 150 | |
| 151 | // Resizable left panel |
| 152 | const [panelWidth, setPanelWidth] = useState(280) |
| 153 | const [isDragging, setIsDragging] = useState(false) |
| 154 | const onDragStart = useCallback((e: React.MouseEvent) => { |
| 155 | e.preventDefault() |
| 156 | setIsDragging(true) |
| 157 | const startX = e.clientX |
| 158 | const startWidth = panelWidth |
| 159 | const onMouseMove = (ev: MouseEvent) => { |
| 160 | const next = Math.min(480, Math.max(180, startWidth + (ev.clientX - startX))) |
| 161 | setPanelWidth(next) |
| 162 | } |
| 163 | const onMouseUp = () => { |
| 164 | setIsDragging(false) |
| 165 | document.removeEventListener('mousemove', onMouseMove) |
| 166 | document.removeEventListener('mouseup', onMouseUp) |
| 167 | } |
| 168 | document.addEventListener('mousemove', onMouseMove) |
| 169 | document.addEventListener('mouseup', onMouseUp) |
| 170 | }, [panelWidth]) |
| 171 | |
| 172 | const handleSelectCommit = (hash: string) => { |
| 173 | if (selectedHash === hash) { setSelectedHash(null); setSelectedFile(null) } |
| 174 | else { setSelectedHash(hash); setSelectedFile(null) } |
| 175 | } |
| 176 | |
| 177 | // Scroll container ref for load-more detection |
| 178 | const scrollRef = useRef<HTMLDivElement>(null) |
| 179 |
nothing calls this directly
no test coverage detected