a18f785bb0
Update inline name editing to local state only; persist on Save Alterações button. Remove instant save behavior and inline confirm/cancel actions; simplify to editable input with local state updates and final save handled by existing SaveVersionDialog.
296 lines
10 KiB
TypeScript
296 lines
10 KiB
TypeScript
import { useState } from "react";
|
|
import { useParams, useNavigate } from "react-router-dom";
|
|
import { Button } from "@/components/ui/button";
|
|
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 { ArrowLeft, Save, History, Power, Pencil } from "lucide-react";
|
|
import { useToast } from "@/hooks/use-toast";
|
|
import { VersionHistoryDialog } from "@/components/agents/VersionHistoryDialog";
|
|
import { SaveVersionDialog } from "@/components/agents/SaveVersionDialog";
|
|
import { Input } from "@/components/ui/input";
|
|
import {
|
|
AlertDialog,
|
|
AlertDialogAction,
|
|
AlertDialogCancel,
|
|
AlertDialogContent,
|
|
AlertDialogDescription,
|
|
AlertDialogFooter,
|
|
AlertDialogHeader,
|
|
AlertDialogTitle,
|
|
} from "@/components/ui/alert-dialog";
|
|
|
|
export default function AgentDetails() {
|
|
const { id } = useParams();
|
|
const navigate = useNavigate();
|
|
const { toast } = useToast();
|
|
const [isHistoryOpen, setIsHistoryOpen] = useState(false);
|
|
const [isSaveVersionOpen, setIsSaveVersionOpen] = useState(false);
|
|
const [isDeactivateDialogOpen, setIsDeactivateDialogOpen] = useState(false);
|
|
const [isEditingName, setIsEditingName] = useState(false);
|
|
const [tempName, setTempName] = useState("");
|
|
|
|
// Mock data - substituir por dados reais do backend
|
|
const [agent, setAgent] = useState<{
|
|
id: string | undefined;
|
|
name: string;
|
|
status: "active" | "inactive";
|
|
model: string;
|
|
systemPrompt: string;
|
|
}>({
|
|
id: id,
|
|
name: "Agente de Atendimento",
|
|
status: "active",
|
|
model: "google/gemini-2.5-flash",
|
|
systemPrompt: "Você é um assistente de atendimento ao cliente. Seja educado, prestativo e objetivo nas suas respostas. Sempre mantenha um tom profissional e cordial.",
|
|
});
|
|
|
|
const [versions] = useState([
|
|
{
|
|
id: 1,
|
|
version: "2.1",
|
|
type: "major" as const,
|
|
description: "Melhorias na clareza das respostas",
|
|
model: "Google Gemini 2.5 Flash",
|
|
prompt: "Você é um assistente de atendimento ao cliente. Seja educado, prestativo e objetivo nas suas respostas. Sempre mantenha um tom profissional e cordial.",
|
|
createdAt: "2024-01-15 14:30",
|
|
author: "João Silva",
|
|
},
|
|
{
|
|
id: 2,
|
|
version: "2.0",
|
|
type: "major" as const,
|
|
description: "Reformulação completa do prompt",
|
|
model: "Google Gemini 2.5 Pro",
|
|
prompt: "Você é um assistente de atendimento. Seja cordial e ajude o cliente.",
|
|
createdAt: "2024-01-10 09:15",
|
|
author: "Maria Santos",
|
|
},
|
|
{
|
|
id: 3,
|
|
version: "1.5",
|
|
type: "minor" as const,
|
|
description: "Ajustes de tom",
|
|
model: "OpenAI GPT-5 Mini",
|
|
prompt: "Você é um assistente. Seja educado.",
|
|
createdAt: "2024-01-05 16:45",
|
|
author: "João Silva",
|
|
},
|
|
]);
|
|
|
|
const aiModels = [
|
|
{ value: "google/gemini-2.5-pro", label: "Google Gemini 2.5 Pro" },
|
|
{ value: "google/gemini-2.5-flash", label: "Google Gemini 2.5 Flash" },
|
|
{ value: "google/gemini-2.5-flash-lite", label: "Google Gemini 2.5 Flash Lite" },
|
|
{ value: "openai/gpt-5", label: "OpenAI GPT-5" },
|
|
{ value: "openai/gpt-5-mini", label: "OpenAI GPT-5 Mini" },
|
|
{ value: "openai/gpt-5-nano", label: "OpenAI GPT-5 Nano" },
|
|
];
|
|
|
|
const handleSave = (versionType: "major" | "minor" | "patch", notes: string) => {
|
|
// TODO: Implementar salvamento no backend
|
|
console.log("Saving agent:", agent, "Version type:", versionType, "Notes:", notes);
|
|
toast({
|
|
title: "Agente atualizado",
|
|
description: `Nova versão ${versionType} salva com sucesso.`,
|
|
});
|
|
};
|
|
|
|
const handleToggleStatus = () => {
|
|
if (agent.status === "active") {
|
|
setIsDeactivateDialogOpen(true);
|
|
} else {
|
|
// Ativar diretamente sem modal
|
|
setAgent({ ...agent, status: "active" });
|
|
toast({
|
|
title: "Status atualizado",
|
|
description: "Agente ativado com sucesso.",
|
|
});
|
|
}
|
|
};
|
|
|
|
const handleConfirmDeactivate = () => {
|
|
setAgent({ ...agent, status: "inactive" });
|
|
toast({
|
|
title: "Status atualizado",
|
|
description: "Agente desativado com sucesso. Esta ação foi registrada.",
|
|
});
|
|
setIsDeactivateDialogOpen(false);
|
|
};
|
|
|
|
const handleStartEditName = () => {
|
|
setTempName(agent.name);
|
|
setIsEditingName(true);
|
|
};
|
|
|
|
const handleNameBlur = () => {
|
|
if (tempName.trim()) {
|
|
setAgent({ ...agent, name: tempName.trim() });
|
|
} else {
|
|
setTempName(agent.name);
|
|
}
|
|
setIsEditingName(false);
|
|
};
|
|
|
|
return (
|
|
<div className="animate-fade-in pb-8">
|
|
{/* Header */}
|
|
<div className="mb-6">
|
|
<Button
|
|
variant="ghost"
|
|
className="mb-4 gap-2"
|
|
onClick={() => navigate("/")}
|
|
>
|
|
<ArrowLeft className="h-4 w-4" />
|
|
Voltar para Agentes
|
|
</Button>
|
|
|
|
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
|
<div className="flex items-center gap-3">
|
|
{isEditingName ? (
|
|
<Input
|
|
value={tempName}
|
|
onChange={(e) => setTempName(e.target.value)}
|
|
className="text-2xl md:text-3xl font-bold h-auto py-1"
|
|
onBlur={handleNameBlur}
|
|
onKeyDown={(e) => {
|
|
if (e.key === "Enter") handleNameBlur();
|
|
if (e.key === "Escape") {
|
|
setTempName(agent.name);
|
|
setIsEditingName(false);
|
|
}
|
|
}}
|
|
autoFocus
|
|
/>
|
|
) : (
|
|
<>
|
|
<h1 className="text-2xl md:text-3xl font-bold text-foreground">{agent.name}</h1>
|
|
<Button
|
|
size="sm"
|
|
variant="ghost"
|
|
className="h-8 w-8 p-0"
|
|
onClick={handleStartEditName}
|
|
>
|
|
<Pencil className="h-4 w-4" />
|
|
</Button>
|
|
</>
|
|
)}
|
|
<Badge
|
|
variant={agent.status === "active" ? "default" : "secondary"}
|
|
className={
|
|
agent.status === "active"
|
|
? "bg-green-600 hover:bg-green-700 text-white"
|
|
: "bg-muted text-muted-foreground"
|
|
}
|
|
>
|
|
{agent.status === "active" ? "● Ativo" : "○ Inativo"}
|
|
</Badge>
|
|
</div>
|
|
|
|
<div className="flex flex-col sm:flex-row gap-2">
|
|
<Button
|
|
variant="outline"
|
|
className="gap-2"
|
|
onClick={() => setIsHistoryOpen(true)}
|
|
>
|
|
<History className="h-4 w-4" />
|
|
<span className="hidden sm:inline">Histórico de Versões</span>
|
|
<span className="sm:hidden">Histórico</span>
|
|
</Button>
|
|
<Button
|
|
variant={agent.status === "active" ? "destructive" : "default"}
|
|
className={agent.status === "active" ? "gap-2" : "gap-2 bg-green-600 hover:bg-green-700 text-white"}
|
|
onClick={handleToggleStatus}
|
|
>
|
|
<Power className="h-4 w-4" />
|
|
{agent.status === "active" ? "Desativar" : "Ativar"}
|
|
</Button>
|
|
<Button className="gap-2" onClick={() => setIsSaveVersionOpen(true)}>
|
|
<Save className="h-4 w-4" />
|
|
Salvar Alterações
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-6">
|
|
{/* AI Model */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Modelo de IA</CardTitle>
|
|
<CardDescription>
|
|
Selecione o modelo de inteligência artificial
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Select
|
|
value={agent.model}
|
|
onValueChange={(value) => setAgent({ ...agent, model: value })}
|
|
>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{aiModels.map((model) => (
|
|
<SelectItem key={model.value} value={model.value}>
|
|
{model.label}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* 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-[300px] font-mono text-sm"
|
|
placeholder="Digite o prompt do sistema..."
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
<VersionHistoryDialog
|
|
open={isHistoryOpen}
|
|
onOpenChange={setIsHistoryOpen}
|
|
agentName={agent.name}
|
|
versions={versions}
|
|
/>
|
|
|
|
<SaveVersionDialog
|
|
open={isSaveVersionOpen}
|
|
onOpenChange={setIsSaveVersionOpen}
|
|
onSave={handleSave}
|
|
/>
|
|
|
|
<AlertDialog open={isDeactivateDialogOpen} onOpenChange={setIsDeactivateDialogOpen}>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>Tem certeza que deseja desativar este agente?</AlertDialogTitle>
|
|
<AlertDialogDescription>
|
|
Esta ação ficará registrada no sistema. O agente não poderá ser utilizado até ser reativado.
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel>Cancelar</AlertDialogCancel>
|
|
<AlertDialogAction onClick={handleConfirmDeactivate} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
|
|
Desativar
|
|
</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
</div>
|
|
);
|
|
}
|