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
87 lines
2.4 KiB
TypeScript
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>
|
|
)
|
|
}
|