Skip to content

[ACM-29130] RBAC UI - Creation wizard - project validation#5748

Open
Ginxo wants to merge 27 commits intostolostron:mainfrom
Ginxo:ACM-29130_newproposal
Open

[ACM-29130] RBAC UI - Creation wizard - project validation#5748
Ginxo wants to merge 27 commits intostolostron:mainfrom
Ginxo:ACM-29130_newproposal

Conversation

@Ginxo
Copy link
Contributor

@Ginxo Ginxo commented Feb 25, 2026

📝 Summary

it depends on backend, so holding it for now

Ticket Summary (Title):
RBAC UI - Creation wizard - project validation

Ticket Link:
https://issues.redhat.com/browse/ACM-29130

Evidences

Video_2026-02-25_17-50-12.mp4

Testing instructions

  1. create a new RA for cluster or cluster set and target namespaces (common projects)
  2. edit it from the CLI adding non existing project name on the cluster (whatever the crazy string you consider)
 oc edit multiclusterroleassignment -n open-cluster-management-global-set $MULTICLUSTER_RA_ID
  1. save it
  2. go back to the console, an error should be shown for that particular RA
  3. hover the error and click on the create missing projects button

Expected results:
the projects are created on the different clusters and the error disappears as soon as the resources are reconciled.

Type of Change:

  • 🐞 Bug Fix
  • ✨ Feature
  • 🔧 Refactor
  • 💸 Tech Debt
  • 🧪 Test-related
  • 📄 Docs

✅ Checklist

General

  • PR title follows the convention (e.g. ACM-12340 Fix bug with...)
  • Code builds and runs locally without errors
  • No console logs, commented-out code, or unnecessary files
  • All commits are meaningful and well-labeled
  • All new display strings are externalized for localization (English only)
  • (Nice to have) JSDoc comments added for new functions and interfaces

If Feature

  • UI/UX reviewed (if applicable)
  • All acceptance criteria met
  • Unit test coverage added or updated
  • Relevant documentation or comments included

If Bugfix

  • Root cause and fix summary are documented in the ticket (for future reference / errata)
  • Fix tested thoroughly and resolves the issue
  • Test(s) added to prevent regression

🗒️ Notes for Reviewers

Summary by CodeRabbit

  • New Features

    • Create missing projects across clusters from role-assignment flows with live progress, per-item processing, and actionable "Create missing projects" button
    • Enhanced role-assignment status UI: expandable error details, reason translations, loading/processing states
    • New cluster→namespace mapping hook to drive namespace-aware flows
  • Bug Fixes & Improvements

    • Alerts/toasts can be modified after creation (id-based updates); improved messages, confirmations, and accessibility (aria labels)
  • Tests

    • Extensive tests for hooks, status flows, alerts, progress, and error handling

Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
@openshift-ci
Copy link

openshift-ci bot commented Feb 25, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci
Copy link

openshift-ci bot commented Feb 25, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: Ginxo

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds i18n keys for missing-project workflows; narrows RoleAssignmentStatus.reason to specific literals; introduces useClusterNamespaceMap and useRoleAssignmentsStatusHook to detect/create missing projects with progress alerts; refactors status UI to accept roleAssignment with per-reason callbacks; extends alert/toast API to support id-returning addAlert and modifyAlert.

Changes

Cohort / File(s) Summary
Localization
frontend/public/locales/en/translation.json
Added translation keys for missing-project workflows, lifecycle messages, success and error texts, and validation/help strings.
RoleAssignment types
frontend/src/resources/multicluster-role-assignment.ts
Restricted RoleAssignmentStatus.reason from string to a union of literal reasons (Processing, InvalidReference, NoMatchingClusters, SuccessfullyApplied, ApplicationFailed, MissingNamespaces).
Hooks — new
frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.tsx
New hook exposing callbacksPerReasonMap, per-RA processing flags, and orchestration logic for creating missing projects with progress reporting and toast updates.
Hooks — new
frontend/src/utils/useClusterNamespaceMap.ts, frontend/src/utils/useClusterNamespaceMap.test.ts
New hook to build cluster→namespaces map from search results; tests validate filtering, map construction, and loading behavior.
Error handling module
frontend/src/routes/UserManagement/roleAssignmentErrorHandlingFunctions.tsx, .../roleAssignmentErrorHandlingFunctions.test.tsx
New functions to compute missing namespaces per cluster and to create ProjectRequest actions across clusters with batching, per-cluster error tracking, progress callbacks, and alerting; comprehensive tests added.
Status component & helpers
frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx, frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentsHelper.tsx, .../RoleAssignment/RoleAssignmentStatusComponent.test.tsx, .../RoleAssignmentsHelper.test.tsx
Refactored Status component API to accept roleAssignment and optional callbacksPerReasonMap, isCallbackProcessing, areActionButtonsDisabled; added ReasonString/ReasonFooter internals and create-missing-projects action wiring; tests updated/expanded.
RoleAssignments integration & tests
frontend/src/routes/UserManagement/RoleAssignment/RoleAssignments.tsx, .../RoleAssignments.test.tsx, .../useRoleAssignmentsStatusHook.test.tsx
Integrated new hook into Status column rendering, passing per-RA processing and callbacks; tests and mocks updated to supply processing maps and modifyAlert.
AcmAlert / Toast changes
frontend/src/ui-components/AcmAlert/AcmAlert.tsx, frontend/src/ui-components/AcmAlert/AcmToast.tsx, .../AcmAlert.test.tsx
Added optional id on alerts, AcmAlertInfoWithId type, replaceAlertById util; addAlert now returns alert with id; added modifyAlert to alert and toast contexts/providers; providers updated to return and support id-based modifications.
Progress UI
frontend/src/wizards/RoleAssignment/CommonProjectCreateProgressBar.tsx, .../CommonProjectCreateProgressBar.test.tsx
Added hideTitle?: boolean prop to optionally hide the title while preserving progress aria attributes; tests added.
Test scaffolding updates
multiple tests (.../CreatePolicySubmit.test.tsx, .../RoleAssignmentWizardModalWrapper.test.tsx, .../CreateArgoResources.test.tsx, .../roleAssignmentModalHelper.test.tsx, .../RoleAssignmentDataHook.test.tsx, .../RoleAssignment/RoleAssignments.test.tsx)
Updated toast context mocks to include modifyAlert, adjusted mocks to use useClusterNamespaceMap, and updated renderStatusCell/test call sites to the new signature.
RoleAssignment data hook
frontend/src/routes/UserManagement/RoleAssignments/hook/RoleAssignmentDataHook.ts, .../RoleAssignmentDataHook.test.tsx
Replaced all-namespaces search with useClusterNamespaceMap, updated loading logic and tests to consume clusterNamespaceMap.
Misc tests
various test files listed in summary
Adjusted mocks and test helpers to align with new alert/toast API and status component signature changes.

Sequence Diagram(s)

sequenceDiagram
    participant UI as RoleAssignments UI
    participant Hook as useRoleAssignmentsStatusHook
    participant ClusterMap as useClusterNamespaceMap
    participant Toast as AcmToast
    participant MCA as fireManagedClusterActionCreate

    UI->>Hook: mount / request callbacksPerReasonMap
    Hook->>ClusterMap: request clusterNamespaceMap
    ClusterMap-->>Hook: return clusterNamespaceMap

    alt MissingNamespaces detected
        Hook->>Toast: addAlert("Creating missing projects", progress=0)
        loop per cluster/namespace
            Hook->>MCA: fireManagedClusterActionCreate(ProjectRequest)
            MCA-->>Hook: success / failure
            Hook->>Toast: modifyAlert(update progress)
        end
        Hook->>Toast: modifyAlert(completion summary)
    else No missing namespaces
        Hook->>Toast: addAlert("No missing projects")
    end

    Hook-->>UI: expose callbacksPerReasonMap, isProcessingMap
    UI->>UI: render RoleAssignmentStatusComponent(roleAssignment, callbacks, processing)
