Gate matrix subject actions at the subject's site scope#97
Open
tgerke wants to merge 1 commit into
Open
Conversation
Site-scoped grants confer nothing at study scope, so gating the lifecycle and break-the-blind menus on study-level permissions hid them from the coordinators and investigators who perform them. Resolve permissions per subject row at the subject's site, matching the FormEntryPage pattern, and pin the endpoint's scoping contract with a test.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found during the docs screenshot work on #96: the subject matrix gated its per-subject actions (lifecycle transitions and break-the-blind) on
usePermissions(studyId)with no site, andeffectivePermissionsdeliberately counts only study-wide grants at study scope. Site-scoped coordinators and investigators — the seeded demo personas, and the usual shape of site staff grants — therefore never saw the menus the permission model intends them to use, while the server would have authorized the same actions.Change
MatrixPage: eachSubjectLifecyclerow now resolves permissions at the subject's site (usePermissions(studyId, subject.siteId)), the same patternFormEntryPagealready uses for signing. React Query caches by(studyId, siteId), so it costs one fetch per site, not per row.queries.test.ts: new test pinning the scoping contract the UI depends on — a site-scopeddata_entrygrant returns[]at study scope andsubject.enroll/data.enterwhen the query names the site. The fixture'smakeUsergains an optionalsiteId, since every existing fixture granted study-wide, which is why this never surfaced.Study-level gating elsewhere on the page (
export.datafor casebook links) is unchanged and correct; a survey of the otherusePermissions(studyId)callers (builder, coding, team, workbench, study page) shows they gate genuinely study-scoped features.Verification
pnpm --filter @edc-core/web typecheckclean.demo-coord(site-scoped) now sees status menus on their site's subjects in both the demo and repeating-groups studies, including Enroll/Screen fail for the screening subject;demo-cra(monitor, nosubject.enroll/data.unblind) sees the full matrix with no menus.