diff --git a/app/api/collections/[collection]/route.ts b/app/api/collections/[collection]/route.ts index 88f6bc2..dca0ecc 100644 --- a/app/api/collections/[collection]/route.ts +++ b/app/api/collections/[collection]/route.ts @@ -1,12 +1,35 @@ -import { NextRequest, NextResponse } from 'next/server'; -import { getDatabase } from '@/lib/db/mongodb'; +import { NextRequest, NextResponse } from "next/server"; +import { getDatabase } from "@/lib/db/mongodb"; +import { ObjectId } from "mongodb"; const ALLOWED_COLLECTIONS = [ - 'accessroles', 'aclentries', 'actions', 'agentcategories', 'agents', - 'assistants', 'balances', 'banners', 'conversations', 'conversationtags', - 'files', 'groups', 'keys', 'memoryentries', 'messages', 'pluginauths', - 'presets', 'projects', 'promptgroups', 'prompts', 'roles', 'sessions', - 'sharedlinks', 'tokens', 'toolcalls', 'transactions', 'users' + "accessroles", + "aclentries", + "actions", + "agentcategories", + "agents", + "assistants", + "balances", + "banners", + "conversations", + "conversationtags", + "files", + "groups", + "keys", + "memoryentries", + "messages", + "pluginauths", + "presets", + "projects", + "promptgroups", + "prompts", + "roles", + "sessions", + "sharedlinks", + "tokens", + "toolcalls", + "transactions", + "users", ]; export async function GET( @@ -14,32 +37,53 @@ export async function GET( { params }: { params: Promise<{ collection: string }> } ) { const { collection } = await params; - + try { - if (!ALLOWED_COLLECTIONS.includes(collection)) { return NextResponse.json( - { error: 'Collection non autorisée' }, + { error: "Collection non autorisée" }, { status: 400 } ); } const { searchParams } = new URL(request.url); - const page = parseInt(searchParams.get('page') || '1'); - const limit = parseInt(searchParams.get('limit') || '20'); - const filter = JSON.parse(searchParams.get('filter') || '{}'); + const page = parseInt(searchParams.get("page") || "1"); + const limit = parseInt(searchParams.get("limit") || "20"); + const filter = JSON.parse(searchParams.get("filter") || "{}"); + + // Gestion spéciale pour la collection users avec recherche par email ou id + if (collection === "users") { + const email = searchParams.get("email"); + const id = searchParams.get("id"); + + if (email) { + filter.email = email.toLowerCase(); + } else if (id) { + // Vérifier si l'ID est un ObjectId valide + if (ObjectId.isValid(id)) { + filter._id = new ObjectId(id); + } else { + // Si l'ID n'est pas valide, retourner une erreur + return NextResponse.json( + { error: "ID utilisateur invalide" }, + { status: 400 } + ); + } + } + } const db = await getDatabase(); const skip = (page - 1) * limit; const [data, total] = await Promise.all([ - db.collection(collection) + db + .collection(collection) .find(filter) .skip(skip) .limit(limit) .sort({ createdAt: -1 }) .toArray(), - db.collection(collection).countDocuments(filter) + db.collection(collection).countDocuments(filter), ]); return NextResponse.json({ @@ -47,13 +91,10 @@ export async function GET( total, page, limit, - totalPages: Math.ceil(total / limit) + totalPages: Math.ceil(total / limit), }); } catch (error) { console.error(`Erreur lors de la récupération de ${collection}:`, error); - return NextResponse.json( - { error: 'Erreur serveur' }, - { status: 500 } - ); + return NextResponse.json({ error: "Erreur serveur" }, { status: 500 }); } -} \ No newline at end of file +} diff --git a/components/collections/users-table.tsx b/components/collections/users-table.tsx index 8f7194a..3dcd292 100644 --- a/components/collections/users-table.tsx +++ b/components/collections/users-table.tsx @@ -13,13 +13,14 @@ import { } from "@/components/ui/table"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; -import { ChevronLeft, ChevronRight } from "lucide-react"; +import { Input } from "@/components/ui/input"; +import { ChevronLeft, ChevronRight, Search } from "lucide-react"; import { formatDate } from "@/lib/utils"; import { LibreChatUser, LibreChatBalance } from "@/lib/types"; - export function UsersTable() { const [page, setPage] = useState(1); + const [searchTerm, setSearchTerm] = useState(""); const limit = 20; // Charger les utilisateurs @@ -46,6 +47,20 @@ export function UsersTable() { return map; }, [balances]); + // Filtrer les utilisateurs selon le terme de recherche + const filteredUsers = useMemo(() => { + if (!searchTerm.trim()) { + return users; + } + + const searchLower = searchTerm.toLowerCase(); + return users.filter( + (user) => + user.name?.toLowerCase().includes(searchLower) || + user.email?.toLowerCase().includes(searchLower) + ); + }, [users, searchTerm]); + const totalPages = Math.ceil(total / limit); const handlePrevPage = () => { @@ -76,7 +91,20 @@ export function UsersTable() { return ( - Liste des utilisateurs ({total}) +
+ + Liste des utilisateurs ({searchTerm ? filteredUsers.length : total}) + +
+ + setSearchTerm(e.target.value)} + className="pl-10" + /> +
+
@@ -93,78 +121,108 @@ export function UsersTable() { - {users.map((user) => { - const userCredits = creditsMap.get(user._id) || 0; - const isActive = new Date(user.updatedAt || user.createdAt) > - new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); // 30 jours en millisecondes - - return ( - - - - {user._id.slice(-8)} - - - - {user.name} - - - {user.email} - - - - {user.role} - - - - - {userCredits.toLocaleString()} crédits - - - - - {isActive ? 'Actif' : 'Inactif'} - - - - - {formatDate(user.createdAt)} - - - - ); - })} + {filteredUsers.length > 0 ? ( + filteredUsers.map((user) => { + const userCredits = creditsMap.get(user._id) || 0; + const isActive = + new Date(user.updatedAt || user.createdAt) > + new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); // 30 jours en millisecondes + + return ( + + + + {user._id.slice(-8)} + + + + {user.name} + + + {user.email} + + + + {user.role} + + + + + {userCredits.toLocaleString()} crédits + + + + + + {isActive ? "Actif" : "Inactif"} + + + + + + {formatDate(user.createdAt)} + + + + ); + }) + ) : ( + + + {searchTerm + ? `Aucun utilisateur trouvé pour "${searchTerm}"` + : "Aucun utilisateur trouvé"} + + + )}
- {/* Pagination */} -
-
- Page {page} sur {totalPages} ({total} éléments au total) + {/* Pagination - masquée lors de la recherche */} + {!searchTerm && ( +
+
+ Page {page} sur {totalPages} ({total} éléments au total) +
+
+ + +
-
- - + )} + + {/* Info de recherche */} + {searchTerm && ( +
+ {filteredUsers.length} résultat(s) trouvé(s) pour "{searchTerm} + "
-
+ )} ); -} \ No newline at end of file +}