Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

07 — Component Library (RBAC Module)

Module-specific components. All base widgets (cards, lists, chips, dialogs, sheets, menus, skeletons, states) come from 00-shared/03; this file adds the RBAC layer. Every component is derived from schema fields (role.schema.ts, organization-member.schema.ts) and the guard model (rbac.guard.ts).


1. PermissionMatrix (hero component)

  • Purpose: render + edit the full permission catalog for one role (S3).
  • Props: permissions (catalog from GET /rbac/permissions), selected (Set of granted perm strings), onChanged(Set<String>), searchQuery, readOnly, compact.
  • Structure: 26 PermissionGroupSections (grouping table in 06 §3), each with tri-state Checkbox (none/some/all) + Wrap of PermissionChips; optional AppSearchBar (owned by parent); live count AppBadge "{sel} of 95".
  • Behaviour: chip tap → toggle; group checkbox → toggle all; search → filter sections (0-match sections collapse); readOnly → chips render as plain labels with Semantics(label: "granted"); no server calls until save (single PATCH, rbac.service.ts:96).
  • Flutter: stateful widget owning Set<String> selected + Map<String,bool> groupState; sections = ListView.builder children (lazy); chips = FilterChip with visualDensity: compact; RepaintBoundary per section (see 15 §2).
  • Golden: phone/tablet/desktop × light/dark × readOnly/editable.

2. PermissionGroupSection

  • Header row: group label (titleSmall), tri-state Checkbox, "{k}/{n}" counter (labelSmall); body Wrap(spacing:8, runSpacing:8) of chips.
  • Semantics(headers:) on header; tri-state announced.

3. PermissionChip

  • FilterChip-like; label = full permission string (bodySmall, mono feel), selected = primaryContainer/onPrimaryContainer; unselected = surfaceVariant.
  • Tooltip: humanized name (proposed), e.g. payments.reconcile → "Reconcile payments" (i18n key perm.payments.reconcile); falls back to raw string.
  • A11y: Semantics(checked: selected, label: '<perm>').

4. RoleRow

  • AppListTile-based list row: AppAvatar (initials, primaryContainer), title = role name, subtitle = slug (mono) + description ellipsized, trailing = AppBadge "System"/"{n} perms" + AppMenu (Edit/Delete for custom; disabled for system).
  • Sort: priority desc (rbac.service.ts:76) — provided pre-sorted by parent.

5. RoleBadge / SystemRoleBadge

  • AppBadge variants: System (outlined, tooltip "Locked — can't be edited"), Custom, and permission-count badge "{n} perms". System badge always on isSystem:true roles (role.schema.ts:78-79).

6. MemberTile

  • AppListTile: AppAvatar 48 (photo/initials from merged user profile, OQ-R7), title displayName (fallback userId mono), subtitle = email + "Joined {date}" (organization-member.schema.ts:30-31), trailing = role chips + AppMenu (Edit roles / Remove — admin only).
  • Role chips = read-only AppChips (tap no-op, tooltip "Managed in role editor"); unknown slug renders raw.

7. MemberStatusBadge

  • AppBadge from MemberStatus (organization-member.schema.ts:7-11): active → success (secondary), invitedtertiary (info), suspendederror. Render-only: server produces only active today (OQ-R3).

8. RolePickerChips

  • Multi-select FilterChip wrap from GET /rbac/roles (priority order); used in S5 (add/edit member). Props: roles, selected, onChanged. System roles get a tiny lock glyph (still selectable — e.g. assigning teacher).

9. UserSearchPicker

  • AppSearchBar-driven result list (user.read), AppListTile rows (avatar, name, email); single-select with check; props: onPicked(User), preselected?.

10. AuditRow / AuditFilterBar

  • AuditRow: action (labelLarge), entityType · actorId (mono bodySmall), timestamp (relative, bodySmall); tap → copies requestId (proposed).
  • AuditFilterBar: three AppDropdowns (action, entityType, actorId) + clear button; map to audit.controller.ts:20-25 query params; RBAC presets (proposed) (OQ-R8).

11. PermissionSummary (read-mode group list)

  • Compact read-only block for S2: group label + granted PermissionChips (or "None in this group"). Reuses PermissionGroupSection in readOnly.

12. Shared-component reuse map

NeedShared component (00-shared/03)
LoadingAppSkeleton (list/card), AppProgress
Empty / error / offlineAppEmptyState, AppErrorState, AppOfflineBanner
FeedbackAppSnackbar, AppBanner (system-role info, 409 conflict)
InputsAppTextField, AppDropdown, AppSearchBar, AppCheckbox
DisplayAppCard, AppAvatar, AppBadge, AppSectionHeader, AppInfoRow
ActionsAppFAB (Roles/Members lists), AppButton, AppDialog (delete/self-removal confirm), AppBottomSheet (S5), AppMenu (row actions)