Skip to content

Add findings table with pagination to access control summary#7643

Merged
kruulik merged 4 commits intoaccess-control-summary-dashboardfrom
access-control-findings-table
Mar 12, 2026
Merged

Add findings table with pagination to access control summary#7643
kruulik merged 4 commits intoaccess-control-summary-dashboardfrom
access-control-findings-table

Conversation

@kruulik
Copy link
Contributor

@kruulik kruulik commented Mar 12, 2026

Ticket ENG-2943

Dependency: Requires #7640 to be merged first (base branch)

Description Of Changes

Add a paginated findings table below the summary cards on the access control summary page. The table shows policy violations grouped by policy + control, with sortable columns for violation count and last violation time. Rows are clickable (noop for now, wired up in a follow-up). Also expands mock data to ~37 violation aggregates and 50 violation log entries for more realistic pagination testing.

Code Changes

  • clients/admin-ui/src/features/access-control/summary/FindingsTable.tsx - New component: paginated Ant Table consuming useGetPolicyViolationsQuery, uses useAntPagination with separate URL query keys
  • clients/admin-ui/src/features/access-control/summary/violationsColumns.tsx - Column definitions for the aggregate violations table (Policy, Control, Violations, Last Violation)
  • clients/admin-ui/src/features/access-control/summary/violationLogsColumns.tsx - Column definitions for the activity log table (for use on the Request Log tab in a follow-up)
  • clients/admin-ui/src/mocks/access-control/data.ts - Expanded mock data: ~37 violation aggregates across 8 policies, 50 violation log entries
  • clients/admin-ui/src/pages/data-discovery/access-control/summary/index.tsx - Render <FindingsTable /> below <SummaryCards />

Steps to Confirm

  1. Run NEXT_PUBLIC_MOCK_API=true npm run dev from clients/admin-ui/
  2. Navigate to /data-discovery/access-control/summary
  3. Scroll below summary cards — findings table should show with columns: Policy, Control, Violations, Last Violation
  4. Verify pagination controls work (page size change, page navigation)
  5. Verify sorting on Violations and Last Violation columns
  6. Verify rows show pointer cursor on hover

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:
    • No migrations
  • Documentation:
    • No documentation updates required

@vercel
Copy link
Contributor

vercel bot commented Mar 12, 2026

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

Project Deployment Actions Updated (UTC)
fides-plus-nightly Error Error Mar 12, 2026 7:29pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
fides-privacy-center Ignored Ignored Mar 12, 2026 7:29pm

Request Review

@kruulik kruulik requested a review from lucanovera March 12, 2026 19:24
@kruulik kruulik marked this pull request as ready for review March 12, 2026 19:25
@kruulik kruulik requested a review from a team as a code owner March 12, 2026 19:25
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 12, 2026

Greptile Summary

This PR adds a paginated FindingsTable component to the access control summary page, displaying policy violation aggregates with sortable columns and separate URL pagination state. It also introduces column definitions for a future violation log table and expands mock data to ~37 aggregates and 50 log entries.

The implementation is mostly clean and follows existing patterns (useAntPagination, distinct pageQueryKey/sizeQueryKey), but there is a notable functional issue with column sorting:

  • Client-side sort on server-side paginated data: The sorter callback functions in violationsColumns.tsx perform in-memory sorting, which only reorders the ~10 items on the current page. The PolicyViolationsParams API contract already includes sort_by and sort_direction fields, but they are not wired up in FindingsTable. This means column sort controls produce misleading results and do not sort the full dataset.
  • Non-deterministic mock data: generateViolations() uses Math.random() for violation_count, so the data layout (and thus which items appear on which page) changes on every module re-evaluation / hot-reload, making pagination testing non-reproducible.
  • Single-character variable names: t in FindingsTable.tsx and i in data.ts violate the project's naming convention of using full descriptive names (not 1–2 character identifiers).

Confidence Score: 3/5

  • Safe to merge with caveats — the column sort controls are functionally misleading and should be addressed before this feature is considered complete.
  • The core pagination plumbing is correct and follows established patterns. However, the client-side sorter functions paired with server-side pagination produce incorrect UX (sorting only the current page rather than the full dataset), and the API already has the right parameters to fix this. The remaining issues are style-level (variable names, non-deterministic mock data).
  • violationsColumns.tsx and FindingsTable.tsx need attention for the server-side sorting wiring.

Important Files Changed

Filename Overview
clients/admin-ui/src/features/access-control/summary/FindingsTable.tsx New paginated findings table component; uses useAntPagination correctly with distinct URL query keys, but does not wire up the server-side sort params supported by the API, making the client-side column sorters in violationsColumns.tsx ineffective across pages.
clients/admin-ui/src/features/access-control/summary/violationsColumns.tsx Column definitions for the violation aggregate table; the sorter callback functions perform client-side sort which only applies to the current page when used with server-side pagination, producing incorrect ordering results.
clients/admin-ui/src/features/access-control/summary/violationLogsColumns.tsx Column definitions for the violation activity log table (not yet used in a rendered component); straightforward and clean implementation.
clients/admin-ui/src/mocks/access-control/data.ts Expanded mock data using generator functions; single-character index variables (i) and non-deterministic Math.random() for violation_count means the dataset changes on every reload, making pagination testing non-reproducible.
clients/admin-ui/src/pages/data-discovery/access-control/summary/index.tsx Renders the new FindingsTable below SummaryCards; minor variable rename from startDate/endDate to start/end as a drive-by cleanup.

