feat: Add prompt history modal
This commit is contained in:
@@ -0,0 +1,205 @@
|
|||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import { GitBranch, Clock, User, FileText, Undo2 } from "lucide-react";
|
||||||
|
|
||||||
|
interface PromptVersion {
|
||||||
|
version: string;
|
||||||
|
type: "major" | "minor" | "patch";
|
||||||
|
changeDescription: string;
|
||||||
|
systemPrompt: string;
|
||||||
|
createdAt: string;
|
||||||
|
createdBy: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PromptHistoryDialogProps {
|
||||||
|
open: boolean;
|
||||||
|
onOpenChange: (open: boolean) => void;
|
||||||
|
prompt: {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
currentVersion: string;
|
||||||
|
} | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PromptHistoryDialog({ open, onOpenChange, prompt }: PromptHistoryDialogProps) {
|
||||||
|
// Mock data - substituir por dados reais do backend
|
||||||
|
const versions: PromptVersion[] = [
|
||||||
|
{
|
||||||
|
version: "2.1.0",
|
||||||
|
type: "minor",
|
||||||
|
changeDescription: "Adicionado mais empatia nas respostas e incluídos exemplos práticos",
|
||||||
|
systemPrompt: "Você é Clara, assistente de atendimento ao cliente. Seja empática...",
|
||||||
|
createdAt: "2 dias atrás",
|
||||||
|
createdBy: "João Silva",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: "2.0.0",
|
||||||
|
type: "major",
|
||||||
|
changeDescription: "Reformulação completa do tom de voz e objetivos principais",
|
||||||
|
systemPrompt: "Você é Clara, assistente de atendimento ao cliente...",
|
||||||
|
createdAt: "1 semana atrás",
|
||||||
|
createdBy: "Maria Santos",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: "1.5.0",
|
||||||
|
type: "minor",
|
||||||
|
changeDescription: "Adicionadas instruções sobre política de devolução",
|
||||||
|
systemPrompt: "Você é um assistente virtual de atendimento...",
|
||||||
|
createdAt: "2 semanas atrás",
|
||||||
|
createdBy: "João Silva",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: "1.0.0",
|
||||||
|
type: "major",
|
||||||
|
changeDescription: "Versão inicial do prompt",
|
||||||
|
systemPrompt: "Você é um assistente virtual...",
|
||||||
|
createdAt: "1 mês atrás",
|
||||||
|
createdBy: "João Silva",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const getVersionTypeColor = (type: string) => {
|
||||||
|
switch (type) {
|
||||||
|
case "major":
|
||||||
|
return "destructive";
|
||||||
|
case "minor":
|
||||||
|
return "default";
|
||||||
|
case "patch":
|
||||||
|
return "secondary";
|
||||||
|
default:
|
||||||
|
return "secondary";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getVersionTypeLabel = (type: string) => {
|
||||||
|
switch (type) {
|
||||||
|
case "major":
|
||||||
|
return "Major";
|
||||||
|
case "minor":
|
||||||
|
return "Minor";
|
||||||
|
case "patch":
|
||||||
|
return "Patch";
|
||||||
|
default:
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRestore = (version: string) => {
|
||||||
|
console.log("Restaurar versão:", version, "do prompt:", prompt?.id);
|
||||||
|
// Implementar lógica de restauração
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!prompt) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
|
<DialogContent className="max-w-4xl max-h-[90vh]">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle className="flex items-center gap-2">
|
||||||
|
<GitBranch className="h-5 w-5" />
|
||||||
|
Histórico de Versões
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Histórico completo de versões do prompt "{prompt.title}"
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<ScrollArea className="h-[600px] pr-4">
|
||||||
|
<div className="space-y-4">
|
||||||
|
{versions.map((version, index) => (
|
||||||
|
<div key={version.version}>
|
||||||
|
<div className="flex items-start gap-4">
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
<div className={`w-3 h-3 rounded-full ${
|
||||||
|
version.version === prompt.currentVersion
|
||||||
|
? "bg-primary ring-4 ring-primary/20"
|
||||||
|
: "bg-muted-foreground"
|
||||||
|
}`} />
|
||||||
|
{index < versions.length - 1 && (
|
||||||
|
<div className="w-0.5 h-full min-h-[80px] bg-border mt-2" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 space-y-3 pb-6">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<code className="text-sm font-mono font-semibold">
|
||||||
|
v{version.version}
|
||||||
|
</code>
|
||||||
|
<Badge variant={getVersionTypeColor(version.type)}>
|
||||||
|
{getVersionTypeLabel(version.type)}
|
||||||
|
</Badge>
|
||||||
|
{version.version === prompt.currentVersion && (
|
||||||
|
<Badge variant="outline" className="bg-primary/10">
|
||||||
|
Atual
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{version.version !== prompt.currentVersion && (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => handleRestore(version.version)}
|
||||||
|
>
|
||||||
|
<Undo2 className="h-3 w-3 mr-2" />
|
||||||
|
Restaurar
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center gap-4 text-sm text-muted-foreground">
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<Clock className="h-3 w-3" />
|
||||||
|
{version.createdAt}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<User className="h-3 w-3" />
|
||||||
|
{version.createdBy}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-start gap-2">
|
||||||
|
<FileText className="h-4 w-4 mt-0.5 text-muted-foreground flex-shrink-0" />
|
||||||
|
<p className="text-sm">{version.changeDescription}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<details className="group">
|
||||||
|
<summary className="cursor-pointer text-sm text-primary hover:underline list-none flex items-center gap-1">
|
||||||
|
<span className="group-open:rotate-90 transition-transform">▶</span>
|
||||||
|
Ver conteúdo do prompt
|
||||||
|
</summary>
|
||||||
|
<div className="mt-2 p-3 bg-muted rounded-lg">
|
||||||
|
<pre className="text-xs font-mono whitespace-pre-wrap">
|
||||||
|
{version.systemPrompt}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
|
||||||
|
<Separator />
|
||||||
|
|
||||||
|
<div className="flex justify-end">
|
||||||
|
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
||||||
|
Fechar
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
+18
-1
@@ -1,6 +1,7 @@
|
|||||||
import { useState, useMemo } from "react";
|
import { useState, useMemo } from "react";
|
||||||
import { CreatePromptDialog } from "@/components/prompts/CreatePromptDialog";
|
import { CreatePromptDialog } from "@/components/prompts/CreatePromptDialog";
|
||||||
import { EditPromptDialog } from "@/components/prompts/EditPromptDialog";
|
import { EditPromptDialog } from "@/components/prompts/EditPromptDialog";
|
||||||
|
import { PromptHistoryDialog } from "@/components/prompts/PromptHistoryDialog";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -34,6 +35,7 @@ const ITEMS_PER_PAGE = 10;
|
|||||||
export default function Prompts() {
|
export default function Prompts() {
|
||||||
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
|
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
|
||||||
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
|
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
|
||||||
|
const [isHistoryDialogOpen, setIsHistoryDialogOpen] = useState(false);
|
||||||
const [selectedPrompt, setSelectedPrompt] = useState<any>(null);
|
const [selectedPrompt, setSelectedPrompt] = useState<any>(null);
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
@@ -131,6 +133,15 @@ export default function Prompts() {
|
|||||||
setIsEditDialogOpen(true);
|
setIsEditDialogOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleViewHistory = (prompt: any) => {
|
||||||
|
setSelectedPrompt({
|
||||||
|
id: prompt.id,
|
||||||
|
title: prompt.title,
|
||||||
|
currentVersion: prompt.version,
|
||||||
|
});
|
||||||
|
setIsHistoryDialogOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="animate-fade-in">
|
<div className="animate-fade-in">
|
||||||
<div className="flex items-center justify-between mb-6">
|
<div className="flex items-center justify-between mb-6">
|
||||||
@@ -207,7 +218,7 @@ export default function Prompts() {
|
|||||||
<Edit className="h-4 w-4 mr-2" />
|
<Edit className="h-4 w-4 mr-2" />
|
||||||
Editar
|
Editar
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={() => console.log("History", prompt.id)}>
|
<DropdownMenuItem onClick={() => handleViewHistory(prompt)}>
|
||||||
<History className="h-4 w-4 mr-2" />
|
<History className="h-4 w-4 mr-2" />
|
||||||
Histórico
|
Histórico
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
@@ -293,6 +304,12 @@ export default function Prompts() {
|
|||||||
onOpenChange={setIsEditDialogOpen}
|
onOpenChange={setIsEditDialogOpen}
|
||||||
prompt={selectedPrompt}
|
prompt={selectedPrompt}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<PromptHistoryDialog
|
||||||
|
open={isHistoryDialogOpen}
|
||||||
|
onOpenChange={setIsHistoryDialogOpen}
|
||||||
|
prompt={selectedPrompt}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user