Files
next-ai-draw-io/components/history-dialog.tsx
Dayuan Jiang 0baf21fadb fix: validate XML before displaying diagram to catch duplicate IDs (#147)
- Add validation to loadDiagram in diagram-context, returns error or null
- display_diagram and edit_diagram tools now check validation result
- Return error to AI agent with state: output-error so it can retry
- Skip validation for trusted sources (localStorage, history, internal templates)
- Add debug logging for tool call inputs to diagnose Bedrock API issues
2025-12-07 14:38:15 +09:00

113 lines
4.3 KiB
TypeScript

"use client"
import Image from "next/image"
import { useState } from "react"
import { Button } from "@/components/ui/button"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
import { useDiagram } from "@/contexts/diagram-context"
interface HistoryDialogProps {
showHistory: boolean
onToggleHistory: (show: boolean) => void
}
export function HistoryDialog({
showHistory,
onToggleHistory,
}: HistoryDialogProps) {
const { loadDiagram: onDisplayChart, diagramHistory } = useDiagram()
const [selectedIndex, setSelectedIndex] = useState<number | null>(null)
const handleClose = () => {
setSelectedIndex(null)
onToggleHistory(false)
}
const handleConfirmRestore = () => {
if (selectedIndex !== null) {
// Skip validation for trusted history snapshots
onDisplayChart(diagramHistory[selectedIndex].xml, true)
handleClose()
}
}
return (
<Dialog open={showHistory} onOpenChange={onToggleHistory}>
<DialogContent className="max-w-3xl max-h-[80vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>Diagram History</DialogTitle>
<DialogDescription>
Here saved each diagram before AI modification.
<br />
Click on a diagram to restore it
</DialogDescription>
</DialogHeader>
{diagramHistory.length === 0 ? (
<div className="text-center p-4 text-gray-500">
No history available yet. Send messages to create
diagram history.
</div>
) : (
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 py-4">
{diagramHistory.map((item, index) => (
<div
key={index}
className={`border rounded-md p-2 cursor-pointer hover:border-primary transition-colors ${
selectedIndex === index
? "border-primary ring-2 ring-primary"
: ""
}`}
onClick={() => setSelectedIndex(index)}
>
<div className="aspect-video bg-white rounded overflow-hidden flex items-center justify-center">
<Image
src={item.svg}
alt={`Diagram version ${index + 1}`}
width={200}
height={100}
className="object-contain w-full h-full p-1"
/>
</div>
<div className="text-xs text-center mt-1 text-gray-500">
Version {index + 1}
</div>
</div>
))}
</div>
)}
<DialogFooter>
{selectedIndex !== null ? (
<>
<div className="flex-1 text-sm text-muted-foreground">
Restore to Version {selectedIndex + 1}?
</div>
<Button
variant="outline"
onClick={() => setSelectedIndex(null)}
>
Cancel
</Button>
<Button onClick={handleConfirmRestore}>
Confirm
</Button>
</>
) : (
<Button variant="outline" onClick={handleClose}>
Close
</Button>
)}
</DialogFooter>
</DialogContent>
</Dialog>
)
}