Add Agents screen to sidebar
This commit is contained in:
@@ -5,6 +5,7 @@ import { ThemeProvider } from "next-themes";
|
|||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
||||||
import { AppLayout } from "./components/layout/AppLayout";
|
import { AppLayout } from "./components/layout/AppLayout";
|
||||||
|
import Agents from "./pages/Agents";
|
||||||
import Prompts from "./pages/Prompts";
|
import Prompts from "./pages/Prompts";
|
||||||
import TestPrompt from "./pages/TestPrompt";
|
import TestPrompt from "./pages/TestPrompt";
|
||||||
import History from "./pages/History";
|
import History from "./pages/History";
|
||||||
@@ -21,6 +22,7 @@ const App = () => (
|
|||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route element={<AppLayout />}>
|
<Route element={<AppLayout />}>
|
||||||
|
<Route path="/agents" element={<Agents />} />
|
||||||
<Route path="/" element={<Prompts />} />
|
<Route path="/" element={<Prompts />} />
|
||||||
<Route path="/test" element={<TestPrompt />} />
|
<Route path="/test" element={<TestPrompt />} />
|
||||||
<Route path="/history" element={<History />} />
|
<Route path="/history" element={<History />} />
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
|
interface CreateAgentDialogProps {
|
||||||
|
open: boolean;
|
||||||
|
onOpenChange: (open: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CreateAgentDialog({ open, onOpenChange }: CreateAgentDialogProps) {
|
||||||
|
const [name, setName] = useState("");
|
||||||
|
const [status, setStatus] = useState<"active" | "inactive">("active");
|
||||||
|
const [selectedPrompt, setSelectedPrompt] = useState("");
|
||||||
|
const [selectedModel, setSelectedModel] = useState("");
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
console.log("Salvando agente:", { name, status, selectedPrompt, selectedModel });
|
||||||
|
// Implementar lógica de salvar no backend
|
||||||
|
onOpenChange(false);
|
||||||
|
// Reset form
|
||||||
|
setName("");
|
||||||
|
setStatus("active");
|
||||||
|
setSelectedPrompt("");
|
||||||
|
setSelectedModel("");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
|
<DialogContent className="max-w-2xl">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Criar Novo Agente</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Configure o agente selecionando um prompt e modelo de IA
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="name">Nome do Agente</Label>
|
||||||
|
<Input
|
||||||
|
id="name"
|
||||||
|
placeholder="Ex: Agente de Atendimento"
|
||||||
|
value={name}
|
||||||
|
onChange={(e) => setName(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="status">Status</Label>
|
||||||
|
<Select value={status} onValueChange={(v) => setStatus(v as "active" | "inactive")}>
|
||||||
|
<SelectTrigger id="status">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="active">Ativo</SelectItem>
|
||||||
|
<SelectItem value="inactive">Inativo</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="prompt">Prompt</Label>
|
||||||
|
<Select value={selectedPrompt} onValueChange={setSelectedPrompt}>
|
||||||
|
<SelectTrigger id="prompt">
|
||||||
|
<SelectValue placeholder="Selecione um prompt" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="atendimento">Prompt de Atendimento v2.1</SelectItem>
|
||||||
|
<SelectItem value="vendas">Prompt de Vendas v1.5</SelectItem>
|
||||||
|
<SelectItem value="analise">Prompt de Análise</SelectItem>
|
||||||
|
<SelectItem value="marketing">Prompt de Marketing</SelectItem>
|
||||||
|
<SelectItem value="suporte">Prompt de Suporte Técnico</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="model">Modelo de IA</Label>
|
||||||
|
<Select value={selectedModel} onValueChange={setSelectedModel}>
|
||||||
|
<SelectTrigger id="model">
|
||||||
|
<SelectValue placeholder="Selecione um modelo" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="gemini-2.5-flash">Google Gemini 2.5 Flash</SelectItem>
|
||||||
|
<SelectItem value="gemini-2.5-pro">Google Gemini 2.5 Pro</SelectItem>
|
||||||
|
<SelectItem value="gpt-5">OpenAI GPT-5</SelectItem>
|
||||||
|
<SelectItem value="gpt-5-mini">OpenAI GPT-5 Mini</SelectItem>
|
||||||
|
<SelectItem value="gpt-4.1">OpenAI GPT-4.1</SelectItem>
|
||||||
|
<SelectItem value="claude-sonnet-4-5">Anthropic Claude Sonnet 4.5</SelectItem>
|
||||||
|
<SelectItem value="claude-opus-4-1">Anthropic Claude Opus 4.1</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-end gap-2 pt-4 border-t">
|
||||||
|
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
||||||
|
Cancelar
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleSave}
|
||||||
|
disabled={!name || !selectedPrompt || !selectedModel}
|
||||||
|
>
|
||||||
|
Criar Agente
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { NavLink } from "react-router-dom";
|
import { NavLink } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
|
Bot,
|
||||||
FileText,
|
FileText,
|
||||||
TestTube,
|
TestTube,
|
||||||
ArrowLeft,
|
ArrowLeft,
|
||||||
@@ -12,6 +13,7 @@ import { Separator } from "@/components/ui/separator";
|
|||||||
import { ThemeToggle } from "./ThemeToggle";
|
import { ThemeToggle } from "./ThemeToggle";
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
|
{ title: "Agentes", url: "/agents", icon: Bot },
|
||||||
{ title: "Prompts", url: "/", icon: FileText },
|
{ title: "Prompts", url: "/", icon: FileText },
|
||||||
{ title: "Testar Prompt", url: "/test", icon: TestTube },
|
{ title: "Testar Prompt", url: "/test", icon: TestTube },
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { CreateAgentDialog } from "@/components/agents/CreateAgentDialog";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table";
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { Plus, Search, MoreVertical, Edit, Trash2 } from "lucide-react";
|
||||||
|
|
||||||
|
export default function Agents() {
|
||||||
|
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
|
||||||
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
|
||||||
|
const [agents] = useState([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: "Agente de Atendimento",
|
||||||
|
status: "active" as const,
|
||||||
|
prompt: "Prompt de Atendimento v2.1",
|
||||||
|
model: "Google Gemini 2.5 Flash",
|
||||||
|
createdAt: "2 dias atrás",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "Agente de Vendas",
|
||||||
|
status: "active" as const,
|
||||||
|
prompt: "Prompt de Vendas v1.5",
|
||||||
|
model: "OpenAI GPT-5",
|
||||||
|
createdAt: "5 dias atrás",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: "Agente de Análise",
|
||||||
|
status: "inactive" as const,
|
||||||
|
prompt: "Prompt de Análise",
|
||||||
|
model: "Anthropic Claude Sonnet 4.5",
|
||||||
|
createdAt: "1 semana atrás",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const filteredAgents = agents.filter(agent =>
|
||||||
|
agent.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="animate-fade-in">
|
||||||
|
<div className="flex items-center justify-between mb-6">
|
||||||
|
<div>
|
||||||
|
<h1 className="text-3xl font-bold text-foreground mb-2">Gestão de Agentes</h1>
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
Crie e gerencie agentes de IA com prompts e modelos específicos
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button className="gap-2" onClick={() => setIsCreateDialogOpen(true)}>
|
||||||
|
<Plus className="h-4 w-4" />
|
||||||
|
Criar Agente
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-6">
|
||||||
|
<div className="relative max-w-md">
|
||||||
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground h-4 w-4" />
|
||||||
|
<Input
|
||||||
|
placeholder="Pesquisar agentes..."
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
|
className="pl-10"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-muted-foreground mt-2">
|
||||||
|
{filteredAgents.length} {filteredAgents.length === 1 ? 'agente encontrado' : 'agentes encontrados'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{filteredAgents.length === 0 ? (
|
||||||
|
<div className="text-center py-12">
|
||||||
|
<p className="text-muted-foreground">Nenhum agente encontrado.</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="rounded-md border">
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead>Nome</TableHead>
|
||||||
|
<TableHead>Prompt</TableHead>
|
||||||
|
<TableHead>Modelo</TableHead>
|
||||||
|
<TableHead>Criado</TableHead>
|
||||||
|
<TableHead>Status</TableHead>
|
||||||
|
<TableHead className="text-right">Ações</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{filteredAgents.map((agent) => (
|
||||||
|
<TableRow key={agent.id}>
|
||||||
|
<TableCell className="font-medium">{agent.name}</TableCell>
|
||||||
|
<TableCell>{agent.prompt}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<code className="text-xs bg-muted px-2 py-1 rounded">
|
||||||
|
{agent.model}
|
||||||
|
</code>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{agent.createdAt}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Badge
|
||||||
|
variant={agent.status === "active" ? "default" : "secondary"}
|
||||||
|
className={agent.status === "active" ? "bg-green-600 hover:bg-green-700" : "bg-muted text-muted-foreground hover:bg-muted"}
|
||||||
|
>
|
||||||
|
{agent.status === "active" ? "Ativo" : "Inativo"}
|
||||||
|
</Badge>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right">
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button variant="ghost" size="icon">
|
||||||
|
<MoreVertical className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end">
|
||||||
|
<DropdownMenuItem onClick={() => console.log("Edit", agent.id)}>
|
||||||
|
<Edit className="h-4 w-4 mr-2" />
|
||||||
|
Editar
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={() => console.log("Delete", agent.id)}
|
||||||
|
className="text-destructive"
|
||||||
|
>
|
||||||
|
<Trash2 className="h-4 w-4 mr-2" />
|
||||||
|
Excluir
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<CreateAgentDialog
|
||||||
|
open={isCreateDialogOpen}
|
||||||
|
onOpenChange={setIsCreateDialogOpen}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user