import { Link, Navigate, createFileRoute } from "@tanstack/react-router" import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" import { CaretRightIcon } from "@phosphor-icons/react" import { useEffect, useMemo, useState } from "react" import type { DatadogConnectBody, LangSmithConnectBody, ModelOption, TeamSettings, UserMapping, } from "@/lib/api" import { AppShell, SettingsRow, SettingsSection } from "@/components/AppShell" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Skeleton } from "@/components/ui/skeleton" import { api } from "@/lib/api" import { useSession } from "@/lib/session" export const Route = createFileRoute("/admin")({ component: AdminPage }) function AdminPage() { const session = useSession() const options = useQuery({ queryKey: ["options"], queryFn: api.options, enabled: !!session.data?.is_admin, }) if (session.isLoading) { return (
) } if (!session.data) return if (!session.data.is_admin) return return (
Reviewer eval Run the offline reviewer benchmark and watch its output stream live.
) } const PR_URL_RE = /^https:\/\/github\.com\/([^/\s]+)\/([^/\s]+)\/pull\/(\d+)/ function TriggerReviewSection() { const [url, setUrl] = useState("") const [error, setError] = useState(null) const [message, setMessage] = useState(null) const parsed = useMemo(() => { const match = PR_URL_RE.exec(url.trim()) if (!match) return null const [, owner, repo, number] = match if (!owner || !repo || !number) return null return { owner, repo, number: Number(number) } }, [url]) const trigger = useMutation({ mutationFn: () => { if (!parsed) throw new Error("invalid PR URL") return api.reReview(parsed.owner, parsed.repo, parsed.number) }, onSuccess: (result) => { setError(null) setMessage( result.queued ? "Review queued — a run is already in progress on this PR." : "Review started." ) }, onError: (e: Error) => { setMessage(null) setError(e.message) }, }) return (
{ setUrl(e.target.value) setMessage(null) setError(null) }} />
{url.trim() && !parsed && (

Enter a full PR URL like https://github.com/owner/repo/pull/123

)} {message && parsed && (

{message}{" "} View review

)} {error &&

{error}

}
) } const PAGE_SIZE = 20 function UserMappingsSection({ enabled }: { enabled: boolean }) { const [error, setError] = useState(null) const [page, setPage] = useState(1) const mappings = useQuery({ queryKey: ["adminUserMappings", page], queryFn: () => api.adminListUserMappings(page, PAGE_SIZE), enabled, }) const total = mappings.data?.total ?? 0 const pageCount = Math.max(1, Math.ceil(total / PAGE_SIZE)) useEffect(() => { if (!mappings.isFetching && page > pageCount) { setPage(pageCount) } }, [mappings.isFetching, page, pageCount]) const remove = useMutation({ mutationFn: (gh: string) => api.adminDeleteUserMapping(gh), onSuccess: () => void mappings.refetch(), onError: (e: Error) => setError(e.message), }) const items = mappings.data?.items ?? [] return (
{error && {error}}
{mappings.isLoading ? ( ) : !items.length ? (

No mappings yet.

) : ( items.map((m: UserMapping) => (
{m.github_login} {m.work_email} {m.slack_user_id ? ` · ${m.slack_user_id}` : ""} {m.source ? ` · ${m.source}` : ""}
)) )}
{total > PAGE_SIZE && (
{total} mapping{total === 1 ? "" : "s"} · page {page} of{" "} {pageCount}
)}
) } function ObservabilityCredentialsSection() { const qc = useQueryClient() const creds = useQuery({ queryKey: ["teamCredentials"], queryFn: api.getTeamCredentials, }) const [error, setError] = useState(null) const [ddSite, setDdSite] = useState("datadoghq.com") const [ddApiKey, setDdApiKey] = useState("") const [ddAppKey, setDdAppKey] = useState("") const [lsApiKey, setLsApiKey] = useState("") const [lsEndpoint, setLsEndpoint] = useState("") const onError = (e: Error) => setError(e.message) const onSuccess = ( saved: Awaited> ) => { qc.setQueryData(["teamCredentials"], saved) setError(null) } const connectDd = useMutation({ mutationFn: (body: DatadogConnectBody) => api.connectDatadog(body), onSuccess: (saved) => { onSuccess(saved) setDdApiKey("") setDdAppKey("") }, onError, }) const disconnectDd = useMutation({ mutationFn: () => api.disconnectDatadog(), onSuccess, onError, }) const connectLs = useMutation({ mutationFn: (body: LangSmithConnectBody) => api.connectLangSmith(body), onSuccess: (saved) => { onSuccess(saved) setLsApiKey("") }, onError, }) const disconnectLs = useMutation({ mutationFn: () => api.disconnectLangSmith(), onSuccess, onError, }) const datadog = creds.data?.datadog const langsmith = creds.data?.langsmith const busy = creds.isLoading return (
disconnectDd.mutate()} disabled={disconnectDd.isPending} > Disconnect ) : (
setDdSite(e.target.value)} disabled={busy} /> setDdApiKey(e.target.value)} disabled={busy} /> setDdAppKey(e.target.value)} disabled={busy} />
) } /> disconnectLs.mutate()} disabled={disconnectLs.isPending} > Disconnect ) : (
setLsApiKey(e.target.value)} disabled={busy} /> setLsEndpoint(e.target.value)} disabled={busy} />
) } />
{error &&

{error}

}
) } function GlobalDefaultsSection({ models }: { models: Array }) { const qc = useQueryClient() const settings = useQuery({ queryKey: ["teamSettings"], queryFn: api.getTeamSettings, }) const [error, setError] = useState(null) const [defaultRepoDraft, setDefaultRepoDraft] = useState("") useEffect(() => { setDefaultRepoDraft(settings.data?.default_repo ?? "") }, [settings.data?.default_repo]) const save = useMutation({ mutationFn: (body: TeamSettings) => api.saveTeamSettings(body), onSuccess: (saved) => { qc.setQueryData(["teamSettings"], saved) setError(null) }, onError: (e: Error) => setError(e.message), }) return (
settings.data && save.mutate({ ...settings.data, default_agent_model: model, default_agent_reasoning_effort: effort, }) } disabled={!settings.data || save.isPending} /> settings.data && save.mutate({ ...settings.data, default_agent_subagent_model: model, default_agent_subagent_reasoning_effort: effort, }) } disabled={!settings.data || save.isPending} /> setDefaultRepoDraft(e.target.value)} onBlur={() => settings.data && save.mutate({ ...settings.data, default_repo: defaultRepoDraft.trim() || null, }) } disabled={!settings.data || save.isPending} /> } /> settings.data && save.mutate({ ...settings.data, default_reviewer_model: model, default_reviewer_reasoning_effort: effort, }) } disabled={!settings.data || save.isPending} /> settings.data && save.mutate({ ...settings.data, default_reviewer_subagent_model: model, default_reviewer_subagent_reasoning_effort: effort, }) } disabled={!settings.data || save.isPending} /> settings.data && save.mutate({ ...settings.data, default_chat_model: null, default_chat_reasoning_effort: null, }) } onChange={(model, effort) => settings.data && save.mutate({ ...settings.data, default_chat_model: model, default_chat_reasoning_effort: effort, }) } disabled={!settings.data || save.isPending} />
{error &&

{error}

}
) } interface RolePickerProps { label: string description: string models: Array model: string | null effort: string | null onChange: (model: string, effort: string) => void disabled: boolean /** * When set, the model dropdown gains a leading "inherit" option with this * label. Selecting it calls {@link onInherit} (clearing the override); an * unset `model` renders as this option. */ inheritLabel?: string onInherit?: () => void } const INHERIT_VALUE = "__inherit__" function RolePicker({ label, description, models, model, effort, onChange, disabled, inheritLabel, onInherit, }: RolePickerProps) { const inheritFallback = inheritLabel ? INHERIT_VALUE : "" const [localModel, setLocalModel] = useState(model ?? inheritFallback) const [localEffort, setLocalEffort] = useState(effort ?? "") useEffect(() => { setLocalModel(model ?? inheritFallback) setLocalEffort(effort ?? "") }, [model, effort, inheritFallback]) const isInherit = localModel === INHERIT_VALUE const selectedModel = models.find((m) => m.id === localModel) const availableEfforts = selectedModel?.efforts ?? [] const handleModelChange = (value: string | null) => { if (!value) return if (value === INHERIT_VALUE) { setLocalModel(INHERIT_VALUE) setLocalEffort("") onInherit?.() return } const nextModel = models.find((m) => m.id === value) if (!nextModel) return const nextEffort = nextModel.efforts.includes(localEffort) ? localEffort : nextModel.default_effort setLocalModel(value) setLocalEffort(nextEffort) onChange(value, nextEffort) } const handleEffortChange = (value: string | null) => { if (!value || !localModel || isInherit) return setLocalEffort(value) onChange(localModel, value) } return ( } /> ) }