import { redirect } from "next/navigation"; import { getTranslations } from "next-intl/server"; import { getSessionUser } from "@/lib/session"; import { listTenants, getOpenClawDefaults } from "@/lib/k8s"; import { OpenClawAdminPanel } from "@/components/admin/openclaw-admin-panel"; /** * /admin/openclaw — platform-default OpenClaw image + per-tenant * overrides table. * * Two sections: * 1. Default — readable from `pieced-openclaw-config` ConfigMap. * Editable via the same form. Empty fields show as "(unset)" * and the operator falls back to its built-in default in that * case (intentionally invisible to the portal — the binary's * baked version moves with releases and we don't want the UI * to claim a misleading "current default"). * 2. Tenant table — every tenant in the cluster with its current * override (or "follows default"). Clicking a row opens a small * inline editor. * * Authorization is gated server-side: `user.isPlatform` only. Any * other user gets redirected to /dashboard. */ export default async function OpenClawAdminPage() { const user = await getSessionUser(); if (!user) redirect("/login"); if (!user.isPlatform) redirect("/dashboard"); const t = await getTranslations("openclawAdmin"); // Parallel fetch — defaults and tenants are independent. const [defaults, tenants] = await Promise.all([ getOpenClawDefaults(), listTenants(), ]); // Sort tenants: overridden first (more interesting to review), // then alphabetically by display name. Helps the admin spot which // tenants are off the platform default at a glance. const sorted = [...tenants].sort((a, b) => { const aOverride = a.spec.openClawImage ? 1 : 0; const bOverride = b.spec.openClawImage ? 1 : 0; if (aOverride !== bOverride) return bOverride - aOverride; return (a.spec.displayName || a.metadata.name).localeCompare( b.spec.displayName || b.metadata.name ); }); return (

{t("title")}

{t("subtitle")}

({ name: tn.metadata.name, displayName: tn.spec.displayName || tn.metadata.name, phase: tn.status?.phase ?? "Unknown", override: tn.spec.openClawImage?.tag ? { tag: tn.spec.openClawImage.tag } : null, }))} />
); }