forked from baron/baron-sso
feat(adminfront): remove unused tenant dashboard and update global overview quick links
This commit is contained in:
@@ -6,7 +6,6 @@ import AuditLogsPage from "../features/audit/AuditLogsPage";
|
|||||||
import AuthCallbackPage from "../features/auth/AuthCallbackPage";
|
import AuthCallbackPage from "../features/auth/AuthCallbackPage";
|
||||||
import AuthPage from "../features/auth/AuthPage";
|
import AuthPage from "../features/auth/AuthPage";
|
||||||
import LoginPage from "../features/auth/LoginPage";
|
import LoginPage from "../features/auth/LoginPage";
|
||||||
import DashboardPage from "../features/dashboard/DashboardPage";
|
|
||||||
import GlobalOverviewPage from "../features/overview/GlobalOverviewPage";
|
import GlobalOverviewPage from "../features/overview/GlobalOverviewPage";
|
||||||
import { TenantAdminsAndOwnersTab } from "../features/tenants/routes/TenantAdminsAndOwnersTab";
|
import { TenantAdminsAndOwnersTab } from "../features/tenants/routes/TenantAdminsAndOwnersTab";
|
||||||
import TenantCreatePage from "../features/tenants/routes/TenantCreatePage";
|
import TenantCreatePage from "../features/tenants/routes/TenantCreatePage";
|
||||||
@@ -35,7 +34,6 @@ export const router = createBrowserRouter(
|
|||||||
element: <AppLayout />,
|
element: <AppLayout />,
|
||||||
children: [
|
children: [
|
||||||
{ index: true, element: <GlobalOverviewPage /> },
|
{ index: true, element: <GlobalOverviewPage /> },
|
||||||
{ path: "dashboard", element: <DashboardPage /> },
|
|
||||||
{ path: "audit-logs", element: <AuditLogsPage /> },
|
{ path: "audit-logs", element: <AuditLogsPage /> },
|
||||||
{ path: "auth", element: <AuthPage /> },
|
{ path: "auth", element: <AuthPage /> },
|
||||||
{ path: "users", element: <UserListPage /> },
|
{ path: "users", element: <UserListPage /> },
|
||||||
|
|||||||
@@ -24,11 +24,6 @@ import RoleSwitcher from "./RoleSwitcher";
|
|||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{ label: "ui.admin.nav.overview", to: "/", icon: LayoutDashboard },
|
{ label: "ui.admin.nav.overview", to: "/", icon: LayoutDashboard },
|
||||||
{
|
|
||||||
label: "ui.admin.nav.tenant_dashboard",
|
|
||||||
to: "/dashboard",
|
|
||||||
icon: ShieldHalf,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: "ui.admin.nav.tenants",
|
label: "ui.admin.nav.tenants",
|
||||||
to: "/tenants",
|
to: "/tenants",
|
||||||
|
|||||||
@@ -1,243 +0,0 @@
|
|||||||
import {
|
|
||||||
Activity,
|
|
||||||
ArrowRight,
|
|
||||||
Building2,
|
|
||||||
CheckCircle2,
|
|
||||||
LineChart,
|
|
||||||
Radio,
|
|
||||||
ShieldCheck,
|
|
||||||
Sparkles,
|
|
||||||
} from "lucide-react";
|
|
||||||
|
|
||||||
const guardHighlights = [
|
|
||||||
{
|
|
||||||
title: "Tenant isolation",
|
|
||||||
body: "All admin calls expect X-Tenant-ID and are prepared for tenant-aware headers.",
|
|
||||||
metric: "Header guard",
|
|
||||||
accent: "active",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Admin TTL",
|
|
||||||
body: "Session budget kept short for admins. App session vs admin session split is explicit.",
|
|
||||||
metric: "15m default",
|
|
||||||
accent: "ttl",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Audit-first",
|
|
||||||
body: "Every management action should log to ClickHouse. Hooks in place for later wiring.",
|
|
||||||
metric: "per-action",
|
|
||||||
accent: "audit",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const stackReadiness = [
|
|
||||||
"React 19 + Vite 7, strict TS, Router v6 data router.",
|
|
||||||
"TanStack Query 5 provider ready with sane defaults.",
|
|
||||||
"Axios client stub with bearer + tenant header injector.",
|
|
||||||
"Tailwind v4 tokens tuned for admin dark plane.",
|
|
||||||
"React Hook Form + Zod planned for client forms.",
|
|
||||||
"IdP-neutral auth hook point reserved for role guard.",
|
|
||||||
];
|
|
||||||
|
|
||||||
const nextSteps = [
|
|
||||||
"Add IdP-neutral OIDC/OAuth auth layer and enforce admin role in RequireAuth.",
|
|
||||||
"Persist tenant picklist and feed X-Tenant-ID for every admin call.",
|
|
||||||
"Add shadcn/ui primitives for forms and tables; lock lint/format.",
|
|
||||||
];
|
|
||||||
|
|
||||||
function DashboardPage() {
|
|
||||||
return (
|
|
||||||
<div className="space-y-10">
|
|
||||||
<section className="relative overflow-hidden rounded-2xl border border-[var(--color-border)] bg-[var(--color-panel)] p-7 shadow-[var(--shadow-card)]">
|
|
||||||
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_24%_20%,rgba(54,211,153,0.14),transparent_32%)]" />
|
|
||||||
<div className="relative flex flex-col gap-6 md:flex-row md:items-center md:justify-between">
|
|
||||||
<div className="space-y-3 max-w-2xl">
|
|
||||||
<div className="inline-flex items-center gap-2 rounded-full border border-[var(--color-border)] px-3 py-1 text-xs uppercase tracking-[0.2em] text-[var(--color-muted)]">
|
|
||||||
<Sparkles size={14} />
|
|
||||||
adminfront ready
|
|
||||||
</div>
|
|
||||||
<h2 className="text-3xl font-semibold leading-tight">
|
|
||||||
Build the admin plane with{" "}
|
|
||||||
<span className="text-[var(--color-accent)]">tenant-aware</span>{" "}
|
|
||||||
defaults and{" "}
|
|
||||||
<span className="text-[var(--color-accent-strong)]">
|
|
||||||
least privilege
|
|
||||||
</span>{" "}
|
|
||||||
UX.
|
|
||||||
</h2>
|
|
||||||
<p className="text-[var(--color-muted)]">
|
|
||||||
Route, query, and styling scaffolds are in place. Use this canvas
|
|
||||||
to ship RP registry, audit exploration, and guarded login aligned
|
|
||||||
with issue #60 while keeping providers swappable.
|
|
||||||
</p>
|
|
||||||
<div className="flex flex-wrap gap-3 text-sm">
|
|
||||||
<span className="rounded-full bg-[rgba(54,211,153,0.16)] px-3 py-2 text-[var(--color-accent)]">
|
|
||||||
Router + Query wired
|
|
||||||
</span>
|
|
||||||
<span className="rounded-full border border-[var(--color-border)] px-3 py-2 text-[var(--color-muted)]">
|
|
||||||
Admin namespace only
|
|
||||||
</span>
|
|
||||||
<span className="rounded-full bg-[rgba(249,168,38,0.16)] px-3 py-2 font-semibold text-[var(--color-accent-strong)]">
|
|
||||||
Auth hook pending
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="grid gap-3 text-sm">
|
|
||||||
<div className="flex items-center gap-2 rounded-xl border border-[var(--color-border)] bg-[rgba(255,255,255,0.02)] px-4 py-3 text-[var(--color-muted)]">
|
|
||||||
<ShieldCheck size={16} />
|
|
||||||
Admin guard scoped to /admin
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2 rounded-xl border border-[var(--color-border)] bg-[rgba(255,255,255,0.02)] px-4 py-3 text-[var(--color-muted)]">
|
|
||||||
<Building2 size={16} />
|
|
||||||
Tenant selection placeholder ready
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2 rounded-xl border border-[var(--color-border)] bg-[rgba(255,255,255,0.02)] px-4 py-3 text-[var(--color-muted)]">
|
|
||||||
<Radio size={16} />
|
|
||||||
Audit stream hook for ClickHouse
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="grid gap-4 md:grid-cols-3">
|
|
||||||
{guardHighlights.map((item) => (
|
|
||||||
<div
|
|
||||||
key={item.title}
|
|
||||||
className="relative overflow-hidden rounded-xl border border-[var(--color-border)] bg-[var(--color-panel)] p-5 transition hover:-translate-y-1 hover:shadow-[0_16px_48px_rgba(7,15,26,0.4)]"
|
|
||||||
>
|
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_25%_25%,rgba(54,211,153,0.12),transparent_45%)]" />
|
|
||||||
<div className="relative flex items-center justify-between gap-2">
|
|
||||||
<div className="text-xs uppercase tracking-[0.2em] text-[var(--color-muted)]">
|
|
||||||
{item.metric}
|
|
||||||
</div>
|
|
||||||
<span className="rounded-full border border-[var(--color-border)] px-3 py-1 text-[11px] text-[var(--color-muted)]">
|
|
||||||
{item.accent}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="relative mt-3 space-y-2">
|
|
||||||
<h3 className="text-lg font-semibold">{item.title}</h3>
|
|
||||||
<p className="text-sm text-[var(--color-muted)]">{item.body}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="grid gap-6 md:grid-cols-[1.2fr,0.8fr]">
|
|
||||||
<div className="rounded-2xl border border-[var(--color-border)] bg-[var(--color-panel)] p-6">
|
|
||||||
<div className="flex items-center justify-between gap-3">
|
|
||||||
<div>
|
|
||||||
<p className="text-xs uppercase tracking-[0.2em] text-[var(--color-muted)]">
|
|
||||||
Stack readiness
|
|
||||||
</p>
|
|
||||||
<h3 className="text-xl font-semibold">Matches issue #60</h3>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="inline-flex items-center gap-2 rounded-full border border-[var(--color-border)] px-3 py-2 text-sm text-[var(--color-muted)] transition hover:border-[var(--color-accent)] hover:text-[var(--color-accent)]"
|
|
||||||
>
|
|
||||||
Setup notes
|
|
||||||
<ArrowRight size={14} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="mt-4 grid gap-3 md:grid-cols-2">
|
|
||||||
{stackReadiness.map((item) => (
|
|
||||||
<div
|
|
||||||
key={item}
|
|
||||||
className="flex items-center gap-3 rounded-xl border border-[var(--color-border)] bg-[rgba(255,255,255,0.02)] px-4 py-3"
|
|
||||||
>
|
|
||||||
<CheckCircle2
|
|
||||||
size={16}
|
|
||||||
className="text-[var(--color-accent)]"
|
|
||||||
/>
|
|
||||||
<p className="text-sm">{item}</p>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="rounded-2xl border border-[var(--color-border)] bg-[var(--color-panel)] p-6">
|
|
||||||
<p className="text-xs uppercase tracking-[0.2em] text-[var(--color-muted)]">
|
|
||||||
Next actions
|
|
||||||
</p>
|
|
||||||
<h3 className="mt-2 text-xl font-semibold">
|
|
||||||
Ship the first guarded flows
|
|
||||||
</h3>
|
|
||||||
<div className="mt-4 space-y-3">
|
|
||||||
{nextSteps.map((item, idx) => (
|
|
||||||
<div
|
|
||||||
key={item}
|
|
||||||
className="flex gap-3 rounded-xl border border-[var(--color-border)] bg-[rgba(255,255,255,0.02)] px-4 py-3"
|
|
||||||
>
|
|
||||||
<div className="grid h-8 w-8 place-items-center rounded-full bg-[rgba(249,168,38,0.12)] text-sm font-semibold text-[var(--color-accent-strong)]">
|
|
||||||
{idx + 1}
|
|
||||||
</div>
|
|
||||||
<p className="text-sm text-[var(--color-text)]">{item}</p>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="rounded-2xl border border-[var(--color-border)] bg-[var(--color-panel)] p-6">
|
|
||||||
<div className="flex flex-col gap-2 md:flex-row md:items-center md:justify-between">
|
|
||||||
<div>
|
|
||||||
<p className="text-xs uppercase tracking-[0.2em] text-[var(--color-muted)]">
|
|
||||||
Ops board
|
|
||||||
</p>
|
|
||||||
<h3 className="text-xl font-semibold">What to prototype next</h3>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2 text-sm text-[var(--color-muted)]">
|
|
||||||
<span className="rounded-full border border-[var(--color-border)] px-3 py-2">
|
|
||||||
Audit → ClickHouse
|
|
||||||
</span>
|
|
||||||
<span className="rounded-full border border-[var(--color-border)] px-3 py-2">
|
|
||||||
RP registry
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mt-4 grid gap-4 md:grid-cols-3">
|
|
||||||
<div className="rounded-xl border border-[var(--color-border)] bg-[rgba(255,255,255,0.02)] p-4">
|
|
||||||
<div className="flex items-center gap-2 text-[var(--color-muted)]">
|
|
||||||
<LineChart size={16} />
|
|
||||||
<span className="text-xs uppercase tracking-[0.16em]">
|
|
||||||
Metrics
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<h4 className="mt-2 text-lg font-semibold">
|
|
||||||
RP registration funnel
|
|
||||||
</h4>
|
|
||||||
<p className="text-sm text-[var(--color-muted)]">
|
|
||||||
Visualize create → secret rotate → redirect URI edits per tenant.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="rounded-xl border border-[var(--color-border)] bg-[rgba(255,255,255,0.02)] p-4">
|
|
||||||
<div className="flex items-center gap-2 text-[var(--color-muted)]">
|
|
||||||
<Activity size={16} />
|
|
||||||
<span className="text-xs uppercase tracking-[0.16em]">Audit</span>
|
|
||||||
</div>
|
|
||||||
<h4 className="mt-2 text-lg font-semibold">Admin action stream</h4>
|
|
||||||
<p className="text-sm text-[var(--color-muted)]">
|
|
||||||
Live feed of admin API calls with per-action tenant, actor, and
|
|
||||||
rate-limit outcome.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="rounded-xl border border-[var(--color-border)] bg-[rgba(255,255,255,0.02)] p-4">
|
|
||||||
<div className="flex items-center gap-2 text-[var(--color-muted)]">
|
|
||||||
<ShieldCheck size={16} />
|
|
||||||
<span className="text-xs uppercase tracking-[0.16em]">
|
|
||||||
Access
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<h4 className="mt-2 text-lg font-semibold">Admin login journey</h4>
|
|
||||||
<p className="text-sm text-[var(--color-muted)]">
|
|
||||||
Outline SMS + app-based MFA choice and emphasize “admin session”
|
|
||||||
TTL with logout.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DashboardPage;
|
|
||||||
@@ -193,10 +193,10 @@ function GlobalOverviewPage() {
|
|||||||
className="w-full justify-between"
|
className="w-full justify-between"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
>
|
>
|
||||||
<Link to="/audit-logs">
|
<Link to="/users">
|
||||||
{t(
|
{t(
|
||||||
"ui.admin.overview.quick_links.view_audit_logs",
|
"ui.admin.overview.quick_links.user_management",
|
||||||
"감사 로그 보기",
|
"사용자 관리",
|
||||||
)}
|
)}
|
||||||
<ArrowUpRight size={16} />
|
<ArrowUpRight size={16} />
|
||||||
</Link>
|
</Link>
|
||||||
@@ -206,10 +206,23 @@ function GlobalOverviewPage() {
|
|||||||
className="w-full justify-between"
|
className="w-full justify-between"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
>
|
>
|
||||||
<Link to="/dashboard">
|
<Link to="/api-keys">
|
||||||
{t(
|
{t(
|
||||||
"ui.admin.overview.quick_links.tenant_dashboard",
|
"ui.admin.overview.quick_links.api_key_management",
|
||||||
"테넌트 대시보드",
|
"API 키 관리",
|
||||||
|
)}
|
||||||
|
<ArrowUpRight size={16} />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
className="w-full justify-between"
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
<Link to="/audit-logs">
|
||||||
|
{t(
|
||||||
|
"ui.admin.overview.quick_links.view_audit_logs",
|
||||||
|
"감사 로그 보기",
|
||||||
)}
|
)}
|
||||||
<ArrowUpRight size={16} />
|
<ArrowUpRight size={16} />
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -732,9 +732,10 @@ title = "Tenant-independent control plane"
|
|||||||
title = "Admin playbook"
|
title = "Admin playbook"
|
||||||
|
|
||||||
[ui.admin.overview.quick_links]
|
[ui.admin.overview.quick_links]
|
||||||
add_tenant = "Tenant Add"
|
add_tenant = "Add Tenant"
|
||||||
tenant_dashboard = "Tenant Dashboard"
|
api_key_management = "API Key Management"
|
||||||
title = "Title"
|
title = "Quick Links"
|
||||||
|
user_management = "User Management"
|
||||||
view_audit_logs = "View Audit Logs"
|
view_audit_logs = "View Audit Logs"
|
||||||
|
|
||||||
[ui.admin.role]
|
[ui.admin.role]
|
||||||
@@ -1393,7 +1394,6 @@ auth_guard = "Auth Guard"
|
|||||||
logout = "Logout"
|
logout = "Logout"
|
||||||
overview = "Overview"
|
overview = "Overview"
|
||||||
relying_parties = "Apps (RP)"
|
relying_parties = "Apps (RP)"
|
||||||
tenant_dashboard = "Tenant Dashboard"
|
|
||||||
user_groups = "Organization"
|
user_groups = "Organization"
|
||||||
tenants = "Tenants"
|
tenants = "Tenants"
|
||||||
users = "Users"
|
users = "Users"
|
||||||
|
|||||||
@@ -777,8 +777,9 @@ title = "운영 플레이북"
|
|||||||
|
|
||||||
[ui.admin.overview.quick_links]
|
[ui.admin.overview.quick_links]
|
||||||
add_tenant = "테넌트 추가"
|
add_tenant = "테넌트 추가"
|
||||||
tenant_dashboard = "테넌트 대시보드"
|
api_key_management = "API 키 관리"
|
||||||
title = "빠른 이동"
|
title = "빠른 이동"
|
||||||
|
user_management = "사용자 관리"
|
||||||
view_audit_logs = "감사 로그 보기"
|
view_audit_logs = "감사 로그 보기"
|
||||||
|
|
||||||
[ui.admin.overview.summary]
|
[ui.admin.overview.summary]
|
||||||
@@ -1485,7 +1486,6 @@ auth_guard = "인증 가드"
|
|||||||
logout = "로그아웃"
|
logout = "로그아웃"
|
||||||
overview = "개요"
|
overview = "개요"
|
||||||
relying_parties = "애플리케이션(RP)"
|
relying_parties = "애플리케이션(RP)"
|
||||||
tenant_dashboard = "테넌트 대시보드"
|
|
||||||
user_groups = "조직 관리"
|
user_groups = "조직 관리"
|
||||||
tenants = "테넌트"
|
tenants = "테넌트"
|
||||||
users = "사용자"
|
users = "사용자"
|
||||||
|
|||||||
@@ -691,7 +691,6 @@ auth_guard = ""
|
|||||||
logout = ""
|
logout = ""
|
||||||
overview = ""
|
overview = ""
|
||||||
relying_parties = ""
|
relying_parties = ""
|
||||||
tenant_dashboard = ""
|
|
||||||
user_groups = ""
|
user_groups = ""
|
||||||
tenants = ""
|
tenants = ""
|
||||||
users = ""
|
users = ""
|
||||||
@@ -705,8 +704,9 @@ title = ""
|
|||||||
|
|
||||||
[ui.admin.overview.quick_links]
|
[ui.admin.overview.quick_links]
|
||||||
add_tenant = ""
|
add_tenant = ""
|
||||||
tenant_dashboard = ""
|
api_key_management = ""
|
||||||
title = ""
|
title = ""
|
||||||
|
user_management = ""
|
||||||
view_audit_logs = ""
|
view_audit_logs = ""
|
||||||
|
|
||||||
[ui.admin.role]
|
[ui.admin.role]
|
||||||
|
|||||||
Reference in New Issue
Block a user