fix: sort RBAC dashboard diagram columns consistently

This commit is contained in:
hsiegeln
2026-03-17 18:32:14 +01:00
parent 4842507ff3
commit 1881aca0e4

View File

@@ -1,38 +1,72 @@
import { useRbacStats, useGroups, useRoles } from '../../../api/queries/admin/rbac';
import type { GroupDetail, RoleDetail } from '../../../api/queries/admin/rbac';
import { useMemo } from 'react';
import { useRbacStats, useGroups } from '../../../api/queries/admin/rbac';
import type { GroupDetail } from '../../../api/queries/admin/rbac';
import styles from './RbacPage.module.css';
export function DashboardTab() {
const stats = useRbacStats();
const groups = useGroups();
const roles = useRoles();
const groupList: GroupDetail[] = groups.data ?? [];
// Build inheritance diagram data: top-level groups sorted alphabetically,
// children sorted alphabetically and indented below their parent.
const { topLevelGroups, childMap } = useMemo(() => {
const sorted = [...groupList].sort((a, b) => a.name.localeCompare(b.name));
const top = sorted.filter((g) => !g.parentGroupId);
const cMap = new Map<string, GroupDetail[]>();
for (const g of sorted) {
if (g.parentGroupId) {
const children = cMap.get(g.parentGroupId) ?? [];
children.push(g);
cMap.set(g.parentGroupId, children);
}
}
return { topLevelGroups: top, childMap: cMap };
}, [groupList]);
// Derive roles from groups in tree order (top-level then children), collecting
// each group's directRoles, deduplicating by id and preserving first-seen order.
const roleList = useMemo(() => {
const seen = new Set<string>();
const result: { id: string; name: string }[] = [];
for (const g of topLevelGroups) {
for (const r of g.directRoles) {
if (!seen.has(r.id)) {
seen.add(r.id);
result.push(r);
}
}
for (const child of childMap.get(g.id) ?? []) {
for (const r of child.directRoles) {
if (!seen.has(r.id)) {
seen.add(r.id);
result.push(r);
}
}
}
}
return result;
}, [topLevelGroups, childMap]);
// Collect unique users from all groups, sorted alphabetically by displayName.
const allUsers = useMemo(() => {
const userMap = new Map<string, string>();
for (const g of groupList) {
for (const m of g.members) {
userMap.set(m.userId, m.displayName);
}
}
return new Map(
[...userMap.entries()].sort((a, b) => a[1].localeCompare(b[1]))
);
}, [groupList]);
if (stats.isLoading) {
return <div className={styles.loading}>Loading...</div>;
}
const s = stats.data;
const groupList: GroupDetail[] = groups.data ?? [];
const roleList: RoleDetail[] = roles.data ?? [];
// Build inheritance diagram data
const topLevelGroups = groupList.filter((g) => !g.parentGroupId);
const childMap = new Map<string, GroupDetail[]>();
for (const g of groupList) {
if (g.parentGroupId) {
const children = childMap.get(g.parentGroupId) ?? [];
children.push(g);
childMap.set(g.parentGroupId, children);
}
}
// Collect unique users from all groups
const allUsers = new Map<string, string>();
for (const g of groupList) {
for (const m of g.members) {
allUsers.set(m.userId, m.displayName);
}
}
return (
<div>