Loading
sequenceDiagram
    participant Component as RoleAssignmentStatusComponent
    participant Props as Props (roleAssignment, callbacksPerReasonMap)
    participant Callback as callbacksPerReasonMap[reason]
    participant Toast as AcmToast

    Component->>Props: inspect roleAssignment.status.reason
    alt reason ∈ {MissingNamespaces, ApplicationFailed}
        Component->>Callback: invoke handler(roleAssignment)
        Callback->>Toast: addAlert / modifyAlert (returns AcmAlertInfoWithId)
        Toast-->>Callback: updated alert info
        Component->>Component: show spinner if isCallbackProcessing
    else other reasons
        Component->>Component: render reason string/footer
    end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 I hop through clusters, names in tow,

Planting projects where they used to be low.
Toasts tick progress, alerts shine bright,
Missing namespaces fixed by midnight.
Hooray — I nibble errors out of sight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% 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 PR title '[ACM-29130] RBAC UI - Creation wizard - project validation' is specific, concise, and clearly summarizes the main feature: project validation in the RBAC creation wizard UI.
Description check ✅ Passed The PR description follows the required template with completed sections: Summary, Ticket details, evidence, testing instructions, type of change (Feature), and a mostly-completed checklist. All essential information is present.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
return newAlertInfos
})
}, [])
const modifyAlert = useCallback<(alertInfo: AcmAlertInfoWithId) => AcmAlertInfoWithId>(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

there is no way I can have a kind of progress component alert thing, so I had to adapt AcmToastContext in order to be able to rerender specific alert based on progress information.
The rest of the code remains the same and the whole application is not affected by this apart from different mocking values from 4 different test files

@Ginxo Ginxo marked this pull request as ready for review February 25, 2026 16:42
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 15

Caution

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

⚠️ Outside diff range comments (1)
frontend/src/wizards/RoleAssignment/CommonProjectCreateProgressBar.tsx (1)

37-37: ⚠️ Potential issue | 🟡 Minor

Division by zero when totalCount is 0.

If totalCount is 0, progressValue evaluates to NaN. While callers currently guard against this, the component itself should be defensive.

🛡️ Proposed fix
-  const progressValue = ((successCount + errorCount) / totalCount) * 100
+  const progressValue = totalCount > 0 ? ((successCount + errorCount) / totalCount) * 100 : 0
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/wizards/RoleAssignment/CommonProjectCreateProgressBar.tsx` at
line 37, The computation of progressValue in CommonProjectCreateProgressBar can
produce NaN when totalCount is 0; update the progressValue calculation (using
successCount, errorCount, totalCount) to defensively handle totalCount === 0
(e.g., set progressValue to 0 when totalCount is 0) and clamp the result to the
0–100 range so the component never renders NaN or out-of-range values.
♻️ Duplicate comments (2)
frontend/src/routes/UserManagement/RoleAssignments/hook/RoleAssignmentDataHook.test.tsx (1)

2-2: Same @testing-library/react-hooks / React 18 incompatibility.

Migrate to import { renderHook } from '@testing-library/react' as noted for the other hook test files.

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

In
`@frontend/src/routes/UserManagement/RoleAssignments/hook/RoleAssignmentDataHook.test.tsx`
at line 2, The test imports renderHook from the deprecated package causing React
18 incompatibility; update the import to use renderHook from
'@testing-library/react' instead of '@testing-library/react-hooks' in
RoleAssignmentDataHook.test.tsx and ensure any references to renderHook in this
file (e.g., calls that wrap hook invocation for RoleAssignmentDataHook) continue
to work with the new import (adjust usage to the RTL renderHook API if
necessary).
frontend/src/utils/useClusterNamespaceMap.test.ts (1)

3-3: Same @testing-library/react-hooks / React 18 incompatibility as the other hook test files.

See comment in useRoleAssignmentsStatusHook.test.tsx (Line 4) — migrate to import { renderHook } from '@testing-library/react'.

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

In `@frontend/src/utils/useClusterNamespaceMap.test.ts` at line 3, Replace the
incompatible import of renderHook from '@testing-library/react-hooks' with the
React 18 compatible import from '@testing-library/react' (update the import
statement that currently reads "import { renderHook } from
'@testing-library/react-hooks'" to "import { renderHook } from
'@testing-library/react'"); ensure existing usages of renderHook in the test
remain unchanged and run under the new import.
🧹 Nitpick comments (6)
frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.tsx (1)

50-50: handleMissingNamespaces captures stale clusterNamespaceMap without useCallback.

Since this async function closes over clusterNamespaceMap and is stored in callbacksPerReasonMap (returned to consumers), it will always reference the latest render's map but also creates a new function identity every render. Consider wrapping in useCallback with appropriate dependencies to prevent unnecessary re-renders in consuming components.

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

In
`@frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.tsx`
at line 50, The async function handleMissingNamespaces closes over
clusterNamespaceMap and is recreated every render (causing new identity in
callbacksPerReasonMap); wrap handleMissingNamespaces in React.useCallback and
include the minimal necessary dependencies (e.g., clusterNamespaceMap and any
other referenced variables) so its identity is stable across renders and it
still captures up-to-date clusterNamespaceMap; update where
callbacksPerReasonMap is built to use the memoized handleMissingNamespaces.
frontend/src/routes/UserManagement/RoleAssignment/RoleAssignments.test.tsx (1)

243-243: modifyAlert mock correctly returns the input alert.

This matches the production modifyAlert behavior (returning the modified alert with its id), unlike other test files that use a bare jest.fn(). Consider aligning the mock pattern across test files for consistency, though this is a minor nit.

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

In `@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignments.test.tsx`
at line 243, Tests use a concrete mock for modifyAlert (jest.fn((alert: any) =>
alert)) while other tests use bare jest.fn(); update the other test files to
match this behavior or change this one to a bare mock for consistency—locate the
modifyAlert mock in RoleAssignments.test.tsx (the modifyAlert jest.fn) and
replace or align it so all tests consistently either return the passed alert
(jest.fn((alert)=>alert)) or use a plain jest.fn() across the suite.
frontend/src/utils/useClusterNamespaceMap.test.ts (1)

155-177: Missing test case for undefined ns.cluster.

The existing test covers undefined namespace names but not undefined cluster names. After fixing the production guard in useClusterNamespaceMap.ts, a test like the following would validate that items with a falsy cluster field are silently skipped rather than polluting the map with a garbage key.

🧪 Suggested additional test
+  it('should skip items with undefined or empty cluster name', () => {
+    mockUseSearchResultItemsQuery.mockReturnValue({
+      data: {
+        searchResult: [
+          {
+            items: [
+              { cluster: 'cluster-1', name: 'valid-ns' },
+              { cluster: undefined, name: 'orphan-ns' },
+              { cluster: '', name: 'empty-cluster-ns' },
+            ],
+          },
+        ],
+      },
+      loading: false,
+      error: undefined,
+    } as any)
+
+    const { result } = renderHook(() => useClusterNamespaceMap())
+
+    expect(result.current.clusterNamespaceMap).toEqual({
+      'cluster-1': ['valid-ns'],
+    })
+  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/utils/useClusterNamespaceMap.test.ts` around lines 155 - 177,
Add a test to validate that useClusterNamespaceMap skips items with a falsy
cluster value: update the test using mockUseSearchResultItemsQuery to return
items where one entry has cluster: undefined (or ''/null) and a valid name, then
renderHook(() => useClusterNamespaceMap()) and assert that
result.current.clusterNamespaceMap does not contain an undefined/empty key and
only includes namespaces grouped under real cluster keys (reference
useClusterNamespaceMap and mockUseSearchResultItemsQuery to locate the code to
modify).
frontend/src/utils/useClusterNamespaceMap.ts (1)

29-30: Redundant optional chaining in the truthy branch.

Line 29 already guards that allNamespacesQuery?.searchResult?.[0]?.items?.length is truthy, so items is guaranteed non-null inside the if block. The optional chaining and || [] fallback on line 30 are unreachable.

♻️ Proposed simplification
-      const items = allNamespacesQuery?.searchResult?.[0]?.items || []
+      const items = allNamespacesQuery!.searchResult![0]!.items!
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/utils/useClusterNamespaceMap.ts` around lines 29 - 30, Inside
useClusterNamespaceMap, the if guard using isLoading and
allNamespacesQuery?.searchResult?.[0]?.items?.length guarantees items is
non-null, so replace the redundant optional chaining and fallback in the
assignment for items: change const items =
allNamespacesQuery?.searchResult?.[0]?.items || [] to a direct (non-optional)
access such as const items = allNamespacesQuery!.searchResult![0]!.items or
const items = allNamespacesQuery.searchResult[0].items (whichever matches your
TS strictness), referencing the existing variables isLoading, allNamespacesQuery
and items to remove the unreachable || [] fallback.
frontend/public/locales/en/translation.json (1)

1487-1490: Consider plural placeholder naming for plural text.

Line 1490 uses plural wording (projects, clusters) with singular placeholder names ({{project}}, {{cluster}}). Using plural placeholder names would make intent clearer and reduce interpolation mismatch risk.

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

In `@frontend/public/locales/en/translation.json` around lines 1487 - 1490, The
plural translation key "Error creating missing projects {{project}} for clusters
{{cluster}}." uses singular placeholders; update the placeholders to plural
(e.g., change to "Error creating missing projects {{projects}} for clusters
{{clusters}}.") and then update any code that calls this translation key to pass
the corresponding plural variables (projects, clusters) instead of
project/cluster so interpolation matches the plural intent.
frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx (1)

134-142: JSDoc is stale and no longer matches the exported props type.

The block still documents status / callbackProgress, which are not present in RoleAssignmentStatusComponentProps. Please update to avoid API confusion.

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

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`
around lines 134 - 142, The JSDoc above RoleAssignmentStatusComponent is stale:
update the comment to match the exported RoleAssignmentStatusComponentProps by
removing references to the nonexistent status and callbackProgress fields (or
replace them with the actual prop names/types used in
RoleAssignmentStatusComponentProps), ensuring the doc correctly describes
callbacksPerReasonMap and any real props; reference the
RoleAssignmentStatusComponent and RoleAssignmentStatusComponentProps symbols
when editing the JSDoc so the comment and exported type stay in sync.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/public/locales/en/translation.json`:
- Around line 2118-2120: Replace the awkward message value for the translation
key that currently reads "No missing projects found for {{name}} RoleAssignment.
MultiClusterRoleAssignment resource is reconciling information." with a clearer
phrase such as "No missing projects found for {{name}} RoleAssignment.
MultiClusterRoleAssignment reconciliation is in progress." — edit the value in
frontend/public/locales/en/translation.json for that exact string so the UI
shows the clearer wording.

In `@frontend/src/resources/multicluster-role-assignment.ts`:
- Around line 40-46: The union type for reason in
multicluster-role-assignment.ts is too narrow and excludes actual backend values
seen in mock data (e.g., "permissions don't applied" and "invalid cluster set");
update the type definition (the `reason` union) to include those exact backend
string literals or relax it to a plain string type, and ensure any code paths
using RoleAssignmentStatusComponent / ReasonString continue to handle unknown
values gracefully.

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`:
- Around line 173-174: The Spinner components in RoleAssignmentStatusComponent
currently use hardcoded English aria-label strings; replace them with localized
strings by wrapping the aria-label values in the translation function (t(...))
and using appropriate i18n keys (e.g., reuse the key used for label "Creating
common projects" or add new keys like 'creatingCommonProjects.ariaLabel') for
both occurrences (the Spinner with label={t('Creating common projects')} and the
other Spinner at the later occurrence referenced in the review). Ensure
aria-label now reads aria-label={t('...')} so screen-reader text is localized.
- Line 126: The Label component currently hardcodes aria-disabled to true which
incorrectly exposes disabled state to assistive tech; update the Label usage
(Label) to either remove the aria-disabled attribute and rely on
isDisabled={isCallbackProcessing} or bind it to the actual state
(aria-disabled={isCallbackProcessing}) so it reflects the same boolean as
isDisabled, ensuring accessibility state matches isCallbackProcessing.
- Around line 42-47: The onClick handler in RoleAssignmentStatusComponent
currently invokes callback immediately in the true branch and returns a function
in the false branch, so clicks become a no-op when callback is missing and the
button remains enabled; change the handler to always provide a function (e.g.,
onClick={() => callback ? callback(roleAssignment) : console.error(... )}) and
also disable the button when no callback is provided by updating isDisabled to
combine areActionButtonsDisabled with !callback so the button is disabled if
there is no callback.

In
`@frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.test.tsx`:
- Around line 127-150: The test uses a synchronous act to invoke handleMissing
from useRoleAssignmentsStatusHook and then immediately reads
isProcessingRoleAssignmentMap/isAnyRoleAssignmentProcessing, which can be flaky
under React 18 concurrent mode; update the test to invoke handleMissing inside
an awaited act (e.g., await act(async () => { handleMissing!(baseRoleAssignment)
})) and/or follow it with a waitFor that asserts the expected state (checking
isProcessingRoleAssignmentMap['ra-1'] and isAnyRoleAssignmentProcessing) so
state updates from fireManagedClusterActionCreate (mocked by
fireManagedClusterActionCreateMock) are fully committed before assertions run.
- Line 4: Tests import utilities from the incompatible package
'@testing-library/react-hooks'; update the imports in the three test files so
renderHook and act are imported from '@testing-library/react' (and ensure your
project dependency `@testing-library/react` is upgraded to v13+ to support React
18), i.e., replace any "import { renderHook, act } from
'@testing-library/react-hooks'" with the equivalent import from
'@testing-library/react' in
frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.test.tsx,
frontend/src/utils/useClusterNamespaceMap.test.ts, and
frontend/src/routes/UserManagement/RoleAssignments/hook/RoleAssignmentDataHook.test.tsx.

In
`@frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.tsx`:
- Around line 195-205: The translation call in useRoleAssignmentsStatusHook is
passing plural keys (projects, clusters) but the template uses singular
placeholders ({{project}}, {{cluster}}), so update the interpolation to match
the template or (better) update the template placeholders to plural — e.g.,
change the t(...) template to use {{projects}} and {{clusters}} to match
Object.values(callbackProgress.errorClusterNamespacesMap).flat() and
Object.keys(callbackProgress.errorClusterNamespacesMap), or alternatively rename
the interpolation object keys to project and cluster if you prefer singular
placeholders; ensure the keys used in the t(...) call exactly match the
placeholders so the toast message is interpolated correctly.
- Around line 82-141: The Promise.all call is receiving nested arrays because
Object.entries(...).map returns an array of arrays, so the inner
fireManagedClusterActionCreate promises aren't awaited; update the outer
iteration to produce a flat Promise[] (e.g., replace the outer .map with
.flatMap over Object.entries(missingNamespacesPerCluster)) so Promise.all
receives a flat list of promises, keeping the existing handlers that update
counter, errorClusterNamespacesMap, toastContext.addAlert, and
setCallbackProgress intact; ensure you reference missingNamespacesPerCluster,
fireManagedClusterActionCreate, counter, and setCallbackProgress when applying
the change.

In `@frontend/src/ui-components/AcmAlert/AcmAlert.tsx`:
- Around line 70-81: modifyAlert currently updates only visibleAlerts causing
activeAlerts to become stale; update activeAlerts in the same callback path as
visibleAlerts (or in a synchronized state update) so both arrays remain
consistent: in the modifyAlert implementation (the function named modifyAlert
that calls setVisibleAlerts) also call the corresponding state updater for
activeAlerts (e.g., setActiveAlerts) to find the same alert by id, replace it,
and return the new array, being careful to handle index === -1 (no-op) and
preserve the function’s return value of alertInfo; mirror the same replacement
logic used in addAlert to keep behavior consistent with removeAlert/clearAlerts.
- Around line 70-81: modifyAlert currently sets newAlertInfos[index] without
checking if index === -1 which silently corrupts the array; update the
modifyAlert callback to mirror removeAlert/removeVisibleAlert by checking the
result of alerts.findIndex((ai) => ai.id === alertInfo.id) and only assign
newAlertInfos[index] = alertInfo and return the updated array when index !== -1,
otherwise return the original alerts unchanged (and still return alertInfo from
the outer function).
- Around line 46-51: The addAlert function currently mutates the caller's
alertInfo by assigning alert.id directly; instead create a new object (e.g.,
newAlert = { ...alert, id: generatedId }) and use that when calling
setActiveAlerts and setVisibleAlerts and when returning the value so the
original alert parameter is not modified; update references to alert.id in
addAlert to use the newAlert variable and keep the generated id logic and return
shape the same (AcmAlertInfoWithId).

In `@frontend/src/ui-components/AcmAlert/AcmToast.tsx`:
- Around line 25-30: The addAlert callback currently mutates the caller's alert
object by assigning alert.id; instead create a new object (e.g., alertWithId)
that spreads the incoming AcmAlertInfo and adds the generated id, then pass
alertWithId to setActiveAlerts and setVisibleAlerts and return it as
AcmAlertInfoWithId; update references in the addAlert implementation to avoid
mutating the original object.
- Around line 49-60: modifyAlert currently assumes the alert id exists and
writes into newAlertInfos[index] without checking for -1; update the modifyAlert
callback (the function passed to setVisibleAlerts referenced as modifyAlert and
the state setter setVisibleAlerts operating on AcmAlertInfoWithId) to first
compute index with alerts.findIndex(...), then only replace newAlertInfos[index]
and return the updated array if index !== -1; if index === -1 simply return the
original alerts array (and still return alertInfo from the outer callback) to
avoid silent writes to newAlertInfos[-1].

In `@frontend/src/utils/useClusterNamespaceMap.ts`:
- Around line 31-44: The reducer in useClusterNamespaceMap.ts is using
ns.cluster as a key without validating it, which can create "undefined" or
empty-string keys; update the reduce callback in the function (the items.reduce
handler) to skip entries where clusterName is falsy or not a non-empty string
(e.g., if (!clusterName || typeof clusterName !== 'string' || clusterName.trim()
=== '') return acc), so only valid clusterName values are used to initialize and
push namespaceName into acc[clusterName].

---

Outside diff comments:
In `@frontend/src/wizards/RoleAssignment/CommonProjectCreateProgressBar.tsx`:
- Line 37: The computation of progressValue in CommonProjectCreateProgressBar
can produce NaN when totalCount is 0; update the progressValue calculation
(using successCount, errorCount, totalCount) to defensively handle totalCount
=== 0 (e.g., set progressValue to 0 when totalCount is 0) and clamp the result
to the 0–100 range so the component never renders NaN or out-of-range values.

---

Duplicate comments:
In
`@frontend/src/routes/UserManagement/RoleAssignments/hook/RoleAssignmentDataHook.test.tsx`:
- Line 2: The test imports renderHook from the deprecated package causing React
18 incompatibility; update the import to use renderHook from
'@testing-library/react' instead of '@testing-library/react-hooks' in
RoleAssignmentDataHook.test.tsx and ensure any references to renderHook in this
file (e.g., calls that wrap hook invocation for RoleAssignmentDataHook) continue
to work with the new import (adjust usage to the RTL renderHook API if
necessary).

In `@frontend/src/utils/useClusterNamespaceMap.test.ts`:
- Line 3: Replace the incompatible import of renderHook from
'@testing-library/react-hooks' with the React 18 compatible import from
'@testing-library/react' (update the import statement that currently reads
"import { renderHook } from '@testing-library/react-hooks'" to "import {
renderHook } from '@testing-library/react'"); ensure existing usages of
renderHook in the test remain unchanged and run under the new import.

---

Nitpick comments:
In `@frontend/public/locales/en/translation.json`:
- Around line 1487-1490: The plural translation key "Error creating missing
projects {{project}} for clusters {{cluster}}." uses singular placeholders;
update the placeholders to plural (e.g., change to "Error creating missing
projects {{projects}} for clusters {{clusters}}.") and then update any code that
calls this translation key to pass the corresponding plural variables (projects,
clusters) instead of project/cluster so interpolation matches the plural intent.

In `@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignments.test.tsx`:
- Line 243: Tests use a concrete mock for modifyAlert (jest.fn((alert: any) =>
alert)) while other tests use bare jest.fn(); update the other test files to
match this behavior or change this one to a bare mock for consistency—locate the
modifyAlert mock in RoleAssignments.test.tsx (the modifyAlert jest.fn) and
replace or align it so all tests consistently either return the passed alert
(jest.fn((alert)=>alert)) or use a plain jest.fn() across the suite.

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`:
- Around line 134-142: The JSDoc above RoleAssignmentStatusComponent is stale:
update the comment to match the exported RoleAssignmentStatusComponentProps by
removing references to the nonexistent status and callbackProgress fields (or
replace them with the actual prop names/types used in
RoleAssignmentStatusComponentProps), ensuring the doc correctly describes
callbacksPerReasonMap and any real props; reference the
RoleAssignmentStatusComponent and RoleAssignmentStatusComponentProps symbols
when editing the JSDoc so the comment and exported type stay in sync.

In
`@frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.tsx`:
- Line 50: The async function handleMissingNamespaces closes over
clusterNamespaceMap and is recreated every render (causing new identity in
callbacksPerReasonMap); wrap handleMissingNamespaces in React.useCallback and
include the minimal necessary dependencies (e.g., clusterNamespaceMap and any
other referenced variables) so its identity is stable across renders and it
still captures up-to-date clusterNamespaceMap; update where
callbacksPerReasonMap is built to use the memoized handleMissingNamespaces.

In `@frontend/src/utils/useClusterNamespaceMap.test.ts`:
- Around line 155-177: Add a test to validate that useClusterNamespaceMap skips
items with a falsy cluster value: update the test using
mockUseSearchResultItemsQuery to return items where one entry has cluster:
undefined (or ''/null) and a valid name, then renderHook(() =>
useClusterNamespaceMap()) and assert that result.current.clusterNamespaceMap
does not contain an undefined/empty key and only includes namespaces grouped
under real cluster keys (reference useClusterNamespaceMap and
mockUseSearchResultItemsQuery to locate the code to modify).

In `@frontend/src/utils/useClusterNamespaceMap.ts`:
- Around line 29-30: Inside useClusterNamespaceMap, the if guard using isLoading
and allNamespacesQuery?.searchResult?.[0]?.items?.length guarantees items is
non-null, so replace the redundant optional chaining and fallback in the
assignment for items: change const items =
allNamespacesQuery?.searchResult?.[0]?.items || [] to a direct (non-optional)
access such as const items = allNamespacesQuery!.searchResult![0]!.items or
const items = allNamespacesQuery.searchResult[0].items (whichever matches your
TS strictness), referencing the existing variables isLoading, allNamespacesQuery
and items to remove the unreachable || [] fallback.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 282123e and 1cbadc5.

📒 Files selected for processing (23)
  • frontend/public/locales/en/translation.json
  • frontend/src/resources/multicluster-role-assignment.ts
  • frontend/src/routes/Governance/policies/CreatePolicySubmit.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignments.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignments.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentsHelper.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentsHelper.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.tsx
  • frontend/src/routes/UserManagement/RoleAssignments/RoleAssignmentWizardModalWrapper.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignments/hook/RoleAssignmentDataHook.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignments/hook/RoleAssignmentDataHook.ts
  • frontend/src/routes/UserManagement/RoleAssignments/roleAssignmentModalHelper.test.ts
  • frontend/src/ui-components/AcmAlert/AcmAlert.test.tsx
  • frontend/src/ui-components/AcmAlert/AcmAlert.tsx
  • frontend/src/ui-components/AcmAlert/AcmToast.tsx
  • frontend/src/utils/useClusterNamespaceMap.test.ts
  • frontend/src/utils/useClusterNamespaceMap.ts
  • frontend/src/wizards/Argo/CreateArgoResources.test.tsx
  • frontend/src/wizards/RoleAssignment/CommonProjectCreateProgressBar.test.tsx
  • frontend/src/wizards/RoleAssignment/CommonProjectCreateProgressBar.tsx

Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (4)
frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx (3)

124-124: ⚠️ Potential issue | 🟡 Minor

aria-disabled is hardcoded and does not reflect the real state.

This always announces disabled state to assistive technologies, even when the label is interactive.

💡 Proposed fix
-      <Label variant="outline" isDisabled={isCallbackProcessing} aria-disabled={true}>
+      <Label variant="outline" isDisabled={isCallbackProcessing} aria-disabled={isCallbackProcessing}>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`
at line 124, The Label component currently hardcodes aria-disabled to true which
incorrectly announces it as disabled; update the Label usage in
RoleAssignmentStatusComponent so aria-disabled reflects the real state (e.g.,
aria-disabled={isCallbackProcessing}) or remove the aria-disabled prop entirely
and rely on isDisabled for semantics, ensuring the component's accessible state
matches the isCallbackProcessing flag.

171-172: ⚠️ Potential issue | 🟡 Minor

Localize spinner aria-label strings.

Both spinner aria-label values are hardcoded in English and should use t(...) for localized accessibility text.

Also applies to: 211-212

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

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`
around lines 171 - 172, The Spinner aria-labels in RoleAssignmentStatusComponent
are hardcoded English strings; update both occurrences where icon={<Spinner
isInline aria-label="..."/>} to use the translation function (e.g.
aria-label={t('Creating common projects for the role assignment clusters')}) and
add corresponding i18n keys used by label props (same keys or appropriately
named ones) so the accessibility strings are localized — check both the
occurrence around the icon prop with label={t('Creating common projects')} and
the duplicate occurrence later (the other icon/label pair around lines ~211-212)
and ensure keys are added to the translation files.

43-49: ⚠️ Potential issue | 🟠 Major

Button fallback path is still a no-op; disable action when callback is unavailable.

When callback is missing, the current handler returns a function instead of executing logic, and the button remains clickable. This leaves a dead action in the UI.

💡 Proposed fix
       onClick={() =>
-        callback
-          ? callback(roleAssignment)
-          : () => console.error('No callback method implemented for reason', roleAssignment.status?.reason)
+        callback ? callback(roleAssignment) : undefined
       }
-      isDisabled={areActionButtonsDisabled}
+      isDisabled={areActionButtonsDisabled || !callback}
       isLoading={isCallbackProcessing}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`
around lines 43 - 49, The onClick currently returns a function when callback is
missing which leaves the button clickable; update RoleAssignmentStatusComponent
so onClick directly calls callback(roleAssignment) when callback exists and
otherwise set onClick to undefined (or null), and ensure the button's disabled
prop uses areActionButtonsDisabled || !callback (i.e. set
isDisabled={areActionButtonsDisabled || !callback}) so actions are truly
disabled when callback is unavailable; keep isLoading as is
(isCallbackProcessing).
frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.tsx (1)

91-95: ⚠️ Potential issue | 🟠 Major

Fix toast interpolation key mismatch in the error summary message.

The string uses {{project}}/{{cluster}}, but the interpolation object provides projects/clusters. This prevents replacement and shows raw placeholders.

💡 Proposed fix
-          message: t('Error creating missing projects {{project}} for clusters {{cluster}}.', {
+          message: t('Error creating missing projects {{projects}} for clusters {{clusters}}.', {
             clusters: Object.keys(callbackProgress.errorClusterNamespacesMap).join(', '),
             projects: Object.values(callbackProgress.errorClusterNamespacesMap).flat().join(', '),
             errorCount: callbackProgress.errorCount,
           }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.tsx`
around lines 91 - 95, In useRoleAssignmentsStatusHook.tsx update the toast
message template to match the interpolation object: replace the placeholders
{{project}} and {{cluster}} with the plural forms {{projects}} and {{clusters}}
(the message composed from callbackProgress and its keys like
callbackProgress.errorClusterNamespacesMap and callbackProgress.errorCount) so
the values provided in the interpolation object are correctly substituted.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.tsx`:
- Around line 20-27: The current reduction only iterates
Object.keys(clusterNamespaceMap) so any cluster present in clusterNamesSet but
missing from clusterNamespaceMap is skipped; change the iteration to cover all
clusters in clusterNamesSet (e.g., iterate Array.from(clusterNamesSet) or the
union of Object.keys(clusterNamespaceMap) and clusterNamesSet) and then use
const existingNamespaces = clusterNamespaceMap[cluster] ?? [] to compute missing
namespaces against targetNamespaces and populate the accumulator as before
(references: clusterNamespaceMap, clusterNamesSet, targetNamespaces, the reduce
block).

---

Duplicate comments:
In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`:
- Line 124: The Label component currently hardcodes aria-disabled to true which
incorrectly announces it as disabled; update the Label usage in
RoleAssignmentStatusComponent so aria-disabled reflects the real state (e.g.,
aria-disabled={isCallbackProcessing}) or remove the aria-disabled prop entirely
and rely on isDisabled for semantics, ensuring the component's accessible state
matches the isCallbackProcessing flag.
- Around line 171-172: The Spinner aria-labels in RoleAssignmentStatusComponent
are hardcoded English strings; update both occurrences where icon={<Spinner
isInline aria-label="..."/>} to use the translation function (e.g.
aria-label={t('Creating common projects for the role assignment clusters')}) and
add corresponding i18n keys used by label props (same keys or appropriately
named ones) so the accessibility strings are localized — check both the
occurrence around the icon prop with label={t('Creating common projects')} and
the duplicate occurrence later (the other icon/label pair around lines ~211-212)
and ensure keys are added to the translation files.
- Around line 43-49: The onClick currently returns a function when callback is
missing which leaves the button clickable; update RoleAssignmentStatusComponent
so onClick directly calls callback(roleAssignment) when callback exists and
otherwise set onClick to undefined (or null), and ensure the button's disabled
prop uses areActionButtonsDisabled || !callback (i.e. set
isDisabled={areActionButtonsDisabled || !callback}) so actions are truly
disabled when callback is unavailable; keep isLoading as is
(isCallbackProcessing).

In
`@frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.tsx`:
- Around line 91-95: In useRoleAssignmentsStatusHook.tsx update the toast
message template to match the interpolation object: replace the placeholders
{{project}} and {{cluster}} with the plural forms {{projects}} and {{clusters}}
(the message composed from callbackProgress and its keys like
callbackProgress.errorClusterNamespacesMap and callbackProgress.errorCount) so
the values provided in the interpolation object are correctly substituted.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 1cbadc5 and cc22817.

📒 Files selected for processing (5)
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/useRoleAssignmentsStatusHook.tsx

Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
@Ginxo
Copy link
Contributor Author

Ginxo commented Feb 26, 2026

/test pr-image-mirror-mce

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx (1)

213-214: ⚠️ Potential issue | 🟡 Minor

Localize pending spinner aria-label.

The pending-state spinner still uses a hardcoded English aria-label. This should go through t(...) like the other spinner label.

Proposed fix
-          icon={<Spinner isInline aria-label="Role Assignment being applied" />}
+          icon={<Spinner isInline aria-label={t('Role Assignment being applied')} />}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`
around lines 213 - 214, The Spinner's aria-label is hardcoded; update the
Spinner in RoleAssignmentStatusComponent so its aria-label is localized via the
i18n translator (use the existing t(...) call pattern), e.g. replace the inline
string in the Spinner prop with a call to t(...) (same key used for label or a
specific key like 'RoleAssignment.pending'/'RoleAssignment.pendingAria') so both
label and aria-label come from t(...) and remain consistent.
🧹 Nitpick comments (3)
frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx (2)

36-39: Make missing-project detection more robust to message casing/wording.

The message heuristic is case-sensitive and tightly tied to one phrasing. Normalizing case (and matching namespace/namespaces) reduces false negatives for showing the recovery action.

Proposed hardening
-  const isMissingNamespaces =
-    roleAssignment.status?.reason === 'MissingNamespaces' ||
-    (roleAssignment.status?.message?.includes('namespaces') && roleAssignment.status?.message?.includes('not found'))
+  const normalizedMessage = roleAssignment.status?.message?.toLowerCase() ?? ''
+  const isMissingNamespaces =
+    roleAssignment.status?.reason === 'MissingNamespaces' ||
+    (normalizedMessage.includes('namespace') && normalizedMessage.includes('not found'))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`
around lines 36 - 39, The current isMissingNamespaces check relies on a
case-sensitive, exact message phrase and misses variants; update the heuristic
in RoleAssignmentStatusComponent by normalizing roleAssignment.status?.message
to a lowercase string (guarding for undefined) and then testing includes for
'namespace' OR 'namespaces' and 'not found' (all lowercase), while still
preserving the existing explicit reason === 'MissingNamespaces' check; reference
the isMissingNamespaces variable and roleAssignment.status?.message to implement
this more robust matching.

134-142: JSDoc is stale relative to current props.

The comment still documents removed fields (status, callbackProgress.*). Updating this block to current props will avoid API confusion.

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

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`
around lines 134 - 142, The JSDoc above RoleAssignmentStatusComponent is stale:
remove references to the removed props (status and callbackProgress.*) and
update the doc to match the component's current props interface; specifically,
ensure callbacksPerReasonMap (and any other actual props defined in the
RoleAssignmentStatusComponent props/type) are documented with accurate types and
descriptions, and remove or replace outdated entries so the JSDoc mirrors the
actual Prop type used by RoleAssignmentStatusComponent.
frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.test.tsx (1)

235-304: Add regression coverage for missing-callback disabled state.

This suite validates areActionButtonsDisabled, but it doesn’t assert the !callback disable path. A small test here would lock in the fix and prevent button re-enablement regressions.

Suggested test addition
+    it('disables Create missing projects button when callback is not provided', () => {
+      render(
+        <RoleAssignmentStatusComponent
+          roleAssignment={createBaseRoleAssignment({
+            ...baseStatus,
+            status: 'Error',
+            reason: 'MissingNamespaces',
+            message: 'Missing',
+          })}
+        />
+      )
+      expect(screen.getByRole('button', { name: 'Create missing projects' })).toBeDisabled()
+    })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.test.tsx`
around lines 235 - 304, Add a test in RoleAssignmentStatusComponent.test.tsx
that asserts the "Create missing projects" button is disabled when the component
lacks a callback for MissingNamespaces (i.e., callbacksPerReasonMap is undefined
or does not include MissingNamespaces): render RoleAssignmentStatusComponent
with status 'Error' and reason 'MissingNamespaces' but without
callbacksPerReasonMap (or with an empty map), then assert the button is disabled
and that clicking it does not call any callback; reference
RoleAssignmentStatusComponent, prop callbacksPerReasonMap, and prop
areActionButtonsDisabled to ensure you cover the "no-callback" disable path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.tsx`:
- Around line 70-126: The current creation loop blows up into an unbounded
fan-out by calling fireManagedClusterActionCreate for every namespace at once;
change it to use bounded concurrency (e.g., a concurrency limit constant like
MAX_CONCURRENCY = 5) and process missingNamespacesPerCluster with a
concurrency-controlled runner (per-cluster or global) that schedules at most
MAX_CONCURRENCY outstanding fireManagedClusterActionCreate promises at a time,
preserving the existing .then/.catch/.finally handling (including counter
updates, errorClusterNamespacesMap, addAlertCallback and onProgressCallback) so
progress and error reporting remain identical; locate the logic around
missingNamespacesPerCluster and fireManagedClusterActionCreate in
roleAssignmentErrorHandlingFunctions.tsx and replace the
Promise.all(flatMap(...)) fan-out with a bounded queue/pool or a small
p-limit-like helper to throttle concurrent calls.
- Around line 20-23: Deduplicate targetNamespaces before doing the diff to avoid
scheduling duplicates: inside the reduce that iterates
Array.from(clusterNamesSet) (the block referencing clusterNamespaceMap and
targetNamespaces), replace uses of targetNamespaces with a deduplicated version
(e.g., create const uniqueTargetNamespaces = Array.from(new
Set(targetNamespaces)) prior to the reduce or at the top of the reducer) and use
uniqueTargetNamespaces when computing missing = uniqueTargetNamespaces.filter(ns
=> !existingNamespaces.includes(ns)) so progress/errors/counts aren't inflated
by duplicates.

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`:
- Around line 191-203: The ExpandableSection in RoleAssignmentStatusComponent
currently renders roleAssignment.status?.message directly, which can be empty
and overrides the StatusTooltip fallback; update the bodyContent so the
ExpandableSection displays roleAssignment.status?.message if present, otherwise
render the same fallback string used by StatusTooltip (reuse the same
translation/key or constant used elsewhere in this component for missing
details) and keep existing props (isErrorExpanded, onErrorToggle) intact.

---

Duplicate comments:
In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`:
- Around line 213-214: The Spinner's aria-label is hardcoded; update the Spinner
in RoleAssignmentStatusComponent so its aria-label is localized via the i18n
translator (use the existing t(...) call pattern), e.g. replace the inline
string in the Spinner prop with a call to t(...) (same key used for label or a
specific key like 'RoleAssignment.pending'/'RoleAssignment.pendingAria') so both
label and aria-label come from t(...) and remain consistent.

---

Nitpick comments:
In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.test.tsx`:
- Around line 235-304: Add a test in RoleAssignmentStatusComponent.test.tsx that
asserts the "Create missing projects" button is disabled when the component
lacks a callback for MissingNamespaces (i.e., callbacksPerReasonMap is undefined
or does not include MissingNamespaces): render RoleAssignmentStatusComponent
with status 'Error' and reason 'MissingNamespaces' but without
callbacksPerReasonMap (or with an empty map), then assert the button is disabled
and that clicking it does not call any callback; reference
RoleAssignmentStatusComponent, prop callbacksPerReasonMap, and prop
areActionButtonsDisabled to ensure you cover the "no-callback" disable path.

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`:
- Around line 36-39: The current isMissingNamespaces check relies on a
case-sensitive, exact message phrase and misses variants; update the heuristic
in RoleAssignmentStatusComponent by normalizing roleAssignment.status?.message
to a lowercase string (guarding for undefined) and then testing includes for
'namespace' OR 'namespaces' and 'not found' (all lowercase), while still
preserving the existing explicit reason === 'MissingNamespaces' check; reference
the isMissingNamespaces variable and roleAssignment.status?.message to implement
this more robust matching.
- Around line 134-142: The JSDoc above RoleAssignmentStatusComponent is stale:
remove references to the removed props (status and callbackProgress.*) and
update the doc to match the component's current props interface; specifically,
ensure callbacksPerReasonMap (and any other actual props defined in the
RoleAssignmentStatusComponent props/type) are documented with accurate types and
descriptions, and remove or replace outdated entries so the JSDoc mirrors the
actual Prop type used by RoleAssignmentStatusComponent.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between cc22817 and 0a84cde.

📒 Files selected for processing (8)
  • frontend/public/locales/en/translation.json
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.tsx
  • frontend/src/ui-components/AcmAlert/AcmAlert.test.tsx
  • frontend/src/ui-components/AcmAlert/AcmAlert.tsx
  • frontend/src/ui-components/AcmAlert/AcmToast.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.test.tsx

Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx (1)

210-217: ⚠️ Potential issue | 🟡 Minor

Localize the Spinner aria-label for the Pending state.

The Spinner at line 213 uses a hardcoded English aria-label ("Role Assignment being applied"), while the Spinner at line 173 correctly uses the localized version via t(). This should be consistent for accessibility in non-English locales.

🔧 Proposed fix
     case roleAssignment.status?.status === 'Pending':
       return (
         <StatusTooltip
-          icon={<Spinner isInline aria-label="Role Assignment being applied" />}
+          icon={<Spinner isInline aria-label={t('Role Assignment being applied')} />}
           label={t('Pending')}
           {...commonStatusTooltipProps}
         />
       )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`
around lines 210 - 217, In RoleAssignmentStatusComponent.tsx update the
Pending-state Spinner to use the localized aria-label instead of the hardcoded
English string: replace the literal "Role Assignment being applied" passed to
Spinner's aria-label with the result of the translation function t(...)
(matching the pattern used by the other Spinner in this component), so the
aria-label is localized for non-English locales.
🧹 Nitpick comments (1)
frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.tsx (1)

78-114: Consider extracting duplicate error handling logic.

The error handling in the .then() branch (lines 82-96) and .catch() branch (lines 100-114) contains nearly identical code for incrementing counter.error, updating errorClusterNamespacesMap, and calling addAlertCallback. This could be extracted to a helper function.

♻️ Suggested refactor
+    const handleError = (clusterName: string, namespace: string, errorMessage: string) => {
+      counter.error++
+      counter.errorClusterNamespacesMap[clusterName] = [
+        ...(counter.errorClusterNamespacesMap[clusterName] || []),
+        namespace,
+      ]
+      addAlertCallback({
+        title: t('Error creating missing project'),
+        message: t('Error creating missing project {{project}} for cluster {{cluster}}. Error: {{error}}.', {
+          project: namespace,
+          cluster: clusterName,
+          error: errorMessage,
+        }),
+        type: 'danger',
+        autoClose: true,
+      })
+    }
+
     const createMissingProject = (clusterName: string, namespace: string) =>
       fireManagedClusterActionCreate(clusterName, {
         apiVersion: ProjectRequestApiVersion,
         kind: ProjectRequestKind,
         metadata: { name: namespace },
       })
         .then((actionResponse) => {
           if (actionResponse.actionDone === 'ActionDone') {
             counter.success++
           } else {
-            counter.error++
-            counter.errorClusterNamespacesMap[clusterName] = [
-              ...(counter.errorClusterNamespacesMap[clusterName] || []),
-              namespace,
-            ]
-            addAlertCallback({
-              title: t('Error creating missing project'),
-              message: t('Error creating missing project {{project}} for cluster {{cluster}}. Error: {{error}}.', {
-                project: namespace,
-                cluster: clusterName,
-                error: actionResponse.message,
-              }),
-              type: 'danger',
-              autoClose: true,
-            })
+            handleError(clusterName, namespace, actionResponse.message ?? 'Unknown error')
           }
         })
-        .catch((err: Error) => {
-          counter.error++
-          counter.errorClusterNamespacesMap[clusterName] = [
-            ...(counter.errorClusterNamespacesMap[clusterName] || []),
-            namespace,
-          ]
-          addAlertCallback({
-            title: t('Error creating missing project'),
-            message: t('Error creating missing project {{project}} for cluster {{cluster}}. Error: {{error}}.', {
-              project: namespace,
-              cluster: clusterName,
-              error: err.message,
-            }),
-            type: 'danger',
-            autoClose: true,
-          })
-        })
+        .catch((err: Error) => handleError(clusterName, namespace, err.message))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.tsx`
around lines 78 - 114, Extract the duplicate error handling into a helper (e.g.,
handleActionError) that accepts (clusterName: string, namespace: string,
errorMessage: string) and performs the shared work: increment counter.error,
update counter.errorClusterNamespacesMap[clusterName] by appending namespace,
and call addAlertCallback with the t(...) translated title and message using
errorMessage; then replace the duplicated blocks inside the .then() branch
(where actionResponse.actionDone !== 'ActionDone') and the .catch((err) => ...)
to call handleActionError(clusterName, namespace, actionResponse.message) or
handleActionError(clusterName, namespace, err.message) respectively so behavior
remains identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`:
- Around line 210-217: In RoleAssignmentStatusComponent.tsx update the
Pending-state Spinner to use the localized aria-label instead of the hardcoded
English string: replace the literal "Role Assignment being applied" passed to
Spinner's aria-label with the result of the translation function t(...)
(matching the pattern used by the other Spinner in this component), so the
aria-label is localized for non-English locales.

---

Nitpick comments:
In
`@frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.tsx`:
- Around line 78-114: Extract the duplicate error handling into a helper (e.g.,
handleActionError) that accepts (clusterName: string, namespace: string,
errorMessage: string) and performs the shared work: increment counter.error,
update counter.errorClusterNamespacesMap[clusterName] by appending namespace,
and call addAlertCallback with the t(...) translated title and message using
errorMessage; then replace the duplicated blocks inside the .then() branch
(where actionResponse.actionDone !== 'ActionDone') and the .catch((err) => ...)
to call handleActionError(clusterName, namespace, actionResponse.message) or
handleActionError(clusterName, namespace, err.message) respectively so behavior
remains identical.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 0a84cde and 8ed809d.

📒 Files selected for processing (4)
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.tsx

Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.test.tsx (1)

248-260: Add callback-assertion coverage for the message-based fallback path.

Line 248 currently verifies only button visibility when reason is ApplicationFailed and message contains missing-namespace text. Add a click assertion for this branch too, so regressions don’t slip through when callback routing changes.

💡 Suggested test addition
+    it('invokes MissingNamespaces callback when reason is ApplicationFailed but message indicates missing namespaces', () => {
+      const onMissingNamespaces = jest.fn()
+      render(
+        <RoleAssignmentStatusComponent
+          roleAssignment={createBaseRoleAssignment({
+            ...baseStatus,
+            status: 'Error',
+            reason: 'ApplicationFailed',
+            message: 'Required namespaces not found on cluster',
+          })}
+          callbacksPerReasonMap={{
+            MissingNamespaces: onMissingNamespaces,
+          }}
+        />
+      )
+      screen.getByRole('button', { name: 'Create missing projects' }).click()
+      expect(onMissingNamespaces).toHaveBeenCalledTimes(1)
+    })

Also applies to: 278-301

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

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.test.tsx`
around lines 248 - 260, The test only checks visibility of the "Create missing
projects" button but not that clicking it calls the component callback; update
the RoleAssignmentStatusComponent tests (the case at lines around 248 and the
similar case around 278-301) to pass a jest.fn() handler (e.g. const
onCreateMissing = jest.fn()) into the component, render the component with that
prop, find the button by role/name, simulate a click (userEvent.click or
fireEvent.click) and assert the mock was called
(expect(onCreateMissing).toHaveBeenCalled()). Ensure you import and use
userEvent or fireEvent and replace the existing visibility-only assertions with
both visibility and click-callback assertions for RoleAssignmentStatusComponent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`:
- Around line 134-142: Update the stale JSDoc for RoleAssignmentStatusComponent
to match the exported prop names and shapes: replace references to "status" and
"callbackProgress.*" with the actual props "roleAssignment" (describe its
expected shape or type), "callbacksPerReasonMap" (map of reason -> callback),
"isCallbackProcessing" (boolean) and "areActionButtonsDisabled" (boolean);
ensure param tags match exact prop identifiers used in the component and remove
or adjust any outdated nested fields like
callbackProgress.successCount/errorCount/totalCount so the docblock accurately
reflects the current component API (RoleAssignmentStatusComponent and its prop
names).

---

Nitpick comments:
In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.test.tsx`:
- Around line 248-260: The test only checks visibility of the "Create missing
projects" button but not that clicking it calls the component callback; update
the RoleAssignmentStatusComponent tests (the case at lines around 248 and the
similar case around 278-301) to pass a jest.fn() handler (e.g. const
onCreateMissing = jest.fn()) into the component, render the component with that
prop, find the button by role/name, simulate a click (userEvent.click or
fireEvent.click) and assert the mock was called
(expect(onCreateMissing).toHaveBeenCalled()). Ensure you import and use
userEvent or fireEvent and replace the existing visibility-only assertions with
both visibility and click-callback assertions for RoleAssignmentStatusComponent.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 8ed809d and d0e8fc3.

📒 Files selected for processing (3)
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.test.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx
  • frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/routes/UserManagement/RoleAssignment/roleAssignmentErrorHandlingFunctions.tsx

Comment on lines 134 to 142
/** Props for the RoleAssignmentStatusComponent
* @param status - The status of the role assignment
* @param callbacksPerReasonMap - A map of callbacks per reason. The key is the reason and the value is the callback function. This is used to display the callback button in the status tooltip.
* @param callbackProgress - The status of the callback processing
* @param callbackProgress.isProcessing - Whether the callback processing is in progress
* @param callbackProgress.successCount - The number of successful callbacks
* @param callbackProgress.errorCount - The number of error callbacks
* @param callbackProgress.totalCount - The total number of callbacks
*/
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Props docblock is stale and mismatched with the exported type.

Line 135+ still documents status and callbackProgress.*, but the actual props are roleAssignment, callbacksPerReasonMap, isCallbackProcessing, and areActionButtonsDisabled. This will mislead consumers and reviewers.

📝 Suggested doc update
-/** Props for the RoleAssignmentStatusComponent
- * `@param` status - The status of the role assignment
- * `@param` callbacksPerReasonMap - A map of callbacks per reason. The key is the reason and the value is the callback function. This is used to display the callback button in the status tooltip.
- * `@param` callbackProgress - The status of the callback processing
- * `@param` callbackProgress.isProcessing - Whether the callback processing is in progress
- * `@param` callbackProgress.successCount - The number of successful callbacks
- * `@param` callbackProgress.errorCount - The number of error callbacks
- * `@param` callbackProgress.totalCount - The total number of callbacks
- */
+/** Props for the RoleAssignmentStatusComponent
+ * `@param` roleAssignment - Flattened role assignment row object used for status rendering
+ * `@param` callbacksPerReasonMap - Optional callback per status reason for footer actions
+ * `@param` isCallbackProcessing - Whether a reason callback action is currently running
+ * `@param` areActionButtonsDisabled - Disables action buttons in tooltip footer
+ */
📝 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
/** Props for the RoleAssignmentStatusComponent
* @param status - The status of the role assignment
* @param callbacksPerReasonMap - A map of callbacks per reason. The key is the reason and the value is the callback function. This is used to display the callback button in the status tooltip.
* @param callbackProgress - The status of the callback processing
* @param callbackProgress.isProcessing - Whether the callback processing is in progress
* @param callbackProgress.successCount - The number of successful callbacks
* @param callbackProgress.errorCount - The number of error callbacks
* @param callbackProgress.totalCount - The total number of callbacks
*/
/** Props for the RoleAssignmentStatusComponent
* `@param` roleAssignment - Flattened role assignment row object used for status rendering
* `@param` callbacksPerReasonMap - Optional callback per status reason for footer actions
* `@param` isCallbackProcessing - Whether a reason callback action is currently running
* `@param` areActionButtonsDisabled - Disables action buttons in tooltip footer
*/
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/routes/UserManagement/RoleAssignment/RoleAssignmentStatusComponent.tsx`
around lines 134 - 142, Update the stale JSDoc for RoleAssignmentStatusComponent
to match the exported prop names and shapes: replace references to "status" and
"callbackProgress.*" with the actual props "roleAssignment" (describe its
expected shape or type), "callbacksPerReasonMap" (map of reason -> callback),
"isCallbackProcessing" (boolean) and "areActionButtonsDisabled" (boolean);
ensure param tags match exact prop identifiers used in the component and remove
or adjust any outdated nested fields like
callbackProgress.successCount/errorCount/totalCount so the docblock accurately
reflects the current component API (RoleAssignmentStatusComponent and its prop
names).

const { t } = useTranslation()
const callback = roleAssignment.status?.reason ? callbacksPerReasonMap?.[roleAssignment.status.reason] : undefined

const isMissingNamespaces =
Copy link
Contributor Author

Choose a reason for hiding this comment

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

temporary solution while backend is offering more error granularity

Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
Signed-off-by: Enrique Mingorance Cano <emingora@redhat.com>
@openshift-ci
Copy link

openshift-ci bot commented Feb 26, 2026

@Ginxo: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/unit-tests-sonarcloud 9285ad2 link true /test unit-tests-sonarcloud

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant