feat(forms): assign compliance forms to owners of a specific type#17787
feat(forms): assign compliance forms to owners of a specific type#17787acrylJonny wants to merge 5 commits into
Conversation
Compliance forms can already be assigned to entity owners, but every owner
gets every form regardless of ownership type. Teams that distinguish
technical, business, data-steward (etc.) owners on the same entity have no
way to route a given form to the right cohort.
This PR adds an optional `ownershipTypes` list to `FormActorAssignment` that
narrows owner-based assignment to owners whose ownership type matches the
form's filter. Empty / unset preserves today's behaviour.
Stack:
- Model: `FormActorAssignment.ownershipTypes: optional array[Urn]`,
searchable + relationship-mapped to the `ownershipType` entity.
- Java: `OwnershipUtils.isOwnerOfEntityWithType` mirrors
`OwnerServiceUtils.isOwnerEqual`'s legacy-enum fallback so owners persisted
with only the deprecated `Owner.type` enum (no `typeUrn`) still match.
`FormService.isFormAssignedToUser` calls into it; tests cover both
`typeUrn`-only and enum-only paths.
- Patch builder: `FormInfoPatchBuilder.{add,remove}AssignedOwnershipType`,
and the existing user/group add/remove paths are folded onto a shared
helper that takes the field name (removes copy-paste error in the original
`setAssignedUsers`/`setAssignedGroups` error message).
- GraphQL: `FormActorAssignment.ownershipTypes` (typed), plus
`FormActorAssignmentInput.ownershipTypes` (create-form) and
`FormActorAssignmentUpdateInput.ownershipTypes{ToAdd,ToRemove}` (update),
wired through `FormMapper`, `FormUtils`, `UpdateFormResolver`, and the
loadable-type batch resolver in `GmsGraphQLEngine`.
- Frontend: `useIsUserAssigned` reads `formAssociation.form.info.actors.ownershipTypes`
and filters owners accordingly; `formFields` fragment fetches the new
`ownershipTypes { urn type info { name description } }` block.
- Python SDK: `Actors.ownership_types` on the YAML recipe model (so the
field documented under `actors:` is actually accepted), plus
`FormPatchBuilder.{add,remove}_assigned_ownership_type`.
- Docs: `forms.md` + compliance-forms guides document the new field and the
built-in ownership-type URNs.
Tests:
- `OwnershipUtilsTest` — covers no-filter, single-type, multi-type, no-match,
group-membership, and the enum-only legacy-owner fallback.
- `FormServiceOwnershipTest` — end-to-end test that
`isFormAssignedToUser` returns the expected result across all those
combinations against mocked `FormInfo` + `Ownership` aspects.
- `FormInfo/__tests__/utils.test.ts` — covers the `useIsUserAssigned`
helper for typed and untyped ownership filtering.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Accept Maybe<Owner[]> (Owner[] | null | undefined) in isAssignedToForm and isOwnerWithType to match the GraphQL-generated entityData.ownership shape. Without this the FE type-check fails on the call site that passes entityData?.ownership?.owners. - Replace the SaaS-only utils.test.ts (which imported non-exported helpers and a missing mocks module) with a focused useIsUserAssigned.test.ts that exercises only the new behavior: isAssignedToMe, owner-assignment, and ownership-type filtering. Mocks now satisfy the required Owner.associatedUrn field. Fixes the datahub-web-react-lint CI job on #17783. Co-authored-by: Cursor <cursoragent@cursor.com>
|
✅ Meticulous spotted 0 visual differences across 1554 screens tested: view results. Meticulous evaluated ~10 hours of user flows against your PR. Expected differences? Click here. Last updated for commit |
Connector Tests ResultsAll connector tests passed for commit To skip connector tests, add the Autogenerated by the connector-tests CI pipeline. |
❌ 1 Tests Failed:
View the top 1 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
Bundle ReportChanges will increase total bundle size by 343 bytes (0.0%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: datahub-react-web-esmAssets Changed:
Files in
|
Motivation
Compliance forms can already be assigned to entity owners, but every owner gets every form regardless of ownership type. Teams that distinguish technical, business, data steward (etc.) owners on the same entity have no way to route a given form to the right cohort.
This PR adds an optional
ownershipTypeslist onFormActorAssignmentthat narrows owner-based assignment to owners whose ownership type matches the form's filter. Empty / unset preserves today's behaviour.What changed
FormActorAssignment.ownershipTypes: optional array[Urn]— searchable, relationship-mapped to theownershipTypeentity.OwnershipUtils.isOwnerOfEntityWithTypemirrorsOwnerServiceUtils.isOwnerEqual's legacy-enum fallback so owners persisted with only the deprecatedOwner.typeenum (notypeUrn) still match.FormService.isFormAssignedToUsercalls into it; tests cover bothtypeUrn-only and enum-only paths.FormInfoPatchBuilder.{add,remove}AssignedOwnershipType. Folds the existing user/group add/remove paths onto a shared helper (also removes the copy-paste error message bug in the SaaS-sidesetAssignedGroups).FormActorAssignment.ownershipTypes(typed),FormActorAssignmentInput.ownershipTypes(create-form),FormActorAssignmentUpdateInput.ownershipTypes{ToAdd,ToRemove}(update). Wired throughFormMapper,FormUtils,UpdateFormResolver, and the loadable-type batch resolver inGmsGraphQLEngine.useIsUserAssignedreadsformAssociation.form.info.actors.ownershipTypesand filters owners;formFieldsfragment fetches the new block.Actors.ownership_typeson the YAML recipe model (so the field documented underactors:is actually accepted by Pydantic), plusFormPatchBuilder.{add,remove}_assigned_ownership_type.forms.md+ compliance-forms guides document the new field and the built-in ownership-type URNs.Behaviour
A user is treated as assigned only if (a) they're explicitly named, or (b) they own the entity with one of the listed ownership types. Empty / unset list preserves the existing "any owner is assigned" behaviour.
Tests
OwnershipUtilsTest— covers no-filter, single-type, multi-type, no-match, group-membership, and the enum-only legacy-owner fallback.FormServiceOwnershipTest— end-to-end test thatisFormAssignedToUserreturns the expected result across all of those combinations against mockedFormInfo+Ownershipaspects.FormInfo/__tests__/utils.test.ts— coversuseIsUserAssignedfor typed and untyped ownership filtering.Checklist
Notes
Originally proposed as #7076 (closed); this is a clean revival rebased against current
master.Made with Cursor