1
0
forked from baron/baron-sso

feat: implement role-based UI filtering for overview and navigation

This commit is contained in:
2026-03-04 14:01:12 +09:00
parent 20a8a19e12
commit 145b807ebf
2 changed files with 41 additions and 28 deletions

View File

@@ -52,9 +52,15 @@ function AppLayout() {
const isTenantAdmin = profile?.role === "tenant_admin"; const isTenantAdmin = profile?.role === "tenant_admin";
const manageableCount = profile?.manageableTenants?.length ?? 0; const manageableCount = profile?.manageableTenants?.length ?? 0;
// Filter out restricted items for non-super admins
const filteredItems = items.filter(item => {
if (item.to === "/api-keys") return isSuperAdmin;
return true;
});
if (isSuperAdmin) { if (isSuperAdmin) {
// Super Admin sees everything // Super Admin sees everything
items.splice(1, 0, { filteredItems.splice(1, 0, {
label: "ui.admin.nav.tenants", label: "ui.admin.nav.tenants",
to: "/tenants", to: "/tenants",
icon: Building2, icon: Building2,
@@ -62,14 +68,14 @@ function AppLayout() {
} else if (isTenantAdmin) { } else if (isTenantAdmin) {
if (manageableCount <= 1 && profile?.tenantId) { if (manageableCount <= 1 && profile?.tenantId) {
// Direct link if only one (or zero in array but has tenantId) tenant // Direct link if only one (or zero in array but has tenantId) tenant
items.splice(1, 0, { filteredItems.splice(1, 0, {
label: "ui.admin.nav.my_tenant", label: "ui.admin.nav.my_tenant",
to: `/tenants/${profile.tenantId}`, to: `/tenants/${profile.tenantId}`,
icon: Building2, icon: Building2,
}); });
} else if (manageableCount > 1) { } else if (manageableCount > 1) {
// Show list menu if multiple tenants // Show list menu if multiple tenants
items.splice(1, 0, { filteredItems.splice(1, 0, {
label: "ui.admin.nav.tenants", label: "ui.admin.nav.tenants",
to: "/tenants", to: "/tenants",
icon: Building2, icon: Building2,
@@ -77,7 +83,7 @@ function AppLayout() {
} }
} }
return items; return filteredItems;
}, [profile]); }, [profile]);
const handleLogout = () => { const handleLogout = () => {

View File

@@ -17,6 +17,7 @@ import {
CardTitle, CardTitle,
} from "../../components/ui/card"; } from "../../components/ui/card";
import { t } from "../../lib/i18n"; import { t } from "../../lib/i18n";
import { RoleGuard } from "../../components/auth/RoleGuard";
import PermissionChecker from "./components/PermissionChecker"; import PermissionChecker from "./components/PermissionChecker";
const summaryCards = [ const summaryCards = [
@@ -178,16 +179,18 @@ function GlobalOverviewPage() {
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent className="space-y-3"> <CardContent className="space-y-3">
<Button <RoleGuard roles={["super_admin"]}>
asChild <Button
className="w-full justify-between" asChild
variant="outline" className="w-full justify-between"
> variant="outline"
<Link to="/tenants/new"> >
{t("ui.admin.overview.quick_links.add_tenant", "테넌트 추가")} <Link to="/tenants/new">
<ArrowUpRight size={16} /> {t("ui.admin.overview.quick_links.add_tenant", "테넌트 추가")}
</Link> <ArrowUpRight size={16} />
</Button> </Link>
</Button>
</RoleGuard>
<Button <Button
asChild asChild
className="w-full justify-between" className="w-full justify-between"
@@ -201,19 +204,21 @@ function GlobalOverviewPage() {
<ArrowUpRight size={16} /> <ArrowUpRight size={16} />
</Link> </Link>
</Button> </Button>
<Button <RoleGuard roles={["super_admin"]}>
asChild <Button
className="w-full justify-between" asChild
variant="outline" className="w-full justify-between"
> variant="outline"
<Link to="/api-keys"> >
{t( <Link to="/api-keys">
"ui.admin.overview.quick_links.api_key_management", {t(
"API 키 관리", "ui.admin.overview.quick_links.api_key_management",
)} "API 키 관리",
<ArrowUpRight size={16} /> )}
</Link> <ArrowUpRight size={16} />
</Button> </Link>
</Button>
</RoleGuard>
<Button <Button
asChild asChild
className="w-full justify-between" className="w-full justify-between"
@@ -231,7 +236,9 @@ function GlobalOverviewPage() {
</Card> </Card>
</div> </div>
<PermissionChecker /> <RoleGuard roles={["super_admin"]}>
<PermissionChecker />
</RoleGuard>
</div> </div>
); );
} }