feat(16-04): show internalName with AD-name fallback in groups list
Name column renders group.internalName ?? group.name (nullish, not
truthiness, since the backend already normalizes blank values to null)
inside a span carrying title={group.name} so the AD name stays
discoverable on hover once an internal name is set. Badge column is
untouched — it remains the sole imported-vs-local marker per D-07.
Adds two component-test cases covering the fallback and its title
attribute (D-04).
This commit is contained in:
@@ -96,6 +96,7 @@ interface Group {
|
||||
tenantId: string;
|
||||
name: string;
|
||||
ldapDn: string | null;
|
||||
internalName: string | null;
|
||||
isDefault: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
@@ -108,6 +109,7 @@ const mockGroups: Group[] = [
|
||||
tenantId: 't1',
|
||||
name: 'Alle Benutzer',
|
||||
ldapDn: null,
|
||||
internalName: null,
|
||||
isDefault: true,
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
updatedAt: '2026-01-01T00:00:00.000Z',
|
||||
@@ -118,6 +120,32 @@ const mockGroups: Group[] = [
|
||||
tenantId: 't1',
|
||||
name: 'Buchhaltung',
|
||||
ldapDn: 'CN=Buchhaltung,OU=Gruppen,DC=ctl,DC=local',
|
||||
internalName: null,
|
||||
isDefault: false,
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
updatedAt: '2026-01-01T00:00:00.000Z',
|
||||
memberCount: 1,
|
||||
},
|
||||
];
|
||||
|
||||
const mockGroupsWithInternalName: Group[] = [
|
||||
{
|
||||
id: 'g3',
|
||||
tenantId: 't1',
|
||||
name: 'AD-Vertrieb',
|
||||
ldapDn: 'CN=AD-Vertrieb,OU=Gruppen,DC=ctl,DC=local',
|
||||
internalName: 'Vertrieb',
|
||||
isDefault: false,
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
updatedAt: '2026-01-01T00:00:00.000Z',
|
||||
memberCount: 2,
|
||||
},
|
||||
{
|
||||
id: 'g4',
|
||||
tenantId: 't1',
|
||||
name: 'AD-Support',
|
||||
ldapDn: 'CN=AD-Support,OU=Gruppen,DC=ctl,DC=local',
|
||||
internalName: null,
|
||||
isDefault: false,
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
updatedAt: '2026-01-01T00:00:00.000Z',
|
||||
@@ -178,6 +206,35 @@ describe('AdminGroupsPage', () => {
|
||||
expect(screen.getByText('1')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the internal name in the name column and the AD name as title when internalName is set (D-04)', async () => {
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve(mockGroupsWithInternalName) })),
|
||||
);
|
||||
|
||||
render(<AdminGroupsPage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Vertrieb')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.queryByText('AD-Vertrieb')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('Vertrieb').closest('span')).toHaveAttribute('title', 'AD-Vertrieb');
|
||||
});
|
||||
|
||||
it('falls back to the stored name in the name column when internalName is not set (D-04)', async () => {
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve(mockGroupsWithInternalName) })),
|
||||
);
|
||||
|
||||
render(<AdminGroupsPage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('AD-Support')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('AD-Support').closest('span')).toHaveAttribute('title', 'AD-Support');
|
||||
});
|
||||
|
||||
it('toggles the default-group star optimistically and persists via PATCH', async () => {
|
||||
const fetchMock = vi.fn((url: string, init?: RequestInit) => {
|
||||
if (typeof url === 'string' && url.endsWith('/groups') && (!init || init.method === undefined)) {
|
||||
|
||||
@@ -177,7 +177,9 @@ export default function AdminGroupsPage() {
|
||||
<tbody className="divide-y divide-border">
|
||||
{groups.map((group) => (
|
||||
<tr key={group.id} className="hover:bg-muted/30 transition-colors">
|
||||
<td className="px-4 py-3 font-medium text-foreground">{group.name}</td>
|
||||
<td className="px-4 py-3 font-medium text-foreground">
|
||||
<span title={group.name}>{group.internalName ?? group.name}</span>
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<span
|
||||
className={`inline-block rounded-full px-2 py-0.5 text-xs font-medium ${
|
||||
|
||||
Reference in New Issue
Block a user