import { useState } from "react"; import { IconFilePlus, IconFileMinus, IconFileX, IconArrowBackUp, IconCheck, IconGitCompare } from "@tabler/icons-react"; import { Button } from "@/components/ui/button"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { useChatStore } from "@/stores"; import { bridge } from "@/services"; import { cn } from "@/lib/utils"; import { FileChange } from "shared/types"; import { toast } from "./ui/sonner"; const STATUS_CONFIG = { Added: { icon: IconFilePlus, color: "text-green-600 dark:text-green-400" }, Deleted: { icon: IconFileX, color: "text-red-600 dark:text-red-400" }, Modified: { icon: IconFileMinus, color: "text-yellow-600 dark:text-yellow-400" }, } as const; function getTotalStats(changes: FileChange[]) { return changes.reduce( (a, c) => ({ additions: a.additions + c.additions, deletions: a.deletions + c.deletions, }), { additions: 0, deletions: 0 }, ); } interface FileItemProps { file: FileChange; onRevert: () => void; onKeep: () => void; onViewDiff: () => void; disabled: boolean; isStreaming?: boolean; } function FileItem({ file, onRevert, onKeep, onViewDiff, disabled, isStreaming }: FileItemProps) { const { icon: Icon, color } = STATUS_CONFIG[file.status]; const name = file.path.split("/").pop() || file.path; const dir = file.path.includes("/") ? file.path.slice(0, file.path.lastIndexOf("/")) : ""; return (
{name} {dir && {dir}}
View Changes {!isStreaming && ( <> Undo Changes Keep Changes )}
+{file.additions} -{file.deletions}
); } interface FileChangesPanelProps { changes: FileChange[]; } export function FileChangesPanel({ changes }: FileChangesPanelProps) { const { isStreaming } = useChatStore(); const [loading, setLoading] = useState(false); const handleRevert = async (filePath?: string) => { setLoading(true); try { await bridge.revertFiles(filePath); } catch (error) { toast.error(`Unable to undo changes: ${error instanceof Error ? error.message : String(error)}`); } finally { setLoading(false); } }; const handleKeep = async (filePath?: string) => { setLoading(true); try { await bridge.keepChanges(filePath); } catch (error) { toast.error(`Unable to keep changes: ${error instanceof Error ? error.message : String(error)}`); } finally { setLoading(false); } }; const stats = getTotalStats(changes); if (!changes.length) { return
No file changes
; } return (
{/* Header with actions */}
{changes.length} file{changes.length !== 1 ? "s" : ""}
+{stats.additions} -{stats.deletions}
{!isStreaming && (
)}
{/* File list */}
{changes.map((file) => ( { void handleRevert(file.path); }} onKeep={() => { void handleKeep(file.path); }} onViewDiff={() => { void bridge.openFileDiff(file.path); }} disabled={loading} isStreaming={isStreaming} /> ))}
); }