bcca7686ee
REQ-001: SSO session via WorkOS (getAuthorizationUrl + exchangeCodeForSession) REQ-002: tenant provisioning on first signup (admin role) REQ-003: invitations via single-use acceptance link REQ-004: RBAC role assignment (admin/operator/viewer) REQ-005: RBAC enforcement at API gateway from first endpoint (/api/me) ---ci--- phase: 2 milestone: v0.1 status: execute ---/ci---
73 lines
2.5 KiB
TypeScript
73 lines
2.5 KiB
TypeScript
/**
|
|
* /dashboard — M1 admin dashboard shell (REQ-002).
|
|
*
|
|
* The 5-step onboarding checklist is rendered here (all grey — steps light up
|
|
* as later waves ship). Wave E wires live Relay Agent health + targets; this
|
|
* shell proves the SSO → /dashboard redirect works end-to-end.
|
|
*/
|
|
|
|
import { getMe } from "./me.js";
|
|
|
|
export default async function DashboardPage() {
|
|
const me = await getMe();
|
|
if (!me) {
|
|
// Not authenticated — bounce to login. getMe() returns null on 401.
|
|
return (
|
|
<main style={{ fontFamily: "system-ui", maxWidth: "32rem", margin: "4rem auto", padding: "0 1rem" }}>
|
|
<h1>CoreCI Chat</h1>
|
|
<p>You are not signed in.</p>
|
|
<p>
|
|
<a href="/login">
|
|
<button style={{ padding: "0.6rem 1.2rem", font: "inherit" }}>Go to login</button>
|
|
</a>
|
|
</p>
|
|
</main>
|
|
);
|
|
}
|
|
|
|
const steps = [
|
|
{ id: "byom", label: "Configure BYOM", wave: "C" },
|
|
{ id: "relay", label: "Install Relay Agent", wave: "D" },
|
|
{ id: "target", label: "Register Target", wave: "D" },
|
|
{ id: "verify", label: "Verify Green Status", wave: "E" },
|
|
{ id: "team", label: "Invite Team", wave: "B" },
|
|
];
|
|
|
|
return (
|
|
<main style={{ fontFamily: "system-ui", maxWidth: "48rem", margin: "2rem auto", padding: "0 1rem" }}>
|
|
<header style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
|
|
<h1>CoreCI Chat Dashboard</h1>
|
|
<span style={{ color: "#666", fontSize: "0.85rem" }}>
|
|
{me.role} · tenant {me.tenantId.slice(0, 8)}
|
|
</span>
|
|
</header>
|
|
|
|
<section>
|
|
<h2>Onboarding</h2>
|
|
<ul style={{ listStyle: "none", padding: 0 }}>
|
|
{steps.map((s) => (
|
|
<li key={s.id} style={{ padding: "0.4rem 0", display: "flex", gap: "0.6rem", alignItems: "center" }}>
|
|
<span
|
|
aria-label={s.id + " status"}
|
|
style={{
|
|
width: "0.9rem",
|
|
height: "0.9rem",
|
|
borderRadius: "50%",
|
|
background: "#ccc",
|
|
display: "inline-block",
|
|
}}
|
|
/>
|
|
<span>{s.label}</span>
|
|
<span style={{ color: "#999", fontSize: "0.75rem" }}>(Wave {s.wave})</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</section>
|
|
|
|
<p style={{ marginTop: "2rem" }}>
|
|
<a href="/api/auth/logout">Sign out</a> ·{" "}
|
|
<a href="/dashboard/team">Team</a>
|
|
</p>
|
|
</main>
|
|
);
|
|
} |