Skip to content

Audit Log Filtering - #2200

Closed
CodyWMitchell wants to merge 3 commits into
RedHatInsights:masterfrom
CodyWMitchell:audit-log-filtering
Closed

Audit Log Filtering#2200
CodyWMitchell wants to merge 3 commits into
RedHatInsights:masterfrom
CodyWMitchell:audit-log-filtering

Conversation

@CodyWMitchell

@CodyWMitchell CodyWMitchell commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

What and why

RHCLOUD-28101

  • Add filtering to Audit Log table
  • Filtering in API currently in Stage/QA (RHCLOUD-45395)

Screenshots

Screen Recording 2026-03-17 at 1 23 21 AM


Anything non-obvious reviewers should know?


Attention needed

  • (Optional) QE: notable impact on test coverage or OUIA IDs changed
  • (Optional) UX: end-user UX modified, designs may need sign-off

Summary by CodeRabbit

  • New Features

    • Added audit log viewer with table display and pagination.
    • Added filtering capabilities to search audit logs by requester, resource type, and action.
  • Documentation

    • Updated changelog with version 1.0.0 release details.
    • Added comprehensive audit log feature documentation.

@CodyWMitchell
CodyWMitchell requested a review from a team as a code owner March 17, 2026 05:29
@coderabbitai

coderabbitai Bot commented Mar 17, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR introduces a comprehensive audit logging feature with new API integration, React components for displaying and filtering audit logs with server-side pagination, internationalization support, and extensive test coverage via Storybook stories across both v1 and v2 code paths.

Changes

Cohort / File(s) Summary
Documentation & Translations
CHANGELOG.md, src/Messages.js
Added version 1.0.0 changelog entry and six new message descriptors (auditLogFilterByRequester, auditLogResourceLabel, auditLogActionLabel, userCapitalized, add, create) for audit log UI labels and filters.
Audit API Clients
src/data/api/audit.ts, src/v2/data/api/audit.ts, src/data/api/index.ts
Created new audit API client modules with TypeScript types, endpoint definitions, factory functions, and re-exports. Central index consolidates API surface for audit logs and other services.
Audit Query Hooks
src/data/queries/audit.ts, src/v2/data/queries/audit.ts
Introduced React-Query hooks (useAuditLogsQuery) and query key structures for fetching audit logs with pagination and filtering support.
Audit Log Components
src/features/audit-log/AuditLog.tsx, src/features/audit-log/AuditLogTable.tsx, src/v2/features/audit-log/AuditLog.tsx
Added new React components: AuditLog page component with server-side data fetching and filters; AuditLogTable presentational component with columns for date, requester, action, resource, description; v2 version extends with client-side filter UI and enum-driven options.
Stories & Test Fixtures
src/features/audit-log/AuditLogTable.stories.tsx, src/user-journeys/access-management/AuditLog.stories.tsx, src/v2/data/mocks/audit.fixtures.ts, src/v2/data/mocks/audit.handlers.ts
Added Storybook stories with multiple states (Default, Loading, Empty, Error, Pagination) and user journey tests for filtering; created audit log fixtures with seven sample entries and mock handler with filtering support for principal_username, resource_type, and action.
Documentation
src/v2/features/audit-log/README.md
Updated README documenting route changes, API/query paths, data layer organization, components, columns, and new filter configuration with parameter mappings.

Sequence Diagram

sequenceDiagram
    participant User
    participant Component as Audit Log Component
    participant Query as React-Query
    participant API as API Client
    participant Server as Backend API
    
    User->>Component: Interact (filter, paginate)
    Component->>Component: Update tableState with filters/pagination
    Component->>Query: Call useAuditLogsQuery(params)
    Query->>API: Call auditApi.getAuditlogs(params)
    API->>Server: GET /api/audit-logs?limit=20&offset=0&filters...
    Server->>API: Return AuditLogPagination
    API->>Query: response.data
    Query->>Component: Provide paginated results + metadata
    Component->>Component: Map API entries to table rows
    Component->>User: Render filtered audit log table
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hop, hop, through the audit logs we go,
Filtering requester, resource, action—watch them flow!
API clients dance with React-Query's grace,
Pagination and stories keep pace in this space.
A comprehensive feature, polished and bright,
The audit log shines with its tabular light! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Audit Log Filtering' accurately summarizes the main change—adding filtering capabilities to the audit log feature—and is clear and specific.
Description check ✅ Passed The description provides the linked issue (RHCLOUD-28101), explains the problem (adding filtering to Audit Log table), includes a screenshot, and acknowledges API-side filtering status, but lacks details on trade-offs or non-obvious implementation notes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can customize the tone of the review comments and chat replies.

