All the initial admin requests approval flow

This commit is contained in:
2026-04-11 11:54:21 +02:00
parent 94bfd25553
commit 9a96d74f5c
7 changed files with 604 additions and 88 deletions

View File

@@ -2,7 +2,7 @@ import { getSessionUser } from "@/lib/session";
import { getTranslations } from "next-intl/server";
import { redirect } from "next/navigation";
import { listTenants } from "@/lib/k8s";
import { StatusBadge } from "@/components/ui/status-badge";
import { AdminPanel } from "@/components/admin/admin-panel";
export default async function AdminPage() {
const user = await getSessionUser();
@@ -30,76 +30,7 @@ export default async function AdminPage() {
</div>
<div className="animate-in animate-in-delay-1">
<div className="flex items-baseline gap-3 mb-4">
<h2 className="text-xs font-semibold uppercase tracking-wider text-text-muted">
{t("allTenants")}
</h2>
<span className="font-mono text-xs text-text-muted tabular-nums">
{tenants.length}
</span>
</div>
{tenants.length === 0 ? (
<div className="bg-surface-1 border border-border rounded-xl p-12 text-center">
<p className="text-text-secondary text-sm">{t("noTenants")}</p>
</div>
) : (
<div className="bg-surface-1 border border-border rounded-xl overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-border text-left">
<th className="px-5 py-3 text-xs font-semibold uppercase tracking-wider text-text-muted">
{t("name")}
</th>
<th className="px-5 py-3 text-xs font-semibold uppercase tracking-wider text-text-muted">
{t("displayName")}
</th>
<th className="px-5 py-3 text-xs font-semibold uppercase tracking-wider text-text-muted">
{t("phase")}
</th>
<th className="px-5 py-3 text-xs font-semibold uppercase tracking-wider text-text-muted">
{t("packages")}
</th>
<th className="px-5 py-3 text-xs font-semibold uppercase tracking-wider text-text-muted">
{t("created")}
</th>
</tr>
</thead>
<tbody>
{tenants.map((tenant) => (
<tr
key={tenant.metadata.name}
className="border-b border-border last:border-0 hover:bg-surface-2/50 transition-colors"
>
<td className="px-5 py-3 font-mono text-xs text-accent">
{tenant.metadata.name}
</td>
<td className="px-5 py-3 text-text-primary">
{tenant.spec.displayName}
</td>
<td className="px-5 py-3">
<StatusBadge
phase={tenant.status?.phase ?? "Pending"}
/>
</td>
<td className="px-5 py-3 text-xs text-text-secondary font-mono">
{tenant.spec.packages?.join(", ") || "—"}
</td>
<td className="px-5 py-3 text-xs text-text-muted tabular-nums">
{tenant.metadata.creationTimestamp
? new Date(
tenant.metadata.creationTimestamp
).toLocaleDateString()
: "—"}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
<AdminPanel initialTenants={tenants} />
</div>
</div>
);

View File

@@ -6,6 +6,7 @@ import { createTenant } from "@/lib/k8s";
/**
* POST /api/admin/requests/[id]/approve
* Approve a tenant request: create the PiecedTenant CR and update status.
* Also supports re-approving a previously rejected request.
*/
export async function POST(
request: Request,
@@ -29,7 +30,7 @@ export async function POST(
);
}
if (tenantRequest.status !== "pending") {
if (tenantRequest.status !== "pending" && tenantRequest.status !== "rejected") {
return NextResponse.json(
{ error: `Request is already ${tenantRequest.status}` },
{ status: 400 }