Spaces:
Running
Running
| "use client"; | |
| import { useState } from "react"; | |
| import { Button } from "@/components/ui/button"; | |
| import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; | |
| import { ScrollArea } from "@/components/ui/scroll-area"; | |
| import { DiffResult } from "@/services/diffPatch"; | |
| import { Card, CardContent } from "@/components/ui/card"; | |
| interface DiffReviewModalProps { | |
| isOpen: boolean; | |
| onClose: () => void; | |
| diffResult: DiffResult | null; | |
| onApply: () => void; | |
| } | |
| const DiffReviewModal = ({ isOpen, onClose, diffResult, onApply }: DiffReviewModalProps) => { | |
| const [isApplying, setIsApplying] = useState(false); | |
| const handleApply = async () => { | |
| setIsApplying(true); | |
| try { | |
| await onApply(); | |
| onClose(); | |
| } finally { | |
| setIsApplying(false); | |
| } | |
| }; | |
| if (!diffResult) return null; | |
| let oldLineNum = 1; | |
| let newLineNum = 1; | |
| return ( | |
| <Dialog open={isOpen} onOpenChange={onClose}> | |
| <DialogContent className="max-w-4xl h-[80vh] flex flex-col"> | |
| <DialogHeader> | |
| <DialogTitle className="flex items-center"> | |
| <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="mr-2"> | |
| <path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/> | |
| <path d="M14 15H9"/> | |
| <path d="M16 12c.5523 0 1-.4477 1-1s-.4477-1-1-1-.999.4477-.999 1 .4467 1 .999 1Z"/> | |
| <path d="M16 18c1.6569 0 3-1.3431 3-3s-1.3431-3-3-3-3 1.3431-3 3 1.3431 3 3 3Z"/> | |
| <path d="m17 2 4 4"/> | |
| <path d="M21 2 12 11"/> | |
| </svg> | |
| Code Changes Review | |
| </DialogTitle> | |
| </DialogHeader> | |
| <div className="text-sm text-gray-500 mb-2 flex items-center"> | |
| <span className="bg-green-100 text-green-800 px-2 py-1 rounded mr-2">+{diffResult.added} lines</span> | |
| <span className="bg-red-100 text-red-800 px-2 py-1 rounded">-{diffResult.removed} lines</span> | |
| </div> | |
| <Card className="flex-1 border border-gray-200 min-h-0"> | |
| <CardContent className="p-0 h-full"> | |
| <ScrollArea className="h-full font-mono text-sm bg-gray-50 rounded-md"> | |
| <div className="p-4"> | |
| {diffResult.changes.map((change, changeIndex) => { | |
| const lines = change.value.endsWith('\n') ? change.value.slice(0, -1).split('\n') : change.value.split('\n'); | |
| return lines.map((line, lineIndex) => { | |
| let currentOldLine = ' '; | |
| let currentNewLine = ' '; | |
| if (change.removed) { | |
| currentOldLine = String(oldLineNum++); | |
| } else if (change.added) { | |
| currentNewLine = String(newLineNum++); | |
| } else { | |
| currentOldLine = String(oldLineNum++); | |
| currentNewLine = String(newLineNum++); | |
| } | |
| return ( | |
| <div | |
| key={`${changeIndex}-${lineIndex}`} | |
| className={`flex items-start py-0.5 ${ | |
| change.added ? 'bg-green-100' : | |
| change.removed ? 'bg-red-100' : '' | |
| }`} | |
| > | |
| <span className="w-10 text-right pr-2 text-gray-400 select-none">{currentOldLine}</span> | |
| <span className="w-10 text-right pr-2 text-gray-400 select-none">{currentNewLine}</span> | |
| <span className={`w-6 text-center font-bold ${ | |
| change.added ? 'text-green-700' : | |
| change.removed ? 'text-red-700' : 'text-gray-500' | |
| }`}> | |
| {change.added ? '+' : change.removed ? '-' : ' '} | |
| </span> | |
| <span className={`flex-1 whitespace-pre-wrap break-all ${ | |
| change.added ? 'text-green-900' : | |
| change.removed ? 'text-red-900' : 'text-gray-800' | |
| }`}> | |
| {line} | |
| </span> | |
| </div> | |
| ); | |
| }); | |
| })} | |
| </div> | |
| </ScrollArea> | |
| </CardContent> | |
| </Card> | |
| <DialogFooter className="flex space-x-2 pt-4"> | |
| <Button variant="outline" onClick={onClose} className="border-gray-300"> | |
| Cancel | |
| </Button> | |
| <Button | |
| onClick={handleApply} | |
| disabled={isApplying} | |
| className="bg-gradient-to-r from-blue-600 to-indigo-700 hover:from-blue-700 hover:to-indigo-800" | |
| > | |
| {isApplying ? ( | |
| <> | |
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="mr-2 animate-spin"> | |
| <path d="M21 12a9 9 0 1 1-6.219-8.56"/> | |
| </svg> | |
| Applying... | |
| </> | |
| ) : ( | |
| "Apply Changes" | |
| )} | |
| </Button> | |
| </DialogFooter> | |
| </DialogContent> | |
| </Dialog> | |
| ); | |
| }; | |
| export default DiffReviewModal; |