Skip to content

Access policies controls UI + new description field#7918

Open
lucanovera wants to merge 15 commits intomainfrom
ENG-2961-FE-Policy-groups-based-on-Control-adding-editing
Open

Access policies controls UI + new description field#7918
lucanovera wants to merge 15 commits intomainfrom
ENG-2961-FE-Policy-groups-based-on-Control-adding-editing

Conversation

@lucanovera
Copy link
Copy Markdown
Contributor

@lucanovera lucanovera commented Apr 14, 2026

Ticket ENG-2961

Description Of Changes

Adds a dedicated Controls management UI for creating, editing, and deleting controls (regulatory framework groupings for access policies). Controls now have a description field. The key is auto-generated from the label on the backend using get_key_from_data.

The backend CRUD endpoints (POST/PATCH/DELETE/GET single for /controls) are scaffolded in the fidesplus repo in a companion PR — this PR covers the fides-side changes (model, migration, and all frontend work).

Code Changes

  • Added nullable description column to Control ORM model and alembic migration (d6e7f8a9b0c1)
  • Added controls list page (/access-policies/controls) using Ant Design List component with List.Item.Meta
  • Added control create page (/access-policies/controls/new) and edit page (/access-policies/controls/[controlKey]) with shared ControlForm component (Name + Description textarea)
  • Added RTK Query endpoints: getControl (dedicated GET), createControl, updateControl, deleteControl
  • Added route constants: CONTROLS_ROUTE, CONTROLS_NEW_ROUTE, CONTROLS_EDIT_ROUTE
  • Updated access policies page: "Manage controls" button links to controls page; policy settings button changed to icon-only with tooltip
  • Added MSW mock handlers for all control CRUD endpoints including 409 conflict/in-use error handling
  • Delete confirmation uses useModal().confirm() with okButtonProps: { danger: true }
  • Navigation uses NextLink; submit buttons show loading state during mutations

Steps to Confirm

Use npm run dev:mock locally to test

  1. Navigate to Access Policies page → click "Manage controls" → verify it lands on /access-policies/controls list page
  2. Click "New control" → fill in Name and Description → submit → verify redirect to list with new control visible
  3. Click "Edit" on a control → update name/description → save → verify redirect to list with changes reflected
  4. Click "Delete" on a control → verify danger-styled confirmation modal → confirm → verify control removed
  5. Verify the settings icon button on access policies page still opens the policy settings modal
  6. Run npx tsc --noEmit in clients/admin-ui/ — should pass with no errors

Pre-Merge Checklist

  • Issue requirements met
  • All CI pipelines succeeded
  • CHANGELOG.md updated
    • Add a db-migration This indicates that a change includes a database migration label to the entry if your change includes a DB migration
    • Add a high-risk This issue suggests changes that have a high-probability of breaking existing code label to the entry if your change includes a high-risk change (i.e. potential for performance impact or unexpected regression) that should be flagged
    • Updates unreleased work already in Changelog, no new entry necessary
  • UX feedback:
    • All UX related changes have been reviewed by a designer
    • No UX review needed
  • Followup issues:
    • Followup issues created
    • No followup issues
  • Database migrations:
    • Ensure that your downrev is up to date with the latest revision on main
    • Ensure that your downgrade() migration is correct and works
      • If a downgrade migration is not possible for this change, please call this out in the PR description!
    • No migrations
  • Documentation:
    • Documentation complete, PR opened in fidesdocs
    • Documentation issue created in fidesdocs
    • If there are any new client scopes created as part of the pull request, remember to update public-facing documentation that references our scope registry
    • No documentation updates required

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
fides-plus-nightly Ready Ready Preview, Comment Apr 15, 2026 7:03pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
fides-privacy-center Ignored Ignored Apr 15, 2026 7:03pm

Request Review

@lucanovera lucanovera marked this pull request as ready for review April 14, 2026 19:57
@lucanovera lucanovera requested review from a team as code owners April 14, 2026 19:57
@lucanovera lucanovera requested review from erosselli, kruulik, speaker-ender and thabofletcher and removed request for a team, erosselli and speaker-ender April 14, 2026 19:57
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 14, 2026

