Files
app/frontend/src/routes/_layout/admin.tsx
T
stroblmeandClaude Fable 5 2303c1f92d Show and revoke registered agents under Admin
An agent that registered itself was invisible, and withdrawing one meant
deleting rows or rotating the signing key. It now sits next to Users, with
the live-token count that tells an approved agent from one that only
registered.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7LwYgJfpkbLCTeiAf8U4A
2026-08-16 16:36:48 +02:00

87 lines
2.4 KiB
TypeScript

import { useSuspenseQuery } from "@tanstack/react-query"
import { createFileRoute, redirect } from "@tanstack/react-router"
import { Suspense } from "react"
import { type UserPublic, UsersService } from "@/client"
import AddUser from "@/components/Admin/AddUser"
import { columns, type UserTableData } from "@/components/Admin/columns"
import OAuthClients from "@/components/Admin/OAuthClients"
import { DataTable } from "@/components/Common/DataTable"
import PendingUsers from "@/components/Pending/PendingUsers"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import useAuth from "@/hooks/useAuth"
function getUsersQueryOptions() {
return {
queryFn: () => UsersService.readUsers({ skip: 0, limit: 100 }),
queryKey: ["users"],
}
}
export const Route = createFileRoute("/_layout/admin")({
component: Admin,
beforeLoad: async () => {
const user = await UsersService.readUserMe()
if (!user.is_superuser) {
throw redirect({
to: "/",
})
}
},
head: () => ({
meta: [
{
title: "Admin - Fluksio",
},
],
}),
})
function UsersTableContent() {
const { user: currentUser } = useAuth()
const { data: users } = useSuspenseQuery(getUsersQueryOptions())
const tableData: UserTableData[] = users.data.map((user: UserPublic) => ({
...user,
isCurrentUser: currentUser?.id === user.id,
}))
return <DataTable columns={columns} data={tableData} />
}
function UsersTable() {
return (
<Suspense fallback={<PendingUsers />}>
<UsersTableContent />
</Suspense>
)
}
function Admin() {
// Agents get in through the same door as people, so they are administered
// next to them rather than in a screen of their own.
return (
<Tabs defaultValue="users" className="flex flex-col gap-6">
<TabsList>
<TabsTrigger value="users">Users</TabsTrigger>
<TabsTrigger value="agents">Agents</TabsTrigger>
</TabsList>
<TabsContent value="users" className="flex flex-col gap-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold tracking-tight">Users</h1>
<p className="text-muted-foreground">
Manage user accounts and permissions
</p>
</div>
<AddUser />
</div>
<UsersTable />
</TabsContent>
<TabsContent value="agents">
<OAuthClients />
</TabsContent>
</Tabs>
)
}