import { notFound } from "next/navigation"; import { getMeshResponseSchema } from "@turbostarter/api/schema"; import { handle } from "@turbostarter/api/utils"; import { Badge } from "@turbostarter/ui-web/badge"; import { api } from "~/lib/api/server"; import { getMetadata } from "~/lib/metadata"; import { DashboardHeader, DashboardHeaderDescription, DashboardHeaderTitle, } from "~/modules/common/layout/dashboard/header"; export const generateMetadata = getMetadata({ title: "Mesh detail · Admin", description: "Members, presences, invites, audit events for a mesh.", }); export default async function MeshDetailPage({ params, }: { params: Promise<{ id: string }>; }) { const { id } = await params; const data = await handle(api.admin.meshes[":id"].$get, { schema: getMeshResponseSchema, })({ param: { id } }).catch(() => null); if (!data || !data.mesh) notFound(); const { mesh, members, presences, invites, auditEvents } = data; return ( <>
{mesh.name} {mesh.slug} Owner: {mesh.ownerName ?? "—"} · {mesh.ownerEmail ?? "—"} · tier{" "} {mesh.tier} · transport {mesh.transport} · visibility{" "} {mesh.visibility}
{members.map((m) => ( ))}
Display name Role Pubkey Joined Last seen Status
{m.displayName} {m.role} {m.peerPubkey.slice(0, 12)}… {new Date(m.joinedAt).toLocaleDateString()} {m.lastSeenAt ? new Date(m.lastSeenAt).toLocaleString() : "—"} {m.revokedAt ? ( revoked ) : ( active )}
{presences.map((p) => ( ))}
Peer Status PID CWD Last ping
{p.displayName ?? "—"} {p.disconnectedAt ? "disconnected" : p.status} {p.pid} {p.cwd} {new Date(p.lastPingAt).toLocaleTimeString()}
{invites.map((inv) => ( ))}
Token Role Uses Expires Status
{inv.token.slice(0, 12)}… {inv.role} {inv.usedCount} / {inv.maxUses} {new Date(inv.expiresAt).toLocaleDateString()} {inv.revokedAt ? ( revoked ) : new Date(inv.expiresAt) < new Date() ? ( expired ) : ( active )}
{auditEvents.map((e) => ( ))}
When Event Actor Target
{new Date(e.createdAt).toLocaleString()} {e.eventType} {e.actorPeerId?.slice(0, 12) ?? "—"} {e.targetPeerId?.slice(0, 12) ?? "—"}
); } function Section({ title, count, empty, children, }: { title: string; count: number; empty: string; children: React.ReactNode; }) { return (

{title}

{count}
{count === 0 ? (

{empty}

) : (
{children}
)}
); }