FrontPilot / src /components /DiffReviewModal.tsx
[dyad]
Init Dyad app
a27839e
"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;