"use client";
import { useCallback, useEffect, useState } from "react";
import { api } from "@/lib/api/client";
import type { components } from "@/lib/api/schema";
import { Card, CardContent } from "@/components/ui/card";
type Instance = components["schemas"]["InstanceStatus"];
function Stat({ label, value }: { label: string; value: React.ReactNode }) {
return (
);
}
export default function AdminPage() {
const [instance, setInstance] = useState(null);
const [forbidden, setForbidden] = useState(false);
const [ready, setReady] = useState(false);
const load = useCallback(async () => {
const { data, response } = await api.GET("/api/v1/admin/instance");
if (response.status === 403) setForbidden(true);
else if (data) setInstance(data);
setReady(true);
}, []);
useEffect(() => {
load();
}, [load]);
if (!ready) return Loading…
;
// Fail closed on anything that isn't a successful owner load: 403 (not owner),
// 401 (not signed in), or any 5xx all land here rather than dereferencing null.
if (forbidden || !instance) {
return (
Instance admin
{forbidden
? "This area is for the instance owner only. Set OWNER_EMAIL in the server environment to your account email (and verify that email) to claim it."
: "Instance status is unavailable right now. Make sure you're signed in as the instance owner."}
);
}
const i = instance;
return (
Instance admin
Operational status for this deployment. You see this because your account is
named in OWNER_EMAIL. Instance ownership is an operator role — it
does not grant access to other people's private tree data.
AI providers (instance-wide)
{i.ai_providers.length === 0 ? (
None configured. Set provider credentials (Anthropic, OpenAI, x.AI, or
Ollama) in the server environment.
) : (
{i.ai_providers.map((p) => (
-
{p.name}
{p.model}
))}
)}
Default provider: {i.default_llm_provider}. Per-tree AI policy is set on
each tree's AI page.
);
}