Title Lines Statements Branches Functions
admin-ui Coverage: 8%
6.09% (2666/43722) 5.21% (1293/24773) 4.18% (542/12939)
fides-js Coverage: 78%
78.98% (1962/2484) 65.55% (1214/1852) 72.57% (336/463)
privacy-center Coverage: 88%
85.97% (331/385) 81.36% (179/220) 78.87% (56/71)

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.25%. Comparing base (b3048ee) to head (ff24db4).
⚠️ Report is 4 commits behind head on main.

❌ Your project check has failed because the head coverage (83.25%) is below the target coverage (85.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7918      +/-   ##
==========================================
- Coverage   85.06%   83.25%   -1.81%     
==========================================
  Files         629      629              
  Lines       40859    40860       +1     
  Branches     4748     4748              
==========================================
- Hits        34757    34020     -737     
- Misses       5029     5641     +612     
- Partials     1073     1199     +126     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

claude[bot]

This comment was marked as outdated.

@lucanovera lucanovera added db-migration This indicates that a change includes a database migration labels Apr 15, 2026
@lucanovera
Copy link
Copy Markdown
Contributor Author

/code-review re-review after changes

Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review: Controls Management UI (#7918)

Overall this is a clean, well-structured feature. The page/component decomposition is sensible, the RTK Query endpoints follow existing patterns, the MSW mocks are thorough, and the UX flow (list → create → edit → delete with confirmation) is cohesive. The tag invalidation strategy (deleteControl invalidating both "Controls" and "Access Policies") is a nice touch.

Issues to address before merge

Migration chain (must fix)
The down_revision = "b3c8d5e7f2a1" in the new migration needs to be verified against the actual HEAD revision on main before this lands. The related checklist items are still unchecked. Additionally, the xx_ filename prefix is non-standard for this repo — migrations typically use a revision-hash prefix; xx_ may cause Alembic sort/discovery issues.

router.query type safety (minor but real)
router.query.controlKey is string | string[] | undefined in Next.js. The as string cast in [controlKey].tsx bypasses this silently. A simple Array.isArray guard (see inline) makes it safe. The same pattern appears in the MSW handlers for req.params.key.

MSW PATCH mock semantics (minor)
The PATCH handler overwrites label and description from the body even when they are undefined, which would corrupt mock state for future contributors who send partial PATCH bodies. In practice today it's fine, but the mock semantics diverge from a real PATCH. See inline comment.

Nits / low-priority

  • useDeleteControlMutation loading state isn't captured in the list page, so nothing prevents a double-click during deletion. Low impact since RTK Query deduplicates, but the UX can stutter.
  • ControlForm uses initialValues to populate the edit form. Ant Design doesn't re-apply initialValues on prop changes — this is safe for the current page-per-route setup, but worth a comment in case the form gets reused elsewhere.
  • The "Manage controls" button on the access policies page is unconditionally rendered when hasPolicies is true, with no feature flag. If controls is being rolled out progressively, it may need a flag guard consistent with alphaPrivacyDocUpload.

The .fides/db_dataset.yml addition and the description field on the Control type/model are straightforward and correct.


🔬 Codegraph: connected (46725 nodes)

💡 Write /code-review in a comment to re-run this review.

Comment thread clients/admin-ui/src/mocks/access-policies/handlers.ts
title: "Delete control",
content: (
<span className="text-gray-500">
Are you sure you want to delete the control &quot;{control.label}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clients/admin-ui/src/pages/access-policies/controls/index.tsx:31

useDeleteControlMutation is destructured without capturing the loading state:

const [deleteControl] = useDeleteControlMutation();

Nothing prevents a second delete click while the first is in-flight. Consider capturing isLoading and disabling the Delete button inside the confirm onOk, or at least preventing double-submission. RTK Query will deduplicate, but the UX is still jarring.

const [form] = Form.useForm<ControlFormValues>();
const isEditing = !!control;

const initialValues = useMemo<ControlFormValues>(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clients/admin-ui/src/features/access-policies/ControlForm.tsx:28

When control changes (e.g. if the edit page ever remounts with a different key without unmounting), initialValues will update via useMemo but Ant Design's Form ignores initialValues after the first render. If this form is ever reused in a context where the control prop can change in-place, you'll need to call form.setFieldsValue(initialValues) inside a useEffect. Not a problem for the current page-per-route setup, but worth a comment or defensive useEffect.

Copy link
Copy Markdown
Contributor

@kruulik kruulik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No comments - code looks great! Tested it out locally with no issues.

Copy link
Copy Markdown
Contributor

@thabofletcher thabofletcher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

db-migration This indicates that a change includes a database migration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants