Refactor agent details page

Move AI model select above system prompt and add version history modal.
This commit is contained in:
gpt-engineer-app[bot]
2025-11-07 19:20:49 +00:00
parent f8966d0ae8
commit 25da60f7b2
2 changed files with 191 additions and 144 deletions
@@ -0,0 +1,122 @@
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Badge } from "@/components/ui/badge";
import { Copy } from "lucide-react";
import { useToast } from "@/hooks/use-toast";
interface VersionHistoryDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
agentName: string;
versions: Array<{
id: number;
version: string;
type: "major" | "minor" | "patch";
description: string;
prompt: string;
createdAt: string;
author: string;
}>;
}
export function VersionHistoryDialog({
open,
onOpenChange,
agentName,
versions,
}: VersionHistoryDialogProps) {
const { toast } = useToast();
const handleCopyPrompt = async (prompt: string) => {
try {
await navigator.clipboard.writeText(prompt);
toast({
title: "Copiado!",
description: "Prompt copiado para a área de transferência.",
});
} catch (error) {
toast({
title: "Erro",
description: "Não foi possível copiar o prompt.",
variant: "destructive",
});
}
};
const getVersionTypeColor = (type: string) => {
switch (type) {
case "major":
return "bg-primary text-primary-foreground";
case "minor":
return "bg-secondary text-secondary-foreground";
case "patch":
return "bg-muted text-muted-foreground";
default:
return "bg-muted text-muted-foreground";
}
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-3xl max-h-[85vh] w-[95vw] sm:w-full">
<DialogHeader>
<DialogTitle>Histórico de Versões</DialogTitle>
<DialogDescription>
Todas as alterações salvas do prompt de {agentName}
</DialogDescription>
</DialogHeader>
<ScrollArea className="h-[60vh] pr-4">
<div className="space-y-4">
{versions.map((version) => (
<div
key={version.id}
className="p-4 rounded-lg border bg-card hover:bg-accent/50 transition-colors"
>
<div className="flex items-start justify-between mb-2">
<div>
<div className="flex items-center gap-2">
<span className="font-semibold">v{version.version}</span>
<Badge className={getVersionTypeColor(version.type)}>
{version.type}
</Badge>
</div>
<p className="text-sm text-muted-foreground mt-1">
{version.description}
</p>
</div>
<Button
variant="ghost"
size="icon"
className="h-8 w-8"
onClick={() => handleCopyPrompt(version.prompt)}
>
<Copy className="h-4 w-4" />
</Button>
</div>
<div className="mt-3 p-3 rounded bg-muted/50">
<p className="text-xs font-mono text-muted-foreground line-clamp-3">
{version.prompt}
</p>
</div>
<div className="mt-3 text-xs text-muted-foreground">
<p>
{version.author} {version.createdAt}
</p>
</div>
</div>
))}
</div>
</ScrollArea>
</DialogContent>
</Dialog>
);
}
+33 -108
View File
@@ -1,20 +1,19 @@
import { useState } from "react";
import { useParams, useNavigate } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { ScrollArea } from "@/components/ui/scroll-area";
import { ArrowLeft, Bot, Save, Clock, Copy } from "lucide-react";
import { ArrowLeft, Bot, Save, History } from "lucide-react";
import { useToast } from "@/hooks/use-toast";
import { VersionHistoryDialog } from "@/components/agents/VersionHistoryDialog";
export default function AgentDetails() {
const { id } = useParams();
const navigate = useNavigate();
const { toast } = useToast();
const [isHistoryOpen, setIsHistoryOpen] = useState(false);
// Mock data - substituir por dados reais do backend
const [agent, setAgent] = useState({
@@ -73,35 +72,6 @@ export default function AgentDetails() {
});
};
const handleCopyPrompt = async (prompt: string) => {
try {
await navigator.clipboard.writeText(prompt);
toast({
title: "Copiado!",
description: "Prompt copiado para a área de transferência.",
});
} catch (error) {
toast({
title: "Erro",
description: "Não foi possível copiar o prompt.",
variant: "destructive",
});
}
};
const getVersionTypeColor = (type: string) => {
switch (type) {
case "major":
return "bg-primary text-primary-foreground";
case "minor":
return "bg-secondary text-secondary-foreground";
case "patch":
return "bg-muted text-muted-foreground";
default:
return "bg-muted text-muted-foreground";
}
};
return (
<div className="animate-fade-in pb-8">
{/* Header */}
@@ -115,7 +85,7 @@ export default function AgentDetails() {
Voltar para Agentes
</Button>
<div className="flex flex-col md:flex-row md:items-start justify-between gap-4">
<div className="flex flex-col gap-4">
<div className="flex items-start gap-4">
<div className="h-16 w-16 rounded-xl bg-primary/10 flex items-center justify-center">
<Bot className="h-8 w-8 text-primary" />
@@ -136,34 +106,24 @@ export default function AgentDetails() {
</div>
</div>
</div>
<Button className="gap-2 w-full md:w-auto" onClick={handleSave}>
<div className="flex flex-col sm:flex-row gap-2">
<Button className="gap-2 flex-1 sm:flex-initial" onClick={handleSave}>
<Save className="h-4 w-4" />
Salvar Alterações
</Button>
<Button
variant="outline"
className="gap-2 flex-1 sm:flex-initial"
onClick={() => setIsHistoryOpen(true)}
>
<History className="h-4 w-4" />
Histórico de Versões
</Button>
</div>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Left Column - Prompt & Model */}
<div className="lg:col-span-2 space-y-6">
{/* System Prompt */}
<Card>
<CardHeader>
<CardTitle>System Prompt</CardTitle>
<CardDescription>
Define o comportamento e personalidade do agente
</CardDescription>
</CardHeader>
<CardContent>
<Textarea
value={agent.systemPrompt}
onChange={(e) => setAgent({ ...agent, systemPrompt: e.target.value })}
className="min-h-[200px] font-mono text-sm"
placeholder="Digite o prompt do sistema..."
/>
</CardContent>
</Card>
<div className="space-y-6 max-w-4xl">
{/* AI Model */}
<Card>
<CardHeader>
@@ -190,67 +150,32 @@ export default function AgentDetails() {
</Select>
</CardContent>
</Card>
</div>
{/* Right Column - Version History */}
<div className="lg:col-span-1">
<Card className="h-full">
{/* System Prompt */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Clock className="h-5 w-5" />
Histórico de Versões
</CardTitle>
<CardTitle>System Prompt</CardTitle>
<CardDescription>
Todas as alterações salvas do prompt
Define o comportamento e personalidade do agente
</CardDescription>
</CardHeader>
<CardContent>
<ScrollArea className="h-[600px] pr-4">
<div className="space-y-4">
{versions.map((version) => (
<div
key={version.id}
className="p-4 rounded-lg border bg-card hover:bg-accent/50 transition-colors"
>
<div className="flex items-start justify-between mb-2">
<div>
<div className="flex items-center gap-2">
<span className="font-semibold">v{version.version}</span>
<Badge className={getVersionTypeColor(version.type)}>
{version.type}
</Badge>
</div>
<p className="text-sm text-muted-foreground mt-1">
{version.description}
</p>
</div>
<Button
variant="ghost"
size="icon"
className="h-8 w-8"
onClick={() => handleCopyPrompt(version.prompt)}
>
<Copy className="h-4 w-4" />
</Button>
</div>
<div className="mt-3 p-3 rounded bg-muted/50">
<p className="text-xs font-mono text-muted-foreground line-clamp-3">
{version.prompt}
</p>
</div>
<div className="mt-3 text-xs text-muted-foreground">
<p>{version.author} {version.createdAt}</p>
</div>
</div>
))}
</div>
</ScrollArea>
<Textarea
value={agent.systemPrompt}
onChange={(e) => setAgent({ ...agent, systemPrompt: e.target.value })}
className="min-h-[300px] font-mono text-sm"
placeholder="Digite o prompt do sistema..."
/>
</CardContent>
</Card>
</div>
</div>
<VersionHistoryDialog
open={isHistoryOpen}
onOpenChange={setIsHistoryOpen}
agentName={agent.name}
versions={versions}
/>
</div>
);
}