Adding a secretary meant deciding all 17 permission resources in the same
dialog. The full-height capture showed the form running past 1300px with the
save button below 16 accordions, and the dynamic registry makes that worse: every
page added in future lengthens this one modal.
The add/edit modal now carries only doctors, profile and address, and fits on
screen with its footer visible. Permissions move to SecretaryPermissionsModal,
reachable from a row action and opened automatically right after a successful
add, since a new secretary starts on the role defaults and the owner usually
wants to set them.
Neither create nor update sends permissions any more — the backend seeds the role
defaults on create, and the permissions modal owns the writes, fanning out over
every link row so a secretary shared across doctors stays consistent.
PermissionAccordions moves to components/ui as a shared component. Sections now
start collapsed with a granted/total badge on each header, so the panel opens at
a fixed height and still says which sections are on.
Two design-system slips caught by re-screenshotting rather than by the audit:
- a text button as a third row action pushed the name column out of the table, so
the desktop row uses an icon with a title and the mobile card keeps the label
- .btn.secondary is not defined in styles.css (variants are primary/ghost/soft/
danger/accent), so it renders as a bare .btn. Used ghost here. 25 other files
have the same dead class; left alone as a separate sweep.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The three hardcoded resource lists in the admin panel are gone. MySecretariesPage,
SecretariesPage and DoctorPermissionsModal now render from
GET /api/v1/permission-catalog, so a resource added to the backend registry shows
up in all of them with no frontend change. Each has a test that proves exactly
that by adding a resource to the mock and asserting it renders.
SecretaryPermissions was an interface with a field per resource, which made
"dynamic" impossible in TypeScript — every new resource would have been a compile
error. It is now an open map. Only two files consumed it.
The borrowed gates are corrected:
- five resource pages moved off appointment_settings onto their own 'resources'
- treatment-cases moved off appointments onto 'treatment'
- service-categories moved onto 'services', which is what ServiceCatalogController
actually manages (categories, item groups, service relations) — not resources
TreatmentCaseController had no permission gate at all, only IS_AUTHENTICATED_FULLY,
so any secretary could read and edit treatment cases. All seven of its actions are
now gated on treatment view/update.
ResourcePermissionTrait takes the resource from an overridable method instead of
hardcoding appointment_settings. HolidayController overrides it back, since the
holidays page really is appointment settings. The booking gate keeps its
appointments.view fallback so a secretary who may book is not blocked by a
resource-config permission.
Defaults were picked to preserve today's effective access, so no role gains or
loses a page from this move.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>