Configure the tone_instructions setting to customize the tone of the review comments and chat replies. For example, you can set the tone to Act like a strict teacher, Act like a pirate and more.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/v2/data/queries/audit.ts (1)

19-21: ⚠️ Potential issue | 🔴 Critical

Use the repo's RBAC-client cast workaround for auditApi.getAuditlogs.

Line 20 directly invokes auditApi.getAuditlogs(params) without the required (as any) cast. Per src/docs/APIClientPatterns.mdx, the @redhat-cloud-services/rbac-client library has broken TypeScript types and requires the (api.method as any) pattern to prevent silent runtime failures.

🔧 Suggested fix
-        const response = await auditApi.getAuditlogs(params);
+        const response = await (auditApi.getAuditlogs as any)(params);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/v2/data/queries/audit.ts` around lines 19 - 21, The call inside the async
queryFn to auditApi.getAuditlogs should use the repo's RBAC-client cast
workaround to avoid broken TypeScript types; replace the direct invocation
auditApi.getAuditlogs(params) with the casted form (auditApi.getAuditlogs as
any)(params) (i.e., cast the method to any before calling) so that queryFn
returns response.data safely; update the invocation within the queryFn block
where auditApi.getAuditlogs is called.
🧹 Nitpick comments (1)
src/user-journeys/access-management/AuditLog.stories.tsx (1)

66-68: The action filter still is not exercised in this journey.

The docs table now advertises requester/resource/action filtering, but the new play coverage only hits requester and resource. Please add a third story for the action select so the last new control cannot regress silently.

Also applies to: 249-368

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/user-journeys/access-management/AuditLog.stories.tsx` around lines 66 -
68, The docs table claims filtering by action but the existing Storybook stories
only exercise requester and resource; add a new story in AuditLog.stories.tsx
(e.g., AuditLogActionFilter or AuditLog_Play_Action) that renders the same
AuditLog component and in its play function selects the action <select> control
and verifies the filter behavior (mirror how the existing
AuditLog_Play_Requester and AuditLog_Play_Resource stories operate), using the
same query selectors/assertions to choose an action option and assert results
update; ensure the new story name is exported so Storybook picks it up and
follow the same test utilities and imports used by the other play functions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CHANGELOG.md`:
- Around line 6-18: Update the CHANGELOG.md entries that link to the fork by
replacing the username segment "CodyWMitchell" with the upstream
"RedHatInsights" in the commit and issue URLs (e.g., the links in the shown
entries referencing commits like 9442e25, 3c1436a, 0ba659a, etc.); regenerate or
search/replace all other occurrences (also apply the same fix to the entries
noted at lines 196-198) so published release notes point to
RedHatInsights/insights-rbac-ui instead of the fork.
- Line 4: Several release subsection headings are using "###" (for example the
"### Bug Fixes" heading) which causes a jump from "#" to "###"; update these
headings to "##" so they are promoted by one level. Search for subsection
headings that begin with "###" in the changelog (e.g., "### Bug Fixes" and the
other similar subsection headings flagged in the review) and replace the leading
"###" with "##" consistently.

In `@src/data/queries/audit.ts`:
- Around line 19-20: The hook's queryFn is calling the generated RBAC client
method directly (auditApi.getAuditlogs(params)), which must be invoked using the
documented cast pattern to avoid runtime failures; update the call inside
queryFn (in this file's audit query hook) to cast the method before invoking it
(i.e., use the (auditApi.getAuditlogs as any)(...) pattern) so the RBAC client
method is called via the documented (api.method as any) call pattern.

In `@src/features/audit-log/AuditLog.tsx`:
- Around line 41-47: The table is only wired for pagination: update the
useTableState call in AuditLog.tsx (the const tableState = useTableState<typeof
columns, AuditLogRow>...) to include filter support and then pass the filter
props into TableView; specifically ensure you expose filterConfig, filters, and
onFiltersChange from tableState (or provide them via the same state hook) and
add filterConfig={...}, filters={tableState.filters}, and
onFiltersChange={tableState.setFilters} (or the appropriate handlers) to the
TableView component so the new filter UI is actually enabled.
- Line 38: The file currently only has a default export for the page component;
add a named export for the component symbol (AuditLog) so the page/container is
exported both as default and as a named export; update the export lines so that
the React component declaration remains (const AuditLog: React.FC = () => { ...
}) and you add/export the named symbol (export { AuditLog };) while leaving the
default export in place—also apply the same named-export change for the other
page component instance referenced around the second occurrence (the one at the
later export on line ~115).
- Around line 49-55: The queryParams currently sort by id ascending (orderBy:
'id') which yields oldest-first; change the audit feed to sort newest-first
before paginating by updating the queryParams in AuditLog.tsx (the
GetAuditlogsParams object constructed in the useMemo) to request descending id
order (e.g., use an API-supported descending spec such as orderBy: 'id:desc' or
add an orderDirection: 'desc' / order: 'desc' field depending on the backend
contract) so pages return newest entries first and pagination remains stable.

In `@src/features/audit-log/AuditLogTable.stories.tsx`:
- Around line 189-209: The test assertions look for exact strings "Audit action
6" and "Audit action 21" but buildMockEntriesForPagination renders entries like
"Audit action N: ...", so update the expectations in AuditLogTable.stories.tsx
to match the actual mock text (e.g., use canvas.getByText with a regex or
substring that includes the colon and following text such as /Audit action 6:/
and /Audit action 21:/, or assert via contains/startsWith) for the initial page
check, the post-pagination check, and the absence check (canvas.queryByText
should use a matching pattern for "Audit action 6:" to confirm it's not
present).
- Around line 162-168: The story export named "Error" shadows the global Error
constructor; rename the export (e.g., ErrorState or ErrorStory) wherever it's
declared (export const Error: Story) and update any references to that story
export (imports/usages within this file or Storybook configs) so the new
identifier is used instead, ensuring the Story type annotation remains (e.g.,
export const ErrorState: Story = { args: { ... } }).

---

Outside diff comments:
In `@src/v2/data/queries/audit.ts`:
- Around line 19-21: The call inside the async queryFn to auditApi.getAuditlogs
should use the repo's RBAC-client cast workaround to avoid broken TypeScript
types; replace the direct invocation auditApi.getAuditlogs(params) with the
casted form (auditApi.getAuditlogs as any)(params) (i.e., cast the method to any
before calling) so that queryFn returns response.data safely; update the
invocation within the queryFn block where auditApi.getAuditlogs is called.

---

Nitpick comments:
In `@src/user-journeys/access-management/AuditLog.stories.tsx`:
- Around line 66-68: The docs table claims filtering by action but the existing
Storybook stories only exercise requester and resource; add a new story in
AuditLog.stories.tsx (e.g., AuditLogActionFilter or AuditLog_Play_Action) that
renders the same AuditLog component and in its play function selects the action
<select> control and verifies the filter behavior (mirror how the existing
AuditLog_Play_Requester and AuditLog_Play_Resource stories operate), using the
same query selectors/assertions to choose an action option and assert results
update; ensure the new story name is exported so Storybook picks it up and
follow the same test utilities and imports used by the other play functions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8bef961b-73a4-4a7e-8c73-d85090fded90

📥 Commits

Reviewing files that changed from the base of the PR and between 63e51a5 and f714f86.

📒 Files selected for processing (15)
  • CHANGELOG.md
  • src/Messages.js
  • src/data/api/audit.ts
  • src/data/api/index.ts
  • src/data/queries/audit.ts
  • src/features/audit-log/AuditLog.tsx
  • src/features/audit-log/AuditLogTable.stories.tsx
  • src/features/audit-log/AuditLogTable.tsx
  • src/user-journeys/access-management/AuditLog.stories.tsx
  • src/v2/data/api/audit.ts
  • src/v2/data/mocks/audit.fixtures.ts
  • src/v2/data/mocks/audit.handlers.ts
  • src/v2/data/queries/audit.ts
  • src/v2/features/audit-log/AuditLog.tsx
  • src/v2/features/audit-log/README.md

Comment thread CHANGELOG.md
# 1.0.0 (2026-03-12)


### Bug Fixes

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Promote these section headings by one level.

The new release block jumps from # straight to ###, which is why markdownlint is flagging MD001 here. Use ## for these section headings.

Also applies to: 194-194, 321-321, 326-326, 335-335

🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 4-4: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CHANGELOG.md` at line 4, Several release subsection headings are using "###"
(for example the "### Bug Fixes" heading) which causes a jump from "#" to "###";
update these headings to "##" so they are promoted by one level. Search for
subsection headings that begin with "###" in the changelog (e.g., "### Bug
Fixes" and the other similar subsection headings flagged in the review) and
replace the leading "###" with "##" consistently.

Comment thread CHANGELOG.md
Comment on lines +6 to +18
* add sast tasks ([#1787](https://github.com/CodyWMitchell/insights-rbac-ui/issues/1787)) ([9442e25](https://github.com/CodyWMitchell/insights-rbac-ui/commit/9442e2568bbd2536885bfbc4e71a7c9cb772a3ab))
* **addGroup:** incorporate pf6 to branch ([3c1436a](https://github.com/CodyWMitchell/insights-rbac-ui/commit/3c1436a48f1750170a2a2065c595be5b18e30105))
* **AddGroupMembers:** restored filtering capabilities ([0ba659a](https://github.com/CodyWMitchell/insights-rbac-ui/commit/0ba659a6a5c8f7f3120cdc13716340bb62da6987))
* **AddGroupWizard:** ensure service accounts are properly added ([6393cd6](https://github.com/CodyWMitchell/insights-rbac-ui/commit/6393cd650b7a03eba4aaa2f34962e5ac224b9ff2))
* **AddGroupWizard:** fix lint ([61fd6e3](https://github.com/CodyWMitchell/insights-rbac-ui/commit/61fd6e3b75a19ab82168bbece5e5b436df12c0aa))
* address CodeRabbit review feedback ([6c81602](https://github.com/CodyWMitchell/insights-rbac-ui/commit/6c81602a47129f6975ba3fa7090eba9359129c3b))
* address console.warns ([c6d342d](https://github.com/CodyWMitchell/insights-rbac-ui/commit/c6d342d3ab2cc9a328294964b68bfcc479853755))
* address remaining CodeRabbit review findings ([ad74c06](https://github.com/CodyWMitchell/insights-rbac-ui/commit/ad74c06477f99b136e5dea44be502cbbc13d7469))
* address skipped Storybook tests ([8d84829](https://github.com/CodyWMitchell/insights-rbac-ui/commit/8d848294883b95a8fb9324c0524a84496391e4b6))
* **admin-group:** when we don't have admin group do not break ([#1765](https://github.com/CodyWMitchell/insights-rbac-ui/issues/1765)) ([881e1da](https://github.com/CodyWMitchell/insights-rbac-ui/commit/881e1dad988d8e624a7eb4f245ffa1e2b1a5cd66))
* allow users to see the full list of permissions for their own profile ([#1858](https://github.com/CodyWMitchell/insights-rbac-ui/issues/1858)) ([0d0d4de](https://github.com/CodyWMitchell/insights-rbac-ui/commit/0d0d4de06a05e54e5cca1b6597b176b9ff669bd1))
* **api-arg:** js clients has broken arguments so we have to use list of args ([#1844](https://github.com/CodyWMitchell/insights-rbac-ui/issues/1844)) ([e3f2d4a](https://github.com/CodyWMitchell/insights-rbac-ui/commit/e3f2d4a02b78c869bd1dab30048f9f4e4402881d))
* attempt at fixing issue with user access roles not seeing what they should in rbac UI ([f1c44d1](https://github.com/CodyWMitchell/insights-rbac-ui/commit/f1c44d1ae82713ba11f4dc485f5de15101f1e540))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Regenerate this entry against the upstream repo.

These new changelog links point at CodyWMitchell/insights-rbac-ui instead of RedHatInsights/insights-rbac-ui, so the published release notes will send readers to fork-specific issue and commit pages.

Also applies to: 196-198

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CHANGELOG.md` around lines 6 - 18, Update the CHANGELOG.md entries that link
to the fork by replacing the username segment "CodyWMitchell" with the upstream
"RedHatInsights" in the commit and issue URLs (e.g., the links in the shown
entries referencing commits like 9442e25, 3c1436a, 0ba659a, etc.); regenerate or
search/replace all other occurrences (also apply the same fix to the entries
noted at lines 196-198) so published release notes point to
RedHatInsights/insights-rbac-ui instead of the fork.

Comment thread src/data/queries/audit.ts
Comment on lines +19 to +20
queryFn: async () => {
const response = await auditApi.getAuditlogs(params);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd 'APIClientPatterns\.mdx$' -x sed -n '1,200p' {}
rg -nP --type=ts --type=tsx '\.\s*getAuditlogs\s*\(' src
rg -nP --type=ts --type=tsx '\(\s*[^)]*\.getAuditlogs\s+as any\s*\)\s*\(' src

Repository: RedHatInsights/insights-rbac-ui

Length of output: 5036


🏁 Script executed:

# Read the audit.ts file to see the actual code
cat -n src/data/queries/audit.ts | head -30

# Search for auditApi imports and usage more reliably
rg -n "auditApi" src/data/queries/audit.ts
rg -n "import.*auditApi\|from.*audit" src/data/queries/audit.ts

Repository: RedHatInsights/insights-rbac-ui

Length of output: 1488


🏁 Script executed:

cat -n src/data/api/audit.ts | head -50

Repository: RedHatInsights/insights-rbac-ui

Length of output: 1110


🏁 Script executed:

# Search for similar query patterns with response.data
rg -n "response\.data" src/data/queries/ -A 1 -B 1

Repository: RedHatInsights/insights-rbac-ui

Length of output: 262


🏁 Script executed:

# Check the getAuditlogs response type definition
rg -n "AuditLogPagination\|GetAuditlogsResponse" src/ -A 3

# Search for how other API calls return responses
rg -n "queryFn:\s*async" src/data/queries/ -A 3 | head -40

Repository: RedHatInsights/insights-rbac-ui

Length of output: 320


🏁 Script executed:

# Search for AuditLogPagination type definition more thoroughly
rg -n "AuditLogPagination" src/data/api/ -B 2 -A 5

# Check what type getAuditlogs returns from rbac-client
rg -n "export type" src/data/api/audit.ts

Repository: RedHatInsights/insights-rbac-ui

Length of output: 1263


🏁 Script executed:

# Search for correct (as any) pattern usage with rbac-client calls
rg -n "\(as any\)" src/data/ -B 1 -A 1 | head -30

Repository: RedHatInsights/insights-rbac-ui

Length of output: 57


🏁 Script executed:

# Search entire src for (as any) pattern to see if it's used elsewhere
rg -n "\(as any\)" src/ | head -20

# Also search for any rbac-client API calls to see what pattern is standard
rg -n "Api\." src/data/ -A 1 | grep -E "(queryFn|return|const)" | head -30

Repository: RedHatInsights/insights-rbac-ui

Length of output: 224


🏁 Script executed:

# Check if there are other direct API calls to rbac-client methods that might need the cast
rg -n "getAuditlogs\|listRoles\|listUsers\|listGroups\|listPolicies" src/data/ | grep -v "import"

Repository: RedHatInsights/insights-rbac-ui

Length of output: 57


Use the documented (api.method as any) call pattern here.

Line 20 calls the generated RBAC client directly. In this repo, that pattern is known to break at runtime, so this hook should cast the method before invoking it.

Suggested fix
-        const response = await auditApi.getAuditlogs(params);
+        const response = await (auditApi.getAuditlogs as any)(params);

As per coding guidelines: "If the PR adds direct calls to @redhat-cloud-services/rbac-client methods WITHOUT the (api.method as any) cast pattern, flag it. The client types are broken and direct usage causes silent runtime failures."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
queryFn: async () => {
const response = await auditApi.getAuditlogs(params);
queryFn: async () => {
const response = await (auditApi.getAuditlogs as any)(params);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/data/queries/audit.ts` around lines 19 - 20, The hook's queryFn is
calling the generated RBAC client method directly
(auditApi.getAuditlogs(params)), which must be invoked using the documented cast
pattern to avoid runtime failures; update the call inside queryFn (in this
file's audit query hook) to cast the method before invoking it (i.e., use the
(auditApi.getAuditlogs as any)(...) pattern) so the RBAC client method is called
via the documented (api.method as any) call pattern.

};
}

const AuditLog: React.FC = () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Add a named export for the component itself.

The type re-export on Line 14 does not satisfy the feature export rule. This file can keep the default export, but the page component should also be exported as a named symbol.

Suggested fix
-const AuditLog: React.FC = () => {
+export const AuditLog: React.FC = () => {
   const intl = useIntl();
   ...
 };
 
 export default AuditLog;

As per coding guidelines, "Features (route/page containers, i.e. files directly under src/features/<island>/) may additionally export a default, but must always have a named export too."

Also applies to: 115-115

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/audit-log/AuditLog.tsx` at line 38, The file currently only has
a default export for the page component; add a named export for the component
symbol (AuditLog) so the page/container is exported both as default and as a
named export; update the export lines so that the React component declaration
remains (const AuditLog: React.FC = () => { ... }) and you add/export the named
symbol (export { AuditLog };) while leaving the default export in place—also
apply the same named-export change for the other page component instance
referenced around the second occurrence (the one at the later export on line
~115).

Comment on lines +41 to +47
const tableState = useTableState<typeof columns, AuditLogRow>({
columns,
getRowId: (row) => row.id,
initialPerPage: 20,
perPageOptions: [10, 20, 50],
syncWithUrl: true,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

This page still never exposes the new filters.

useTableState is initialized for pagination only, and TableView never receives filterConfig, filters, or onFiltersChange. So this route remains a plain paginated table even though filtering was added elsewhere in the audit-log UI.

Also applies to: 96-109

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/audit-log/AuditLog.tsx` around lines 41 - 47, The table is only
wired for pagination: update the useTableState call in AuditLog.tsx (the const
tableState = useTableState<typeof columns, AuditLogRow>...) to include filter
support and then pass the filter props into TableView; specifically ensure you
expose filterConfig, filters, and onFiltersChange from tableState (or provide
them via the same state hook) and add filterConfig={...},
filters={tableState.filters}, and onFiltersChange={tableState.setFilters} (or
the appropriate handlers) to the TableView component so the new filter UI is
actually enabled.

Comment on lines +49 to +55
const queryParams: GetAuditlogsParams = useMemo(
() => ({
limit: tableState.perPage,
offset: (tableState.page - 1) * tableState.perPage,
orderBy: 'id' as const,
}),
[tableState.perPage, tableState.page],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Sort the feed newest-first before paginating.

Line 53 uses orderBy: 'id', which sorts this page differently from the v2 audit-log page and from the visible Date column. With server-side pagination, that can put the oldest entries on page 1 and reshuffle later pages when new events arrive.

Suggested fix
-      orderBy: 'id' as const,
+      orderBy: '-created' as const,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const queryParams: GetAuditlogsParams = useMemo(
() => ({
limit: tableState.perPage,
offset: (tableState.page - 1) * tableState.perPage,
orderBy: 'id' as const,
}),
[tableState.perPage, tableState.page],
const queryParams: GetAuditlogsParams = useMemo(
() => ({
limit: tableState.perPage,
offset: (tableState.page - 1) * tableState.perPage,
orderBy: '-created' as const,
}),
[tableState.perPage, tableState.page],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/audit-log/AuditLog.tsx` around lines 49 - 55, The queryParams
currently sort by id ascending (orderBy: 'id') which yields oldest-first; change
the audit feed to sort newest-first before paginating by updating the
queryParams in AuditLog.tsx (the GetAuditlogsParams object constructed in the
useMemo) to request descending id order (e.g., use an API-supported descending
spec such as orderBy: 'id:desc' or add an orderDirection: 'desc' / order: 'desc'
field depending on the backend contract) so pages return newest entries first
and pagination remains stable.

Comment on lines +162 to +168
export const Error: Story = {
args: {
entries: [],
totalCount: 0,
isLoading: false,
error: 'Failed to load audit log. Please try again.',
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

fd "AuditLogTable.stories.tsx" -type f

Repository: RedHatInsights/insights-rbac-ui

Length of output: 245


🏁 Script executed:

cat -n src/features/audit-log/AuditLogTable.stories.tsx | sed -n '155,175p'

Repository: RedHatInsights/insights-rbac-ui

Length of output: 820


🏁 Script executed:

# Check if biome/eslint config exists and look for noShadowRestrictedNames rule
find . -maxdepth 2 -name "biome.json*" -o -name ".eslintrc*" -o -name "eslint.config.*" | head -5

Repository: RedHatInsights/insights-rbac-ui

Length of output: 106


🏁 Script executed:

cat biome.json | head -100

Repository: RedHatInsights/insights-rbac-ui

Length of output: 1849


🏁 Script executed:

# Check for noShadowRestrictedNames rule in biome config
rg "noShadowRestrictedNames" biome.json

Repository: RedHatInsights/insights-rbac-ui

Length of output: 57


🏁 Script executed:

# Check eslint config for any rules related to shadowing
cat eslint.config.js | grep -A 5 -B 5 "shadow\|Shadow" || echo "No shadow rules found in eslint.config.js"

Repository: RedHatInsights/insights-rbac-ui

Length of output: 116


🏁 Script executed:

# Check if there are any linting violations in the specific file
rg "noShadowRestrictedNames" . --type json -A 2 -B 2

Repository: RedHatInsights/insights-rbac-ui

Length of output: 57


🏁 Script executed:

# Let's check the Biome documentation reference in the schema to understand the default behavior
# Also check if the Error export is actually flagged anywhere in the codebase
rg "export const Error" src/features/audit-log/AuditLogTable.stories.tsx

Repository: RedHatInsights/insights-rbac-ui

Length of output: 104


🏁 Script executed:

# Let's see if there are any recent commits or lint reports mentioning this issue
git log --oneline -20 -- src/features/audit-log/AuditLogTable.stories.tsx 2>/dev/null || echo "Git history not available"

Repository: RedHatInsights/insights-rbac-ui

Length of output: 128


🏁 Script executed:

# Check what the actual component file looks like to verify this is indeed a story file
ls -la src/features/audit-log/ | head -20

Repository: RedHatInsights/insights-rbac-ui

Length of output: 390


🏁 Script executed:

# Verify the Biome rule by checking official Biome documentation or testing the specific rule
# Let's check if there are any other similar violations in the codebase
rg "export const (Error|Array|Object|Function|String|Boolean|Number|Symbol|BigInt)" --type tsx src/

Repository: RedHatInsights/insights-rbac-ui

Length of output: 102


🏁 Script executed:

# Check the biome documentation inline in a comment or any related rules being enforced
# Let's understand the default severity of noShadowRestrictedNames in Biome
python3 << 'EOF'
# Biome v2.4.7 noShadowRestrictedNames rule information
# This rule is part of the 'correctness' ruleset and is included in 'recommended': true
# The rule detects when you shadow names of restricted global variables
# Examples: Error, Array, Object, String, Boolean, Number, Symbol, Map, Set, etc.

# When included in recommended rules without explicit override, the default level is 'warn' or 'error'
# For this codebase with "recommended": true, the rule should be ACTIVE

restricted_names = [
    'Error', 'Array', 'Object', 'Function', 'String', 'Boolean', 
    'Number', 'Symbol', 'BigInt', 'Map', 'Set', 'WeakMap', 'WeakSet'
]

print("Biome noShadowRestrictedNames rule details:")
print(f"- Rule name: noShadowRestrictedNames")
print(f"- Category: correctness")
print(f"- Status: Active (via 'recommended': true in biome.json)")
print(f"- Restricted names include: {', '.join(restricted_names)}")
print(f"- Violation in file: export const Error triggers this rule")
EOF

Repository: RedHatInsights/insights-rbac-ui

Length of output: 423


Rename this story export to avoid shadowing the global Error constructor.

export const Error: Story shadows the global Error constructor and violates Biome's noShadowRestrictedNames rule, which is active in this codebase's linter configuration.

🔧 Suggested fix
-export const Error: Story = {
+export const ErrorState: Story = {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const Error: Story = {
args: {
entries: [],
totalCount: 0,
isLoading: false,
error: 'Failed to load audit log. Please try again.',
},
export const ErrorState: Story = {
args: {
entries: [],
totalCount: 0,
isLoading: false,
error: 'Failed to load audit log. Please try again.',
},
🧰 Tools
🪛 Biome (2.4.7)

[error] 162-162: Do not shadow the global "Error" property.

(lint/suspicious/noShadowRestrictedNames)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/audit-log/AuditLogTable.stories.tsx` around lines 162 - 168, The
story export named "Error" shadows the global Error constructor; rename the
export (e.g., ErrorState or ErrorStory) wherever it's declared (export const
Error: Story) and update any references to that story export (imports/usages
within this file or Storybook configs) so the new identifier is used instead,
ensuring the Story type annotation remains (e.g., export const ErrorState: Story
= { args: { ... } }).

Comment on lines +189 to +209
// Wait for first page: one of the first-page-only entries (id 6 = "Audit action 6")
await waitFor(() => {
expect(canvas.getByText('Audit action 6')).toBeInTheDocument();
});

// Pagination should show total (e.g. "1 - 20 of 25" or "25" in total-items)
const paginationRegion = canvasElement.querySelector('.pf-v6-c-pagination, [class*="pagination"]');
expect(paginationRegion).toBeInTheDocument();
expect(canvasElement.textContent).toMatch(/25/);

// Go to next page
const nextButtons = canvas.getAllByRole('button', { name: /next/i });
expect(nextButtons.length).toBeGreaterThan(0);
await userEvent.click(nextButtons[0]);

// Page 2 should show entries 21–25 (first on page 2 is "Audit action 21")
await waitFor(() => {
expect(canvas.getByText('Audit action 21')).toBeInTheDocument();
});
// First-page-only entry should not be visible
expect(canvas.queryByText('Audit action 6')).not.toBeInTheDocument();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Match the pagination assertions to the actual mock text.

Lines 191, 206, and 209 query for Audit action 6 / Audit action 21, but buildMockEntriesForPagination renders Audit action N: .... These exact-string lookups will fail before the page-change behavior is validated.

🔧 Suggested fix
-    await waitFor(() => {
-      expect(canvas.getByText('Audit action 6')).toBeInTheDocument();
-    });
+    await expect(canvas.findByText(/Audit action 6:/i)).resolves.toBeInTheDocument();
@@
-    await waitFor(() => {
-      expect(canvas.getByText('Audit action 21')).toBeInTheDocument();
-    });
+    await expect(canvas.findByText(/Audit action 21:/i)).resolves.toBeInTheDocument();
@@
-    expect(canvas.queryByText('Audit action 6')).not.toBeInTheDocument();
+    expect(canvas.queryByText(/Audit action 6:/i)).not.toBeInTheDocument();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Wait for first page: one of the first-page-only entries (id 6 = "Audit action 6")
await waitFor(() => {
expect(canvas.getByText('Audit action 6')).toBeInTheDocument();
});
// Pagination should show total (e.g. "1 - 20 of 25" or "25" in total-items)
const paginationRegion = canvasElement.querySelector('.pf-v6-c-pagination, [class*="pagination"]');
expect(paginationRegion).toBeInTheDocument();
expect(canvasElement.textContent).toMatch(/25/);
// Go to next page
const nextButtons = canvas.getAllByRole('button', { name: /next/i });
expect(nextButtons.length).toBeGreaterThan(0);
await userEvent.click(nextButtons[0]);
// Page 2 should show entries 21–25 (first on page 2 is "Audit action 21")
await waitFor(() => {
expect(canvas.getByText('Audit action 21')).toBeInTheDocument();
});
// First-page-only entry should not be visible
expect(canvas.queryByText('Audit action 6')).not.toBeInTheDocument();
// Wait for first page: one of the first-page-only entries (id 6 = "Audit action 6")
await expect(canvas.findByText(/Audit action 6:/i)).resolves.toBeInTheDocument();
// Pagination should show total (e.g. "1 - 20 of 25" or "25" in total-items)
const paginationRegion = canvasElement.querySelector('.pf-v6-c-pagination, [class*="pagination"]');
expect(paginationRegion).toBeInTheDocument();
expect(canvasElement.textContent).toMatch(/25/);
// Go to next page
const nextButtons = canvas.getAllByRole('button', { name: /next/i });
expect(nextButtons.length).toBeGreaterThan(0);
await userEvent.click(nextButtons[0]);
// Page 2 should show entries 21–25 (first on page 2 is "Audit action 21")
await expect(canvas.findByText(/Audit action 21:/i)).resolves.toBeInTheDocument();
// First-page-only entry should not be visible
expect(canvas.queryByText(/Audit action 6:/i)).not.toBeInTheDocument();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/audit-log/AuditLogTable.stories.tsx` around lines 189 - 209, The
test assertions look for exact strings "Audit action 6" and "Audit action 21"
but buildMockEntriesForPagination renders entries like "Audit action N: ...", so
update the expectations in AuditLogTable.stories.tsx to match the actual mock
text (e.g., use canvas.getByText with a regex or substring that includes the
colon and following text such as /Audit action 6:/ and /Audit action 21:/, or
assert via contains/startsWith) for the initial page check, the post-pagination
check, and the absence check (canvas.queryByText should use a matching pattern
for "Audit action 6:" to confirm it's not present).

@riccardo-forina

Copy link
Copy Markdown
Contributor

This branch looks like it was started before the v1/v2 split freeze and has pulled in a massive amount of cross-boundary conflicts and auto-generated artifacts (like the bot-managed CHANGELOG.md). >

The actual fix for this ticket in the new v2 architecture only requires touching a few lines. I'm going to close this PR so we don't accidentally merge this git history. Let's sync up this morning so I can show you exactly where this goes in the new structure!

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.

3 participants