Add pagination to agents screen

Implement pagination controls on the agents screen to manage a large number of agents. This includes state management for current page and items per page, logic to slice and display agents, and UI elements for navigation (previous, next, page numbers, ellipsis). The search functionality now resets to the first page.
This commit is contained in:
gpt-engineer-app[bot]
2025-11-07 19:52:34 +00:00
parent f87685e014
commit 5a9ca2bbf9
+96 -8
View File
@@ -5,12 +5,23 @@ 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";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination";
import { Plus, Search, Bot, ChevronRight } from "lucide-react"; import { Plus, Search, Bot, ChevronRight } from "lucide-react";
export default function Agents() { export default function Agents() {
const navigate = useNavigate(); const navigate = useNavigate();
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 9;
const [agents] = useState([ const [agents] = useState([
{ {
@@ -43,6 +54,18 @@ export default function Agents() {
agent.name.toLowerCase().includes(searchQuery.toLowerCase()) agent.name.toLowerCase().includes(searchQuery.toLowerCase())
); );
// Paginação
const totalPages = Math.ceil(filteredAgents.length / itemsPerPage);
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const paginatedAgents = filteredAgents.slice(startIndex, endIndex);
// Reset para primeira página quando buscar
const handleSearch = (query: string) => {
setSearchQuery(query);
setCurrentPage(1);
};
return ( return (
<div className="animate-fade-in"> <div className="animate-fade-in">
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-center justify-between gap-4 mb-6">
@@ -64,13 +87,20 @@ export default function Agents() {
<Input <Input
placeholder="Pesquisar agentes..." placeholder="Pesquisar agentes..."
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => handleSearch(e.target.value)}
className="pl-10" className="pl-10"
/> />
</div> </div>
<p className="text-sm text-muted-foreground mt-2"> <div className="flex items-center justify-between mt-2">
{filteredAgents.length} {filteredAgents.length === 1 ? 'agente encontrado' : 'agentes encontrados'} <p className="text-sm text-muted-foreground">
</p> {filteredAgents.length} {filteredAgents.length === 1 ? 'agente encontrado' : 'agentes encontrados'}
</p>
{totalPages > 1 && (
<p className="text-sm text-muted-foreground">
Página {currentPage} de {totalPages}
</p>
)}
</div>
</div> </div>
{filteredAgents.length === 0 ? ( {filteredAgents.length === 0 ? (
@@ -78,8 +108,9 @@ export default function Agents() {
<p className="text-muted-foreground">Nenhum agente encontrado.</p> <p className="text-muted-foreground">Nenhum agente encontrado.</p>
</div> </div>
) : ( ) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <>
{filteredAgents.map((agent) => ( <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{paginatedAgents.map((agent) => (
<Card <Card
key={agent.id} key={agent.id}
className="group relative overflow-hidden border-2 transition-all duration-300 hover:shadow-lg hover:scale-[1.02] bg-gradient-to-br from-card to-card/50 cursor-pointer" className="group relative overflow-hidden border-2 transition-all duration-300 hover:shadow-lg hover:scale-[1.02] bg-gradient-to-br from-card to-card/50 cursor-pointer"
@@ -130,8 +161,65 @@ export default function Agents() {
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
))} ))}
</div> </div>
{totalPages > 1 && (
<div className="mt-8 flex justify-center">
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
onClick={() => setCurrentPage(prev => Math.max(1, prev - 1))}
className={currentPage === 1 ? "pointer-events-none opacity-50" : "cursor-pointer"}
/>
</PaginationItem>
{[...Array(totalPages)].map((_, index) => {
const pageNumber = index + 1;
// Mostrar primeira página, última página e páginas próximas à atual
if (
pageNumber === 1 ||
pageNumber === totalPages ||
(pageNumber >= currentPage - 1 && pageNumber <= currentPage + 1)
) {
return (
<PaginationItem key={pageNumber}>
<PaginationLink
onClick={() => setCurrentPage(pageNumber)}
isActive={currentPage === pageNumber}
className="cursor-pointer"
>
{pageNumber}
</PaginationLink>
</PaginationItem>
);
}
// Mostrar ellipsis
if (pageNumber === currentPage - 2 || pageNumber === currentPage + 2) {
return (
<PaginationItem key={pageNumber}>
<PaginationEllipsis />
</PaginationItem>
);
}
return null;
})}
<PaginationItem>
<PaginationNext
onClick={() => setCurrentPage(prev => Math.min(totalPages, prev + 1))}
className={currentPage === totalPages ? "pointer-events-none opacity-50" : "cursor-pointer"}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
</div>
)}
</>
)} )}
<CreateAgentDialog <CreateAgentDialog