fix(permissions): flatten permission matrix table to fix column alignment and scroll lag

This commit is contained in:
Matthias Hochmeister
2026-04-18 16:20:44 +02:00
parent fa9f50d982
commit bef5a685a8

View File

@@ -460,67 +460,57 @@ function PermissionMatrixTab() {
})} })}
</TableRow> </TableRow>
<TableRow> {isExpanded && (() => {
<TableCell colSpan={2 + nonAdminGroups.length} sx={{ p: 0 }}> let lastSubGroup: string | null | undefined = undefined;
<Collapse in={isExpanded} timeout="auto" unmountOnExit> return fgPerms.map((perm: Permission) => {
<Table size="small"> const depTooltip = getDepTooltip(perm.id);
<TableBody> const tooltipText = [perm.description, depTooltip].filter(Boolean).join('\n');
{(() => { const subGroup = getSubGroupLabel(fg.id, perm.id);
let lastSubGroup: string | null | undefined = undefined; const showSubGroupHeader = subGroup !== lastSubGroup && subGroup !== null;
return fgPerms.map((perm: Permission) => { lastSubGroup = subGroup;
const depTooltip = getDepTooltip(perm.id); return (
const tooltipText = [perm.description, depTooltip].filter(Boolean).join('\n'); <React.Fragment key={perm.id}>
const subGroup = getSubGroupLabel(fg.id, perm.id); {showSubGroupHeader && (
const showSubGroupHeader = subGroup !== lastSubGroup && subGroup !== null; <TableRow>
lastSubGroup = subGroup; <TableCell
return ( colSpan={2 + nonAdminGroups.length}
<React.Fragment key={perm.id}> sx={{ pl: 5, py: 0.5, bgcolor: 'action.selected' }}
{showSubGroupHeader && ( >
<TableRow> <Typography variant="caption" sx={{ fontWeight: 600, textTransform: 'uppercase', letterSpacing: 0.5, color: 'text.secondary' }}>
<TableCell {subGroup}
colSpan={2 + nonAdminGroups.length} </Typography>
sx={{ pl: 5, py: 0.5, bgcolor: 'action.selected', position: 'sticky', left: 0, zIndex: 1 }} </TableCell>
> </TableRow>
<Typography variant="caption" sx={{ fontWeight: 600, textTransform: 'uppercase', letterSpacing: 0.5, color: 'text.secondary' }}> )}
{subGroup} <TableRow hover>
</Typography> <TableCell sx={{ pl: 6, bgcolor: 'background.paper' }}>
</TableCell> <Tooltip title={tooltipText || ''} placement="right"><span>{perm.label}</span></Tooltip>
</TableRow> </TableCell>
)} <TableCell align="center">
<TableRow hover> <Checkbox checked disabled sx={{ opacity: 0.3 }} />
<TableCell sx={{ pl: 6, minWidth: 250, position: 'sticky', left: 0, zIndex: 1, bgcolor: 'background.paper' }}> </TableCell>
<Tooltip title={tooltipText || ''} placement="right"><span>{perm.label}</span></Tooltip> {nonAdminGroups.map(g => {
</TableCell> const isGranted = (grants[g] || []).includes(perm.id);
<TableCell align="center" sx={{ minWidth: 120 }}> const curReverseDeps = reverseDeps[perm.id] || [];
<Checkbox checked disabled sx={{ opacity: 0.3 }} /> const isRequiredByOther = isGranted && curReverseDeps.some(d => (grants[g] || []).includes(d));
</TableCell> return (
{nonAdminGroups.map(g => { <TableCell key={g} align="center">
const isGranted = (grants[g] || []).includes(perm.id); <Tooltip title={isRequiredByOther ? 'Wird von anderen Berechtigungen benötigt' : ''} placement="top">
const curReverseDeps = reverseDeps[perm.id] || []; <span>
const isRequiredByOther = isGranted && curReverseDeps.some(d => (grants[g] || []).includes(d)); <Checkbox checked={isGranted}
return ( onChange={() => handlePermissionToggle(g, perm.id, grants, groups)}
<TableCell key={g} align="center" sx={{ minWidth: 120 }}> disabled={permissionMutation.isPending} size="small"
<Tooltip title={isRequiredByOther ? 'Wird von anderen Berechtigungen benötigt' : ''} placement="top"> sx={isRequiredByOther ? { color: 'warning.main', '&.Mui-checked': { color: 'warning.main' } } : undefined} />
<span> </span>
<Checkbox checked={isGranted} </Tooltip>
onChange={() => handlePermissionToggle(g, perm.id, grants, groups)} </TableCell>
disabled={permissionMutation.isPending} size="small" );
sx={isRequiredByOther ? { color: 'warning.main', '&.Mui-checked': { color: 'warning.main' } } : undefined} /> })}
</span> </TableRow>
</Tooltip> </React.Fragment>
</TableCell> );
); });
})} })()}
</TableRow>
</React.Fragment>
);
});
})()}
</TableBody>
</Table>
</Collapse>
</TableCell>
</TableRow>
</React.Fragment> </React.Fragment>
); );
})} })}