Skip to main content
Glama
page.tsx6.95 kB
"use client"; import { Claims } from "@repo/db/types"; import { Badge } from "@repo/ui/components/ui/badge"; import { Button } from "@repo/ui/components/ui/button"; import { Input } from "@repo/ui/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@repo/ui/components/ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@repo/ui/components/ui/table"; import { Eye } from "lucide-react"; import Link from "next/link"; import { useState } from "react"; import { AdminPageHeader } from "@/components/admin/admin-page-header"; import { AdminTablePagination } from "@/components/admin/admin-table-pagination"; import { trpc } from "@/lib/trpc/client"; import { getAssetUrl } from "@/lib/utils"; type AppType = "client" | "server" | "application" | "all"; type ClaimStatus = "pending" | "approved" | "rejected" | "all"; export default function AdminClaimsPage() { const [searchQuery, setSearchQuery] = useState(""); const [statusFilter, setStatusFilter] = useState<ClaimStatus>("all"); const [appTypeFilter, setAppTypeFilter] = useState<AppType>("all"); const [currentPage, setCurrentPage] = useState(1); const [itemsPerPage] = useState(10); const { data: searchResult, isLoading, } = trpc.claims.search.useQuery({ query: searchQuery, page: currentPage, limit: itemsPerPage, status: statusFilter !== "all" ? statusFilter : undefined, appType: appTypeFilter !== "all" ? appTypeFilter : undefined, }); const getStatusBadge = (status: string) => { switch (status) { case "pending": return <Badge variant="secondary">待处理</Badge>; case "approved": return <Badge variant="default">已通过</Badge>; case "rejected": return <Badge variant="destructive">已拒绝</Badge>; default: return <Badge variant="outline">{status}</Badge>; } }; return ( <div className="space-y-6"> <AdminPageHeader title="所有权申请管理" description="管理应用的所有权申请" /> <div className="flex items-center gap-4"> <Input placeholder="搜索应用名称或申请人..." value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} className="max-w-sm" /> <Select value={statusFilter} onValueChange={(value) => setStatusFilter(value as ClaimStatus)} > <SelectTrigger className="w-[180px]"> <SelectValue placeholder="申请状态" /> </SelectTrigger> <SelectContent> <SelectItem value="all">全部状态</SelectItem> <SelectItem value="pending">待处理</SelectItem> <SelectItem value="approved">已通过</SelectItem> <SelectItem value="rejected">已拒绝</SelectItem> </SelectContent> </Select> <Select value={appTypeFilter} onValueChange={(value) => setAppTypeFilter(value as AppType)} > <SelectTrigger className="w-[180px]"> <SelectValue placeholder="应用类型" /> </SelectTrigger> <SelectContent> <SelectItem value="all">全部类型</SelectItem> <SelectItem value="client">客户端</SelectItem> <SelectItem value="server">服务端</SelectItem> <SelectItem value="application">应用程序</SelectItem> </SelectContent> </Select> </div> <div className="rounded-md border"> <Table> <TableHeader> <TableRow> <TableHead>应用</TableHead> <TableHead>申请人</TableHead> <TableHead>证明类型</TableHead> <TableHead>应用类型</TableHead> <TableHead>状态</TableHead> <TableHead>提交时间</TableHead> <TableHead>操作</TableHead> </TableRow> </TableHeader> <TableBody> {isLoading ? ( <TableRow> <TableCell colSpan={7} className="text-center"> 加载中... </TableCell> </TableRow> ) : searchResult?.data?.length === 0 ? ( <TableRow> <TableCell colSpan={7} className="text-center"> 暂无数据 </TableCell> </TableRow> ) : ( searchResult?.data?.map((claim) => ( <TableRow key={claim.id}> <TableCell> <div className="flex items-center gap-3"> {claim.appIcon && ( <img src={getAssetUrl(claim.appIcon)} alt={claim.appName} className="h-8 w-8 rounded-lg" /> )} <div className="flex flex-col"> <span className="font-medium">{claim.appName}</span> <span className="text-xs text-muted-foreground"> {claim.appId} </span> </div> </div> </TableCell> <TableCell> <div className="flex flex-col"> <span>{claim.userName}</span> <span className="text-xs text-muted-foreground"> {claim.userEmail} </span> </div> </TableCell> <TableCell>{claim.proofType}</TableCell> <TableCell>{claim.appType}</TableCell> <TableCell>{getStatusBadge(claim.status)}</TableCell> <TableCell> {new Date(claim.createdAt).toLocaleDateString()} </TableCell> <TableCell> <Button variant="ghost" size="sm" asChild> <Link href={`/admin/claims/${claim.id}`}> <Eye className="mr-2 h-4 w-4" /> 查看 </Link> </Button> </TableCell> </TableRow> )) )} </TableBody> </Table> </div> {searchResult && ( <AdminTablePagination currentPage={currentPage} totalPages={Math.ceil(searchResult.pagination.total / itemsPerPage)} onPageChange={setCurrentPage} totalItems={searchResult.pagination.total} itemsPerPage={itemsPerPage} showingFrom={(currentPage - 1) * itemsPerPage + 1} showingTo={Math.min(currentPage * itemsPerPage, searchResult.pagination.total)} /> )} </div> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/metacode0602/open-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server