Einheitliche Seitenkoepfe mit Modul-Kachel, Knopf- und Linkklassen
statt gelber Schrift, Karten ohne harte Rahmen, Tabellenkoepfe ohne
Grossbuchstaben, Marktplatz mit Fluent-Reitern, Filterpillen und
Kachel-Karten, Einstellungs-/Verwaltungsnavigation mit Auswahlpille,
leere Zustaende mit Symbol im Kreis, Proxmox ohne leuchtende Schatten.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
useButtonType: alle Schaltflaechen ausserhalb der drei echten Formulare
(Mandanten/Benutzer/LDAP) erhalten type="button"; die drei tatsaechlichen
Absende-Buttons behalten type="submit" (Zahl bleibt 1/1/2, siehe <verify>).
noSvgWithoutTitle: Symbole neben sichtbarem Text (Zurueck-Pfeil, Navigations-
Icons in der Admin-Seitenleiste) werden dekorativ (aria-hidden="true"); das
Schloss-Symbol der LDAP-Standardzuordnung traegt jetzt einen eigenen Titel
(admin.ldap.fieldMapping.defaultIcon), weil es ohne begleitenden Text pro
Tabellenzeile die ganze Bedeutung allein traegt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
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).
- Remove AD radio-selection block, discovery effect/state, and the
two-step create-then-PATCH-bind flow from GroupFormModal.tsx (D-07):
a local group can no longer be bound to an AD group from this dialog.
- Add locked name field with provenance hint + AD-DN read-only line and
an editable internalName field for imported groups (D-03/D-04); create
state gets a hint linking to the LDAP import area.
- Visible save-error line (never a silent catch{}) that distinguishes a
409 name collision from a generic failure; dialog stays open, inputs
are preserved.
- Add Group.internalName to the page.tsx interface now (Rule 3 — the
modal cannot typecheck without it; Task 2 adds the display-cell usage).
- Add seven new admin.groups i18n keys to de.json/en.json (orphaned
ldapBind.* keys removed in Task 3).
- GroupMembersModal.tsx: chip list of current members with source badge
(MANUAL/LDAP); LDAP-sourced chips carry a disabled remove button with a
"managed via AD sync" tooltip (D-19) instead of an active one; second
section adds manual members via GET /users + POST /groups/:id/members,
already-member candidates shown disabled (upsert on the API is
folgenlos, no special-case needed)
- DeleteGroupDialog.tsx: loads GET /groups/:id/impact and interpolates
memberCount/grantCount into the confirmation text (D-17); deliberately
breaks from the project's silent-delete-failure precedent -- stays open
and shows a visible error on a failed DELETE, since a silent failure
here would leave an admin believing a group (and its grants) is gone
while it still grants access (T-15-24)
- page.tsx: wires both dialogs in, refetches the group list after any
member/delete mutation so member counts and badges stay current
- groups-page.test.tsx: disabled-vs-active remove button by membership
source, delete text shows both numbers, visible error + dialog stays
open on failed delete
- page.tsx: sixth admin route, table (Name/AD-Bindung/Standardgruppe/
Mitglieder/Aktionen), empty state matching AdminUsersPage's noUsers
pattern, optimistic default-group star toggle (PATCH /groups/:id
isDefault) with rollback + visible error div on failure, full refetch
on success since setting one group default unsets all others server-side
(D-13 transaction)
- GroupFormModal.tsx: create/rename dialog; AD binding section reuses
GET /ldap/groups (D-18) with a radio list (D-05: exactly one AD group
per Tessera group) instead of the LDAP page's checkbox multi-select;
visible discoverError/noResults states instead of a silent-empty list
(UI-SPEC backstop); create-with-binding does POST then a second PATCH
since CreateGroupDto only accepts `name`
- groups-page.test.tsx: empty state, populated table, star-toggle
optimistic PATCH + rollback-on-failure