| 390 | selectedHash: string | null |
| 391 | onSelectCommit: (commit: GitLogEntry) => void |
| 392 | }> = ({ workingDir, selectedHash, onSelectCommit }) => { |
| 393 | const { t } = useI18n() |
| 394 | const { |
| 395 | data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage, |
| 396 | } = useInfiniteQuery({ |
| 397 | queryKey: queryKeys.git.log(workingDir), |
| 398 | queryFn: ({ pageParam = 0 }) => |
| 399 | apiClient.get<GitLogResponse>('/git/log', { |
| 400 | params: { workingDir, limit: String(PAGE_SIZE), skip: String(pageParam) }, |
| 401 | }), |
| 402 | initialPageParam: 0, |
| 403 | getNextPageParam: (lastPage, allPages) => |
| 404 | lastPage.commits.length < PAGE_SIZE ? undefined : allPages.length * PAGE_SIZE, |
| 405 | }) |
| 406 | |
| 407 | const commits = data?.pages.flatMap((p) => p.commits) || [] |
| 408 | |
| 409 | if (isLoading) { |
| 410 | return ( |
| 411 | <div className="flex items-center gap-1.5 px-3 py-2 text-muted-foreground/70 text-[11px]"> |
| 412 | <Loader2 size={11} className="animate-spin" /> |
| 413 | <span>{t('正在加载提交记录...')}</span> |
| 414 | </div> |
| 415 | ) |
| 416 | } |
| 417 | if (commits.length === 0) { |
| 418 | return <div className="px-3 py-2 text-[11px] text-muted-foreground/60">{t('暂无提交记录')}</div> |
| 419 | } |
| 420 | |
| 421 | return ( |
| 422 | <div className="space-y-px px-1.5 pb-1.5"> |
| 423 | {commits.map((commit) => { |
| 424 | const active = selectedHash === commit.hash |
| 425 | return ( |
| 426 | <button |
| 427 | key={commit.hash} |
| 428 | type="button" |
| 429 | onClick={() => onSelectCommit(commit)} |
| 430 | className={cn( |
| 431 | 'flex items-start gap-1.5 w-full px-1.5 py-1 rounded-sm text-left group', |
| 432 | active ? 'bg-muted' : 'hover:bg-muted/60', |
| 433 | )} |
| 434 | title={commit.message} |
| 435 | > |
| 436 | <span className={cn( |
| 437 | 'w-1.5 h-1.5 rounded-full mt-1.5 shrink-0 transition-colors', |
| 438 | active ? 'bg-brand' : 'bg-border group-hover:bg-muted-foreground/60', |
| 439 | )} /> |
| 440 | <span className="flex-1 min-w-0"> |
| 441 | <span className={cn('block text-xs truncate', active ? 'text-foreground font-medium' : 'text-foreground/90')}> |
| 442 | {commit.message} |
| 443 | </span> |
| 444 | <span className="block text-[11px] text-muted-foreground/70 truncate"> |
| 445 | <span className="font-mono">{commit.shortHash}</span> |
| 446 | {' · '}{commit.author}{' · '}{timeAgo(commit.timestamp)} |
| 447 | </span> |
| 448 | </span> |
| 449 | </button> |