Last reviewed commit: bed0f93

<Pagination
{...paginationProps}
total={data?.total}
showTotal={(t, range) => `${range[0]}-${range[1]} of ${t} items`}
Copy link
Contributor

Choose a reason for hiding this comment

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

Single-character variable name

t is a 1-character variable name that should use a descriptive full name per the project's naming convention.

Suggested change
showTotal={(t, range) => `${range[0]}-${range[1]} of ${t} items`}
showTotal={(total, range) => `${range[0]}-${range[1]} of ${total} items`}

Rule Used: Use full names for variables, not 1 to 2 character... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +136 to +141
CONTROLS[policy].map((control, i) => ({
policy,
control,
violation_count: Math.floor(Math.random() * 40) + 2,
last_violation: new Date(baseTime - i * 2 * 60 * 60 * 1000).toISOString(),
})),
Copy link
Contributor

Choose a reason for hiding this comment

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

Single-character variable names

i is a 1-character variable name that should use a descriptive full name per the project's naming convention. The same applies to the index variable i at line 191 in generateLogs().

Suggested change
CONTROLS[policy].map((control, i) => ({
policy,
control,
violation_count: Math.floor(Math.random() * 40) + 2,
last_violation: new Date(baseTime - i * 2 * 60 * 60 * 1000).toISOString(),
})),
CONTROLS[policy].map((control, controlIndex) => ({
policy,
control,
violation_count: Math.floor(Math.random() * 40) + 2,
last_violation: new Date(baseTime - controlIndex * 2 * 60 * 60 * 1000).toISOString(),
})),

Also update generateLogs (line 191):

return Array.from({ length: 50 }, (_, logIndex) => ({
  timestamp: new Date(baseTime - logIndex * 45 * 60 * 1000).toISOString(),
  consumer: LOG_CONSUMERS[logIndex % LOG_CONSUMERS.length],
  policy: allPolicies[logIndex % allPolicies.length],
  dataset: LOG_DATASETS[logIndex % LOG_DATASETS.length],
  data_use: LOG_DATA_USES[logIndex % LOG_DATA_USES.length],
}));

Rule Used: Use full names for variables, not 1 to 2 character... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

CONTROLS[policy].map((control, i) => ({
policy,
control,
violation_count: Math.floor(Math.random() * 40) + 2,
Copy link
Contributor

Choose a reason for hiding this comment

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

Non-deterministic mock data from Math.random()

violation_count is randomized via Math.random() on each module evaluation. This means the data (including sort order after .sort()) will be different on every hot-reload, page refresh, or module re-import during development. This makes pagination behavior non-reproducible: a count that was 34 in one session might be 11 in the next, causing items to appear on different pages.

Since the intent is realistic pagination testing, consider using deterministic values (e.g. seeded, or a static formula like (controlIndex + 1) * 3 + policyIndex) so the data is consistent between reloads.

Comment on lines +22 to +34
width: 120,
sorter: (a, b) => a.violation_count - b.violation_count,
},
{
title: "Last violation",
dataIndex: "last_violation",
key: "last_violation",
width: 160,
render: (timestamp: string) =>
formatDistance(new Date(timestamp), new Date(), { addSuffix: true }),
sorter: (a, b) =>
new Date(a.last_violation).getTime() -
new Date(b.last_violation).getTime(),
Copy link
Contributor

Choose a reason for hiding this comment

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

Client-side sort applied to a single page of server-side paginated data

The sorter functions defined here perform client-side sorting, but FindingsTable fetches only one page of data at a time from the server. As a result, clicking a column header will only sort the currently displayed items — not the full dataset of ~37 violations.

For example, if page 1 shows violations with counts [34, 28, 22, 15, 12, 10, 9, 8, 7, 6] and the user sorts ascending, they'll see those same 10 items reordered, but the actual lowest-violation items from pages 2–4 are never surfaced. This gives users a misleading picture of the data ordering.

The API already supports server-side sorting via sort_by and sort_direction params in PolicyViolationsParams (in access-control.slice.ts), but these are not wired up in FindingsTable.

To fix this, the inline sorter functions should be removed (or replaced with sorter: true to keep the sort-arrow UI) and the <Table>'s onChange handler should capture sort events and pass sort_by/sort_direction to useGetPolicyViolationsQuery. A sort state change should also reset the page back to 1.

@kruulik kruulik merged commit bbf6d00 into access-control-summary-dashboard Mar 12, 2026
39 of 42 checks passed
@kruulik kruulik deleted the access-control-findings-table branch March 12, 2026 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant