import React from 'react'; import { FileTypeIcon } from '@/components/icons/FileTypeIcon'; import { Button } from '@/components/ui/button'; import { Text } from '@/components/ui/text'; import { cn } from '@/lib/utils'; import { getApplyPatchFilePath } from './toolDiffUtils'; type ApplyPatchFileEntry = { file: Record; path: string; name: string; added: number | null; removed: number | null; }; const parseCount = (value: unknown): number | null => { if (typeof value === 'number' && Number.isFinite(value)) { return Math.max(0, Math.trunc(value)); } if (typeof value === 'string') { const parsed = Number.parseInt(value, 10); return Number.isFinite(parsed) ? Math.max(0, parsed) : null; } return null; }; const combineCounts = (base: number | null, incoming: number | null): number | null => { if (base === null) return incoming; if (incoming === null) return base; return base + incoming; }; const getApplyPatchFileEntries = (metadata: Record | undefined): ApplyPatchFileEntry[] => { const files = Array.isArray(metadata?.files) ? metadata.files : []; const entriesByPath = new Map(); for (const file of files) { if (!file || typeof file !== 'object') continue; const fileRecord = file as Record; const displayPath = typeof fileRecord.relativePath === 'string' ? fileRecord.relativePath : typeof fileRecord.filePath === 'string' ? fileRecord.filePath : ''; if (!displayPath) continue; const added = parseCount(fileRecord.additions); const removed = parseCount(fileRecord.deletions); const existing = entriesByPath.get(displayPath); if (existing) { existing.added = combineCounts(existing.added, added); existing.removed = combineCounts(existing.removed, removed); continue; } entriesByPath.set(displayPath, { file: fileRecord, path: displayPath, name: displayPath.split('/').pop() || displayPath, added, removed, }); } return Array.from(entriesByPath.values()); }; export const ApplyPatchFileButtons = ({ animate = true, metadata, onFileClick, openDiffLabel, showFileIcons = true, textClassName, }: { animate?: boolean; metadata: Record | undefined; onFileClick?: (file: Record, event: React.MouseEvent) => void; openDiffLabel: string; showFileIcons?: boolean; textClassName?: string; }): React.ReactNode => { const entries = getApplyPatchFileEntries(metadata); if (entries.length <= 1) return null; return ( <> {entries.map((entry) => { const hasPerFileDiff = entry.added !== null || entry.removed !== null; const content = ( <> {showFileIcons ? : null} {entry.name} {hasPerFileDiff ? ( +{entry.added ?? 0} / -{entry.removed ?? 0} ) : null} ); const canOpen = onFileClick && entry.file.type !== 'delete' && getApplyPatchFilePath(entry.file); const actionLabel = `${openDiffLabel}: ${entry.path}`; return canOpen ? ( ) : ( {content} ); })} ); };