Skip to content

feat(admin-ui): revamp User Claims module as per Figma (#2632)#2701

Merged
moabu merged 12 commits intomainfrom
admin-ui-issue-2632
Mar 18, 2026
Merged

feat(admin-ui): revamp User Claims module as per Figma (#2632)#2701
moabu merged 12 commits intomainfrom
admin-ui-issue-2632

Conversation

@faisalsiddique4400
Copy link
Contributor

@faisalsiddique4400 faisalsiddique4400 commented Mar 16, 2026

feat(admin-ui): revamp User Claims module as per Figma (#2632)

Summary

This PR revamps the User Claims module in the Admin UI to align with the latest Figma designs as part of the ongoing Admin UI redesign initiative.

Changes Included

  • Updated layout and visual styling according to Figma specifications.
  • Improved information hierarchy and form structure.
  • Standardized spacing, typography, and alignment with the updated design system.
  • Enhanced usability for managing and configuring user claims.
  • Ensured responsive behavior and consistent UI interactions.

Result

  • Modernized and visually consistent User Claims module.
  • Improved clarity and usability for administrators managing claim configurations.
  • Better alignment with the overall Admin UI redesign effort.

Parent Initiative

This work is part of the following parent feature:
feat(admin-ui): Revamp the existing design of the admin-ui according to the new design

🔗 Ticket

Closes: #2632

Summary by CodeRabbit

  • New Features

    • Keyboard-accessible multi-select control and full "User Claims" pages: list, add, edit, view.
  • Improvements

    • UI relabeled to "User Claims" across listings, tooltips and titles.
    • Redesigned, theme-aware form layouts with dark-mode support and an added status color variant.
    • Expanded validation messages and translations (EN/ES/FR/PT) for clearer form guidance.
  • Bug Fixes

    • More consistent browser autofill styling for inputs and textareas.

Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 16, 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

Replaces legacy Attribute pages with a new User Claims feature (list/add/edit/view/detail), adds Formik-based UserClaimsForm and GluuMultiSelectRow, introduces attribute CRUD react-query hooks and mutation-effects, updates theming/styles, expands locale keys, refactors validation to static i18n keys, and adds/removes tests accordingly.

Changes

Cohort / File(s) Summary
Color & Global Styles
admin-ui/app/customColors.ts, admin-ui/app/styles/main.scss, admin-ui/plugins/scripts/components/CustomScripts/styles/CustomScriptFormPage.style.ts
Added statusActiveBgDark color token, autofill overrides, and tightened focus-visible outline/box-shadow specificity.
Gluu Multi-Select Component
admin-ui/app/routes/Apps/Gluu/GluuMultiSelectRow.tsx, admin-ui/app/routes/Apps/Gluu/styles/GluuMultiSelectRow.style.ts, admin-ui/app/routes/Apps/Gluu/types/GluuMultiSelectRow.types.ts
New accessible, themed, Formik-integrated multi-select component with types and styles.
Localization
admin-ui/app/locales/en/translation.json, .../es/translation.json, .../fr/translation.json, .../pt/translation.json
Added user-claim related titles/messages/tooltips, multi-select hint, validation/error keys, success messages, and menu entry across locales.
Schema hooks & API surface
admin-ui/plugins/schema/hooks/useAttributeApi.ts, admin-ui/plugins/schema/hooks/useMutationEffects.ts, admin-ui/plugins/schema/hooks/useSchemaWebhook.ts, admin-ui/plugins/schema/hooks/useSchemaAuditLogger.ts, admin-ui/plugins/schema/hooks/index.ts, admin-ui/plugins/schema/constants/index.ts
New attribute CRUD hooks (list/get/create/update/delete), toAttributeList, mutation-effects utility, webhook/audit integrations, cache/query constants, and a hooks barrel export.
User Claims pages & routing
admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx, .../UserClaimsAddPage.tsx, .../UserClaimsEditPage.tsx, .../UserClaimsViewPage.tsx, .../UserClaimsDetailPage.tsx, admin-ui/plugins/schema/plugin-metadata.ts
Added full set of UserClaims pages and wired plugin routes; pages use react-query, permission checks, theming, and mutation flows.
User Claims form & styles
admin-ui/plugins/schema/components/Person/UserClaimsForm.tsx, .../styles/UserClaimsFormPage.style.ts, .../styles/UserClaimsListPage.style.ts
New Formik-based UserClaimsForm with validation toggle, multi-column layout, Gluu row components, commit/footer flow, and themed styles for form and list pages.
Refactored Attribute components
admin-ui/plugins/schema/components/Person/AttributeAddPage.tsx, .../AttributeEditPage.tsx, .../AttributeDetailPage.tsx, .../AttributeListPage.tsx, .../AttributeViewPage.tsx, .../AttributeForm.tsx
Refactored legacy Attribute pages to use new hooks, theming and Gluu components; exports changed to memoized defaults in several places.
Validation & form helpers
admin-ui/plugins/schema/utils/validation.ts, admin-ui/plugins/schema/utils/formHelpers.ts
Switched validation messages to static i18n key strings (removed t param), adjusted transforms, and updated type import targets to UserClaims types.
Types, utilities & minor edits
admin-ui/app/redux/types/index.ts, admin-ui/app/utilities.tsx, admin-ui/plugins/admin/components/Assets/types/FormTypes.ts, admin-ui/plugins/user-management/utils/attributeTransformUtils.ts, admin-ui/app/routes/Apps/Gluu/GluuTabs.tsx
Small formatting/type declaration tweaks; no behavioral changes.
Tests
admin-ui/plugins/schema/__tests__/components/*
Removed several legacy Attribute tests and added comprehensive UserClaims tests (add/edit/form/list) covering UI, loading/error states, and mutation flows.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Page as UserClaimsFormPage
    participant Theme as ThemeContext
    participant Form as UserClaimsForm (Formik)
    participant Hooks as useAttributeApi
    participant Mutation as ReactQuery Mutation
    participant Redux as Redux/Toast

    User->>Page: Open Add/Edit page
    Page->>Theme: read themeColors/isDark
    Theme-->>Page: theme data
    Page->>Form: init values & validation
    User->>Form: edit fields
    Form->>Formik: update values
    User->>Form: submit
    Form->>Hooks: call create/update mutateAsync
    Hooks->>Mutation: perform HTTP request
    alt Success
        Mutation->>Hooks: returns success
        Hooks->>Redux: dispatch success toast
        Hooks->>Mutation: invalidate queries
    else Error
        Mutation->>Hooks: returns error
        Hooks->>Redux: dispatch error toast
    end
Loading
sequenceDiagram
    actor User
    participant List as UserClaimsListPage
    participant Hooks as useAttributes/useDeleteAttribute
    participant Query as ReactQuery
    participant API as Backend
    participant Table as GluuTable
    participant Modal as ConfirmDialog

    User->>List: Load page
    List->>Hooks: useAttributes(params)
    Hooks->>Query: fetch (cached)
    Query->>API: GET /api/v1/attributes/
    API-->>Query: attributes
    Query-->>List: data
    List->>Table: render rows
    User->>Table: click delete
    Table->>Modal: open confirm
    User->>Modal: confirm
    Modal->>Hooks: delete.mutateAsync(inum)
    Hooks->>API: DELETE /api/v1/attributes/{inum}
    API-->>Hooks: success
    Hooks->>Query: invalidate & refetch
    Hooks->>Redux: dispatch success toast
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested reviewers

  • duttarnab
  • moabu

Poem

🐇
I hopped through props and Formik rows,
Bright themes and hooks where data flows.
Chips that glint and badges softly gleam,
Locale strings whisper in a multilingual dream.
A tiny rabbit cheers your refactor team!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: a revamp of the User Claims module to align with Figma designs, which is directly reflected in the substantial refactoring of multiple User Claims components and supporting infrastructure throughout the changeset.
Linked Issues check ✅ Passed The PR comprehensively addresses issue #2632 by revamping the User Claims module with updated UI components, improved form structure, standardized styling, enhanced usability, and responsive interactions aligned with Figma specifications.
Out of Scope Changes check ✅ Passed All changes are directly related to the User Claims module revamp objective. Minor supporting changes to validation schemas, hooks, and styling infrastructure are necessary to support the new User Claims components and do not introduce unrelated functionality.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch admin-ui-issue-2632
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@mo-auto mo-auto added the comp-admin-ui Component affected by issue or PR label Mar 16, 2026
Copy link
Contributor

@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: 21

Caution

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

⚠️ Outside diff range comments (2)
admin-ui/plugins/schema/utils/validation.ts (1)

64-78: ⚠️ Potential issue | 🟠 Major

Allow minLength === maxLength; current predicate rejects valid exact-length constraints.

At Line 77, return value < maxLengthFromParent fails when values are equal, but the error key at Line 66 indicates only “min greater than max” should fail. Equality should pass.

Suggested fix
-                    return value < maxLengthFromParent
+                    return value <= maxLengthFromParent
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@admin-ui/plugins/schema/utils/validation.ts` around lines 64 - 78, The
'min-max' schema.test predicate currently rejects equal min/max because it
returns value < maxLengthFromParent; update the predicate in the
schema.test('min-max', ...) function so it allows equality by returning value <=
maxLengthFromParent (i.e., treat minLength === maxLength as valid), preserving
the existing null/undefined guards and error message key
'errors.min_greater_than_max'.
admin-ui/plugins/schema/components/Person/AttributeAddPage.tsx (1)

61-72: 🧹 Nitpick | 🔵 Trivial

Consider extracting defaultAttribute as a module constant.

The default attribute object is recreated on each render. Since it's static, extracting it outside the component improves clarity and avoids unnecessary object allocations.

Suggested extraction
+const DEFAULT_ATTRIBUTE: Partial<AttributeItem> = {
+  jansHideOnDiscovery: false,
+  selected: false,
+  scimCustomAttr: false,
+  oxMultiValuedAttribute: false,
+  custom: false,
+  required: false,
+  attributeValidation: { maxLength: null, regexp: null, minLength: null },
+  editType: [],
+  viewType: [],
+  usageType: [],
+}
+
 function AttributeAddPage(): JSX.Element {
   // ...
-  const defaultAttribute: Partial<AttributeItem> = {
-    jansHideOnDiscovery: false,
-    selected: false,
-    scimCustomAttr: false,
-    oxMultiValuedAttribute: false,
-    custom: false,
-    required: false,
-    attributeValidation: { maxLength: null, regexp: null, minLength: null },
-    editType: [],
-    viewType: [],
-    usageType: [],
-  }
   // ...
-              <AttributeForm item={defaultAttribute as AttributeItem} customOnSubmit={onSubmit} />
+              <AttributeForm item={DEFAULT_ATTRIBUTE as AttributeItem} customOnSubmit={onSubmit} />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@admin-ui/plugins/schema/components/Person/AttributeAddPage.tsx` around lines
61 - 72, Extract the inline defaultAttribute object out of the component as a
top-level module constant (e.g., const DEFAULT_ATTRIBUTE: Partial<AttributeItem>
= { ... }) and replace the in-component declaration in AttributeAddPage with a
reference to that constant; when creating a new attribute instance inside the
component, use a shallow copy (e.g., { ...DEFAULT_ATTRIBUTE }) to avoid shared
mutable state and preserve the Partial<AttributeItem> type.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@admin-ui/app/locales/en/translation.json`:
- Line 807: The user-facing string for the JSON key "multi_select_hint" contains
awkward phrasing ("appeared dropdown"); update messages.multi_select_hint to a
grammatically correct copy such as "Enter multiple items by selecting each one
from the dropdown that appears after typing an item." or equivalent clear
phrasing, ensuring you replace the existing value for "multi_select_hint" in
translation.json.

In `@admin-ui/app/locales/fr/translation.json`:
- Line 773: Update the French copy for the "multi_select_hint" key to a more
natural UI phrasing: replace the current string with something like "Saisissez
plusieurs éléments en les sélectionnant dans la liste déroulante qui s'affiche
après chaque saisie." so the hint reads smoothly in French and avoids the
awkward "menu déroulant apparu."

In `@admin-ui/app/routes/Apps/Gluu/GluuMultiSelectRow.tsx`:
- Around line 165-184: The option elements rendered in the options.map block are
not keyboard accessible: add tabIndex={0} to the option container (the div using
classes.optionItem and role="option") and attach an onKeyDown handler that
listens for Enter and Space keys and calls handleOptionClick(option.value)
(preventDefault for Space to avoid page scroll); ensure aria-selected remains
set and the same isSelected logic and
classes.optionItemSelected/classes.checkboxChecked are preserved so keyboard
users can focus and activate options consistently.
- Around line 13-24: The CheckIcon SVG is missing an accessible title; update
the CheckIcon component to include a <title> element with a unique id and wire
it to the SVG via aria-labelledby (and set role="img") so assistive tech can
read the icon, or if it truly is decorative set aria-hidden="true" instead;
reference the CheckIcon component and its SVG element and ensure the title id is
deterministic (e.g., "check-icon-title") or generated and the
CheckIcon.displayName remains unchanged.

In `@admin-ui/app/routes/Apps/Gluu/styles/GluuMultiSelectRow.style.ts`:
- Around line 24-43: The selectTrigger style currently removes the outline and
lacks a visible keyboard focus indicator—restore a visible interactive state by
either not removing outline in selectTrigger or by enhancing its
'&:focus-within' to apply a clear focus treatment (e.g., noticeable borderColor
and/or boxShadow) so keyboard focus is visible; also update the remove-chip
button selector (the chip remove hover rule referenced on Line 86) to ensure its
hover color contrasts and add a ':focus-visible' rule for that button to provide
the same visible focus styling as the selectTrigger so both keyboard and mouse
interactions are clearly indicated.

In `@admin-ui/app/routes/Apps/Gluu/types/GluuMultiSelectRow.types.ts`:
- Around line 6-9: The GluuMultiSelectRowFormik type narrows Formik's
setFieldValue signature causing type incompatibility; update the
GluuMultiSelectRowFormik type so setFieldValue matches Formik (accepts (field:
string, value: any, shouldValidate?: boolean) => Promise<void> or a permissive
return/type like unknown) or at minimum declare setFieldValue(field: string,
value: string[] | any): unknown to match call sites, and keep handleBlur as is;
modify the type definition (GluuMultiSelectRowFormik) accordingly so real Formik
objects can be passed without TS errors.

In `@admin-ui/plugins/schema/__tests__/components/AttributeEditPage.test.tsx`:
- Around line 45-48: The mocked route param includes an accidental leading
colon; update the jest.mock for useParams so it returns gid without the colon
(useParams: jest.fn(() => ({ gid: 'test-inum-123' }))), ensuring the test uses
the actual param value rather than the route-syntax string in
AttributeEditPage.test.tsx.

In `@admin-ui/plugins/schema/__tests__/components/AttributeForm.test.tsx`:
- Around line 358-369: The test in AttributeForm.test.tsx clicks the Apply
button but never asserts that the commit dialog appears; update the it('triggers
commit dialog flow when Apply is clicked on dirty form') test for AttributeForm
to await and assert the commit dialog is rendered after
fireEvent.click(applyBtn) (e.g. use await screen.findByRole('dialog') or await
screen.findByText(/commit/i) and expect it toBeInTheDocument()/visible) so the
commit dialog flow is actually verified.

In `@admin-ui/plugins/schema/__tests__/components/AttributeListPage.test.tsx`:
- Around line 31-56: The test currently hardcodes the mocked return of
useAttributes inside jest.mock while assertions reference attributes[0], risking
fixture drift; extract a single shared fixture object (e.g., attributesFixture
or mockAttributes) and use that object both in the jest.mock implementation for
useAttributes and in all assertions (replace references to attributes[0] with
the shared fixture reference), and apply the same change to the other assertions
around lines 102-127 so the mock and assertions are driven from the same source.

In `@admin-ui/plugins/schema/components/Person/AttributeDetailPage.tsx`:
- Around line 50-68: AttributeDetailPage currently joins array values for
editType and viewType into a comma-separated string so GluuFormDetailRow renders
them as one badge, causing inconsistency with AttributeListPage which renders
each array item as its own badge; update AttributeDetailPage to map array values
to individual badge entries (for editType and viewType) instead of join,
mirroring the behavior in AttributeListPage, or alternatively confirm
intentional single-badge behavior and add a comment/prop to GluuFormDetailRow to
handle comma-separated strings consistently; look for symbols
AttributeDetailPage, AttributeListPage, editType, viewType and GluuFormDetailRow
to apply the change.

In `@admin-ui/plugins/schema/components/Person/AttributeEditPage.tsx`:
- Around line 87-108: The useMemo hook for computing isBlocking is placed after
an early return (when queryError && !isLoading), violating Rules of Hooks; move
the useMemo call so hooks are invoked unconditionally (e.g., place the const
isBlocking = useMemo(...) before the conditional that returns the error UI) or
compute isBlocking without hooks (inline boolean: const isBlocking = isLoading
|| updateMutation.isPending) above the return; ensure useMemo or the inline
compute references isLoading and updateMutation.isPending and remains in the
same position across all renders in AttributeEditPage (so hooks order is
stable).

In `@admin-ui/plugins/schema/components/Person/AttributeForm.tsx`:
- Around line 387-388: Duplicate comment lines are present in AttributeForm.tsx
(the two identical "Row 7: Multivalued | Hide On Discovery" comments). Edit the
AttributeForm component and remove one of the duplicated comment lines so only a
single comment remains; locate the duplicate near the Row 7 section inside the
AttributeForm JSX and delete the redundant comment.
- Around line 44-51: Replace the untyped useContext(ThemeContext) + repeated
type assertions in AttributeForm.tsx with the typed useTheme hook: import and
call useTheme (from '@/context/theme/themeContext'), remove the manual
ThemeContext usage and assertions, then compute themeColors/isDark inside the
existing useMemo using the typed theme state (falling back to DEFAULT_THEME),
keeping getThemeColor, DEFAULT_THEME and THEME_DARK usage unchanged so the logic
and return values remain the same.

In `@admin-ui/plugins/schema/components/Person/AttributeListPage.tsx`:
- Around line 143-155: handleDeleteConfirm currently accepts an unused _message
parameter and instead builds userMessage from itemToDelete; either remove the
unused _message parameter from the handleDeleteConfirm signature or use it when
calling deleteAttributeMutation.mutateAsync. Update the handleDeleteConfirm
callback (the function named handleDeleteConfirm and the call site that calls
deleteAttributeMutation.mutateAsync) to pass _message (falling back to the
existing `Deleted attribute ${itemToDelete.name ?? itemToDelete.inum}` text if
_message is empty) or remove _message entirely if the caller/interface doesn't
supply a message.
- Around line 467-479: The hardcoded loading={false} on the GluuTable is
confusing because a computed loading variable exists; add a concise inline
comment next to the GluuTable loading prop (or above the table block) that
explains this is intentional: GluuLoader (used in this component) wraps the
table and controls the UI spinner, so the table must receive loading={false} to
avoid double-loading UI; reference the computed loading variable and
GluuLoader/GluuTable by name to make the design explicit for future readers.
- Around line 61-62: Replace the empty-object cast for itemToDelete with a
nullable type: change the state to use itemToDelete: JansAttribute | null and
initialize it to null (keeping modal/setModal as-is), then update every place
that reads or resets itemToDelete (e.g., where setItemToDelete({} as
JansAttribute) or direct property access occurs) to handle null safely or reset
with setItemToDelete(null); ensure components and handlers referencing
itemToDelete check for null before accessing properties.

In `@admin-ui/plugins/schema/hooks/useAttributeApi.ts`:
- Around line 61-79: The hooks (useCreateAttribute, useUpdateAttribute,
useDeleteAttribute) currently spread ...baseMutation which exposes the raw
mutate function and allows callers to bypass side effects; fix this by moving
the cache invalidation, triggerAttributeWebhook, and logAudit calls into the
mutation's callbacks (e.g., pass an onSuccess/onError to the underlying
useMutation options) or explicitly override both mutate and mutateAsync to call
those side effects before/after delegating to baseMutation; ensure you reference
and update baseMutation, mutate, mutateAsync, queryClient.invalidateQueries,
triggerAttributeWebhook, and logAudit so no public path can invoke the mutation
without running the side effects.

In `@admin-ui/plugins/schema/hooks/useMutationEffects.ts`:
- Around line 47-57: The success guard successHandledRef is only reset when
mutation.isIdle, causing it to remain true across consecutive submissions;
update the logic in useMutationEffects (where mutation, successHandledRef,
dispatch(updateToast(...)), navigateBack, and navigateOnSuccess are used) to
clear successHandledRef whenever the mutation is no longer in isSuccess (e.g.,
if mutation.isPending or mutation.isError or simply !mutation.isSuccess) so
subsequent successful mutations can show the toast and navigate again.

In `@admin-ui/plugins/schema/utils/validation.ts`:
- Around line 45-47: The numeric schema transform currently checks value === ''
which fails because Yup.number() passes the raw empty string in originalValue;
update the transform callbacks (the Yup.number().nullable().transform calls) to
accept both (value, originalValue) and use originalValue === '' to return null
(otherwise return value), and apply the same fix to the other identical
transform occurrence so blank inputs are correctly converted to null.

In
`@admin-ui/plugins/scripts/components/CustomScripts/styles/CustomScriptFormPage.style.ts`:
- Around line 325-326: The focus styles are inconsistent: formWithInputs uses
outline/boxShadow with `${OUTLINE_NONE} !important` but propsInput still uses
`${OUTLINE_NONE}` which can cause specificity issues; update the propsInput
style block (the propsInput constant) to apply `${OUTLINE_NONE} !important` for
both outline and boxShadow (matching formWithInputs) so focus styling is
consistent across components.
- Around line 328-331: The current rule targeting '& input:focus-visible, &
select:focus-visible' removes the focus indicator (uses OUTLINE_NONE), which
breaks keyboard focus visibility; update the CSS in CustomScriptFormPage.style
by either deleting that focus-visible selector or replacing it with an
accessible focus style (e.g., set a visible outline or subtle ring using a
contrasting color and modest thickness via outline/boxShadow instead of
OUTLINE_NONE) so keyboard users retain a clear focus indicator; edit the block
that references OUTLINE_NONE to apply the new visible focus styles for
input:focus-visible and select:focus-visible.

---

Outside diff comments:
In `@admin-ui/plugins/schema/components/Person/AttributeAddPage.tsx`:
- Around line 61-72: Extract the inline defaultAttribute object out of the
component as a top-level module constant (e.g., const DEFAULT_ATTRIBUTE:
Partial<AttributeItem> = { ... }) and replace the in-component declaration in
AttributeAddPage with a reference to that constant; when creating a new
attribute instance inside the component, use a shallow copy (e.g., {
...DEFAULT_ATTRIBUTE }) to avoid shared mutable state and preserve the
Partial<AttributeItem> type.

In `@admin-ui/plugins/schema/utils/validation.ts`:
- Around line 64-78: The 'min-max' schema.test predicate currently rejects equal
min/max because it returns value < maxLengthFromParent; update the predicate in
the schema.test('min-max', ...) function so it allows equality by returning
value <= maxLengthFromParent (i.e., treat minLength === maxLength as valid),
preserving the existing null/undefined guards and error message key
'errors.min_greater_than_max'.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1568a1ae-7e8e-43cc-8f1b-ccdae3aa68a1

📥 Commits

Reviewing files that changed from the base of the PR and between 02137ce and 50c48c2.

📒 Files selected for processing (34)
  • admin-ui/app/customColors.ts
  • admin-ui/app/locales/en/translation.json
  • admin-ui/app/locales/es/translation.json
  • admin-ui/app/locales/fr/translation.json
  • admin-ui/app/locales/pt/translation.json
  • admin-ui/app/redux/types/index.ts
  • admin-ui/app/routes/Apps/Gluu/GluuMultiSelectRow.tsx
  • admin-ui/app/routes/Apps/Gluu/GluuTabs.tsx
  • admin-ui/app/routes/Apps/Gluu/styles/GluuMultiSelectRow.style.ts
  • admin-ui/app/routes/Apps/Gluu/types/GluuMultiSelectRow.types.ts
  • admin-ui/app/styles/main.scss
  • admin-ui/app/utilities.tsx
  • admin-ui/plugins/schema/__tests__/components/AttributeAddPage.test.js
  • admin-ui/plugins/schema/__tests__/components/AttributeAddPage.test.tsx
  • admin-ui/plugins/schema/__tests__/components/AttributeDetailPage.test.js
  • admin-ui/plugins/schema/__tests__/components/AttributeEditPage.test.js
  • admin-ui/plugins/schema/__tests__/components/AttributeEditPage.test.tsx
  • admin-ui/plugins/schema/__tests__/components/AttributeForm.test.tsx
  • admin-ui/plugins/schema/__tests__/components/AttributeListPage.test.js
  • admin-ui/plugins/schema/__tests__/components/AttributeListPage.test.tsx
  • admin-ui/plugins/schema/components/Person/AttributeAddPage.tsx
  • admin-ui/plugins/schema/components/Person/AttributeDetailPage.tsx
  • admin-ui/plugins/schema/components/Person/AttributeEditPage.tsx
  • admin-ui/plugins/schema/components/Person/AttributeForm.tsx
  • admin-ui/plugins/schema/components/Person/AttributeListPage.tsx
  • admin-ui/plugins/schema/components/Person/AttributeViewPage.tsx
  • admin-ui/plugins/schema/components/Person/styles/AttributeFormPage.style.ts
  • admin-ui/plugins/schema/components/Person/styles/AttributeListPage.style.ts
  • admin-ui/plugins/schema/constants/index.ts
  • admin-ui/plugins/schema/hooks/index.ts
  • admin-ui/plugins/schema/hooks/useAttributeApi.ts
  • admin-ui/plugins/schema/hooks/useMutationEffects.ts
  • admin-ui/plugins/schema/utils/validation.ts
  • admin-ui/plugins/scripts/components/CustomScripts/styles/CustomScriptFormPage.style.ts
💤 Files with no reviewable changes (4)
  • admin-ui/plugins/schema/tests/components/AttributeEditPage.test.js
  • admin-ui/plugins/schema/tests/components/AttributeDetailPage.test.js
  • admin-ui/plugins/schema/tests/components/AttributeListPage.test.js
  • admin-ui/plugins/schema/tests/components/AttributeAddPage.test.js

@faisalsiddique4400 faisalsiddique4400 changed the title eat(admin-ui): revamp SCIM module as per Figma (#2635) ### feat(admin-ui): revamp User Claims module as per Figma (#2632) Mar 17, 2026
@faisalsiddique4400 faisalsiddique4400 changed the title ### feat(admin-ui): revamp User Claims module as per Figma (#2632) feat(admin-ui): revamp User Claims module as per Figma (#2632) Mar 17, 2026
@mo-auto mo-auto added the kind-feature Issue or PR is a new feature request label Mar 17, 2026
faisalsiddique4400 and others added 2 commits March 17, 2026 15:22
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Copy link
Contributor

@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: 11

♻️ Duplicate comments (1)
admin-ui/app/routes/Apps/Gluu/styles/GluuMultiSelectRow.style.ts (1)

24-40: ⚠️ Potential issue | 🟠 Major

Restore visible keyboard focus styles for trigger and chip remove controls.

Line 37 removes the outline, but there is no replacement focus treatment on selectTrigger, and chipRemove also lacks :focus-visible. Keyboard focus is not visibly detectable.

🎯 Proposed fix
     selectTrigger: {
@@
-      outline: 'none',
+      outline: 'none',
@@
+      '&:focus-within': {
+        borderColor: customColors.statusActive,
+        boxShadow: `0 0 0 3px ${isDark ? 'rgba(102, 187, 106, 0.25)' : 'rgba(102, 187, 106, 0.2)'}`,
+      },
     },
@@
     chipRemove: {
@@
       '&:hover': {
         backgroundColor: customColors.logo,
       },
+      '&:focus-visible': {
+        outline: `2px solid ${customColors.statusActive}`,
+        outlineOffset: 2,
+      },
     },

Also applies to: 68-85

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

In `@admin-ui/app/routes/Apps/Gluu/styles/GluuMultiSelectRow.style.ts` around
lines 24 - 40, selectTrigger and chipRemove currently remove the default outline
(outline: 'none') and lack any :focus-visible replacement, making keyboard focus
invisible; restore accessible focus styles by removing outline: 'none' from
selectTrigger (or replace it) and add a :focus-visible rule for both
selectTrigger and chipRemove that applies a visible focus indicator (e.g., a 2px
solid or box-shadow ring using the theme focus color and preserved
border-radius) so keyboard users can see focus; update the style object keys for
selectTrigger and chipRemove (and the equivalent block around lines 68-85) to
include these :focus-visible treatments while keeping existing transitions and
layout.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@admin-ui/app/locales/en/translation.json`:
- Around line 1265-1267: Replace the repurposed shared translation key by adding
a dedicated key (e.g., "titles.all_user_claims") for the User Claims page
instead of changing "titles.all_attributes"; update the translation JSON to add
"titles.all_user_claims": "User Claims" and revert "titles.all_attributes" to
its original generic value, then update the UI to use the new key by changing
the lookup in UserClaimsListPage
(admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx) to
t('titles.all_user_claims') so Reports
(admin-ui/app/routes/Dashboards/Reports/Reports.tsx) continues to read
t('titles.all_attributes') unchanged.

In `@admin-ui/app/locales/es/translation.json`:
- Around line 806-808: Add the missing localization entry for the key
messages.no_data in the Spanish translations so t('messages.no_data') used by
UserClaimsListPage.tsx (the empty-state/table message) resolves to a Spanish
string; open the Spanish translation JSON and add an appropriate value (e.g.,
"Sin datos" or similar) under the "messages" object using the exact key
messages.no_data, then save and run a quick UI/lang refresh to verify the empty
table shows the Spanish text.

In `@admin-ui/app/routes/Apps/Gluu/GluuMultiSelectRow.tsx`:
- Around line 128-133: The Enter/Space key handler on the combobox trigger
(onKeyDown that calls toggleDropdown) is firing when the keyboard event
originated from a chip remove button; update the onKeyDown guards in
GluuMultiSelectRow to ignore events that originate from the chip remove control
(e.g., check e.target or e.target.closest(...) for the remove button selector or
a data attribute) before calling toggleDropdown, and in the chip remove button
handlers add event.stopPropagation()/event.preventDefault() for Enter/Space so
the event does not bubble to the trigger; apply this fix to both the trigger
onKeyDown block (where toggleDropdown is invoked) and the other key handler
block around lines 146-153.

In `@admin-ui/plugins/schema/__tests__/components/UserClaimsListPage.test.tsx`:
- Around line 110-116: In the 'renders action icons for edit, view, and delete'
test for the UserClaimsListPage component, replace the non-idiomatic
document.querySelector checks with React Testing Library queries (e.g., use
screen.getByTestId or await screen.findByTestId) for the three icon testids
("EditIcon", "VisibilityOutlinedIcon", "DeleteOutlinedIcon") so the assertions
use RTL's getByTestId semantics and improve consistency with the rest of the
test suite.

In `@admin-ui/plugins/schema/components/Person/UserClaimsEditPage.tsx`:
- Around line 41-45: Gate the attribute query behind a resolved read decision
and initialize Cedarling for the Attributes resource first: call useCedarling()
and invoke its resource-initialization/priming function for
ADMIN_UI_RESOURCES.Attributes (using attributeResourceId) before starting
useAttribute(inum), ensure hasCedarReadPermission(attributeResourceId) is
evaluated with attributeResourceId in the dependency list, and only
call/useAttribute when the init call has completed and canRead is true (i.e.,
replace the unconditional useAttribute(inum) with a conditional/gated invocation
based on the initialization-complete flag and canRead).
- Line 49: The inum is being corrupted by stripping colons in the line that
defines inum; remove the lossy transformation and use the decoded gid directly
so LDAP inums keep their colons. Update the variable assignment that references
gid (used by ATTRIBUTE_EDIT and the component that reads useParams()) to stop
calling gid?.replace(':', '') and instead pass gid (or gid || '') through,
relying on ATTRIBUTE_EDIT URL-encoding to handle safe transport.

In `@admin-ui/plugins/schema/components/Person/UserClaimsForm.tsx`:
- Line 460: The JSX is using redundant "?? undefined" after optional chaining
(e.g., value={formik.values?.regexp ?? undefined})—remove the nullish coalescing
so the value uses the optional-chained expression directly
(value={formik.values?.regexp}) and apply the same simplification for minLength
and maxLength in UserClaimsForm.tsx (references: formik.values?.minLength and
formik.values?.maxLength).

In `@admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx`:
- Around line 451-458: The submit handler wired to GluuSearchToolbar is clearing
active criteria because onSearchSubmit is pointed to handleRefresh which resets
pattern, status, and sortBy; update the wiring so submitting does not wipe
filters: either change onSearchSubmit to call the same handler as onSearch
(handlePatternSearch) or add a new submit handler that invokes the
search/refresh logic without resetting pattern, status, or sortBy (modify
handleRefresh to accept a flag like preserveCriteria or add a new function
submitPattern that calls the search logic while preserving filters). Ensure the
updated handler is used in the GluuSearchToolbar props (searchOnType, onSearch,
onSearchSubmit) and that filters remains untouched on Enter/submit.
- Around line 83-87: The list query is firing before authorization is resolved
because authorizeHelper(attributeScopes) runs in useEffect after the first
render while useAttributes(...) initiates immediately; change the data-loading
to wait for the authorization decision by gating the useAttributes/list query on
the resolved authorization (e.g., only call/use the hook when canRead === true
and when authorization resolution has completed), update the logic in
UserClaimsListPage to check the resolved authorization flag (and/or canRead)
before starting the table/list request, and apply the same gating fix to the
similar block referenced around lines 91-97.

In `@admin-ui/plugins/schema/hooks/useAttributeApi.ts`:
- Around line 84-86: The mutate wrappers in useCreateAttribute,
useUpdateAttribute, and useDeleteAttribute call mutateAsync without returning or
handling its promise, causing potential unhandled rejections; update each
wrapper (the mutate: (...args: Parameters<typeof mutateAsync>) => { ... }
blocks) to either return the promise (return mutateAsync(...args)) so callers
can chain/await it or await and catch errors inside the wrapper (try { await
mutateAsync(...args) } catch (err) { /* handle/log or rethrow */ }) to ensure
errors are handled; apply this change consistently for the three mutate wrappers
referenced in the file.

In `@admin-ui/plugins/schema/hooks/useSchemaWebhook.ts`:
- Around line 17-26: The try/catch around the synchronous reducer dispatch is
unnecessary; remove the try/catch block (including the devLogger.error call) and
simply call dispatch(triggerWebhook({ createdFeatureValue: attribute as
Record<string, JsonValue>, feature })); locate the call in useSchemaWebhook.ts
where dispatch and triggerWebhook are used and replace the try/catch with the
direct dispatch invocation.

---

Duplicate comments:
In `@admin-ui/app/routes/Apps/Gluu/styles/GluuMultiSelectRow.style.ts`:
- Around line 24-40: selectTrigger and chipRemove currently remove the default
outline (outline: 'none') and lack any :focus-visible replacement, making
keyboard focus invisible; restore accessible focus styles by removing outline:
'none' from selectTrigger (or replace it) and add a :focus-visible rule for both
selectTrigger and chipRemove that applies a visible focus indicator (e.g., a 2px
solid or box-shadow ring using the theme focus color and preserved
border-radius) so keyboard users can see focus; update the style object keys for
selectTrigger and chipRemove (and the equivalent block around lines 68-85) to
include these :focus-visible treatments while keeping existing transitions and
layout.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9613b6db-78f9-4127-b436-3306a30546d8

📥 Commits

Reviewing files that changed from the base of the PR and between 50c48c2 and bcc8b6b.

📒 Files selected for processing (29)
  • admin-ui/app/locales/en/translation.json
  • admin-ui/app/locales/es/translation.json
  • admin-ui/app/locales/fr/translation.json
  • admin-ui/app/locales/pt/translation.json
  • admin-ui/app/routes/Apps/Gluu/GluuMultiSelectRow.tsx
  • admin-ui/app/routes/Apps/Gluu/styles/GluuMultiSelectRow.style.ts
  • admin-ui/plugins/admin/components/Assets/types/FormTypes.ts
  • admin-ui/plugins/schema/__tests__/components/UserClaimsAddPage.test.tsx
  • admin-ui/plugins/schema/__tests__/components/UserClaimsEditPage.test.tsx
  • admin-ui/plugins/schema/__tests__/components/UserClaimsForm.test.tsx
  • admin-ui/plugins/schema/__tests__/components/UserClaimsListPage.test.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsAddPage.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsDetailPage.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsEditPage.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsForm.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsViewPage.tsx
  • admin-ui/plugins/schema/components/Person/styles/UserClaimsFormPage.style.ts
  • admin-ui/plugins/schema/components/Person/styles/UserClaimsListPage.style.ts
  • admin-ui/plugins/schema/components/types/UserClaimsListPage.types.ts
  • admin-ui/plugins/schema/hooks/useAttributeApi.ts
  • admin-ui/plugins/schema/hooks/useMutationEffects.ts
  • admin-ui/plugins/schema/hooks/useSchemaAuditLogger.ts
  • admin-ui/plugins/schema/hooks/useSchemaWebhook.ts
  • admin-ui/plugins/schema/plugin-metadata.ts
  • admin-ui/plugins/schema/utils/formHelpers.ts
  • admin-ui/plugins/schema/utils/validation.ts
  • admin-ui/plugins/scripts/components/CustomScripts/styles/CustomScriptFormPage.style.ts
  • admin-ui/plugins/user-management/utils/attributeTransformUtils.ts

Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Copy link
Contributor

@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: 6

♻️ Duplicate comments (3)
admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx (1)

83-97: ⚠️ Potential issue | 🟠 Major

Delay the list query until Cedarling resolves read access.

authorizeHelper(attributeScopes) still runs after the first render, but useAttributes(...) starts immediately. That means the list endpoint can be called before the Attributes read decision exists. Wait for authorization resolution and only enable the query when canRead is true.

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

In `@admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx` around
lines 83 - 97, The attributes query is starting before authorization finishes;
modify the component to wait for the authorizeHelper result (the resolved read
decision, e.g., canRead) and the attributeScopes resolution before running
useAttributes. Specifically, ensure authorizeHelper(attributeScopes) is awaited
or its derived boolean (canRead) is tracked in state/effect and only call or
enable useAttributes when that boolean is true (and attributeScopes length > 0);
target the authorizeHelper, attributeScopes, and useAttributes usage to add this
gating so the list query is not issued until read access is confirmed.
admin-ui/app/locales/en/translation.json (1)

808-808: ⚠️ Potential issue | 🟡 Minor

Make the hint text match the actual control.

GluuMultiSelectRow is a click-to-open multiselect; there is no typing step. This copy still describes a typeahead flow, so the User Claims form will tell users to do something the control cannot do.

✏️ Suggested copy
-    "multi_select_hint": "Enter multiple items by selecting each one from the dropdown that appears after typing an item.",
+    "multi_select_hint": "Select one or more items from the dropdown.",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@admin-ui/app/locales/en/translation.json` at line 808, The translation for
"multi_select_hint" currently describes a typing/typeahead flow but the UI uses
GluuMultiSelectRow which is a click-to-open multiselect; update the
"multi_select_hint" value to reflect the actual control behavior (e.g., instruct
users to click the dropdown and choose items to add multiple entries) so the
User Claims form guidance matches GluuMultiSelectRow.
admin-ui/plugins/schema/components/Person/UserClaimsEditPage.tsx (1)

41-51: ⚠️ Potential issue | 🟠 Major

Authorize the resource before firing the edit query.

This page still starts useAttribute(inum) on the first render without priming Cedarling for ADMIN_UI_RESOURCES.Attributes. A direct deep link can send the protected request before the read decision exists. Gate the fetch behind resolved authorization first.

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

In `@admin-ui/plugins/schema/components/Person/UserClaimsEditPage.tsx` around
lines 41 - 51, The edit page currently calls useAttribute(inum) immediately,
which can fire a protected request before Cedarling has resolved permissions;
change the call so the attribute fetch is gated by the resolved read permission
from useCedarling (hasCedarReadPermission). Keep computing canRead with useMemo
(as now), then pass a falsy id (e.g., null or '') to useAttribute when canRead
is not true (for example: const { data: attribute, isLoading, error } =
useAttribute(canRead ? inum : null)), ensuring the fetch only runs once
hasCedarReadPermission granted access; reference useCedarling,
hasCedarReadPermission, canRead, inum, and useAttribute when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@admin-ui/app/routes/Apps/Gluu/GluuMultiSelectRow.tsx`:
- Around line 125-139: The combobox trigger div in GluuMultiSelectRow.tsx does
not call formik.handleBlur so the field never becomes touched on focus exit; add
an onBlur handler to the trigger div that invokes formik.handleBlur (e.g.,
onBlur={(e) => formik.handleBlur?.(e)}) so parent forms (like UserClaimsForm)
can mark the field touched and show validation; ensure you add this to the same
element that has toggleDropdown, role="combobox", aria-expanded, tabIndex, and
preserve existing keyboard handling.

In `@admin-ui/plugins/schema/components/Person/UserClaimsForm.tsx`:
- Around line 71-75: The footer currently ignores hideButtons.back and only uses
isViewMode; update the footer visibility logic to derive showBack and showSave
directly from hideButtons (not just via isViewMode). Specifically, replace
usages that rely on isViewMode (and the hardcoded showBack) with direct checks
like hideButtons?.back and hideButtons?.save when rendering the footer and
computing button visibility in UserClaimsForm (and the similar logic around the
other occurrence at lines 498-506). Ensure hideButtons being undefined defaults
to showing buttons (i.e., treat undefined as false for “hidden”) so callers can
pass any partial combination of { save, back } to hide individual buttons.
- Around line 297-349: The multi-select rows pass raw Formik error keys to
GluuMultiSelectRow, causing untranslated keys to show (e.g.,
formik.errors.editType); update the three GluuMultiSelectRow usages (for
name="editType", "viewType", "usageType") to translate error messages before
passing them: call the i18n translator (t) on the error value when constructing
errorMessage (and keep showError boolean logic), so errorMessage becomes the
localized string (e.g., errorMessage={formik.errors.editType ?
t(formik.errors.editType as string) : ''}); ensure the same change is applied
for editType, viewType, and usageType.

In `@admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx`:
- Around line 91-100: The component currently treats undefined attributesData as
"no data"; update the logic to explicitly handle query failures from
useAttributes by checking its error/isError state (from useAttributes) and
rendering an error state before rendering the table, instead of falling through
to messages.no_data. Locate the useAttributes call and related values
(useAttributes, attributesData, isLoading, attributes, toAttributeList,
totalItems) and add a branch that returns or renders an error UI when the hook
reports an error (include the error details/message), while preserving loading
and empty states; apply the same fix to the analogous block referenced around
the 449-483 area.

In `@admin-ui/plugins/schema/components/Person/UserClaimsViewPage.tsx`:
- Around line 41-51: Prime Cedarling for ADMIN_UI_RESOURCES.Attributes before
computing read permission and before running the attribute query: call your
cedarling initialization for the Attributes resource (via the hook returned by
useCedarling) first, then compute canRead (ensure attributeResourceId is
included in the useMemo deps) and only invoke useAttribute(inum) when read
access is resolved/allowed (e.g., pass an enabled flag or conditionally call
useAttribute when canRead is true or when a canReadResolved flag is set); update
the flow around useCedarling, hasCedarReadPermission, useMemo and useAttribute
so the authorization is initialized and the query is gated.

In `@admin-ui/plugins/schema/hooks/useAttributeApi.ts`:
- Around line 62-79: Post-write side effects (cache invalidation,
triggerAttributeWebhook, logAudit) are currently allowed to throw after
baseMutation.mutateAsync succeeds, which incorrectly flips the mutation to
error; wrap the post-write steps in a try/catch inside the mutateAsync function
(and the analogous update/delete mutateAsync blocks referenced) so that you
await baseMutation.mutateAsync(...) and then run invalidateQueries,
triggerAttributeWebhook(result), and logAudit(...) inside a try block, catch any
errors, record/log them (but do not rethrow), and always return the successful
result so the mutation state reflects the actual CRUD outcome and
useMutationEffects sees the real success.

---

Duplicate comments:
In `@admin-ui/app/locales/en/translation.json`:
- Line 808: The translation for "multi_select_hint" currently describes a
typing/typeahead flow but the UI uses GluuMultiSelectRow which is a
click-to-open multiselect; update the "multi_select_hint" value to reflect the
actual control behavior (e.g., instruct users to click the dropdown and choose
items to add multiple entries) so the User Claims form guidance matches
GluuMultiSelectRow.

In `@admin-ui/plugins/schema/components/Person/UserClaimsEditPage.tsx`:
- Around line 41-51: The edit page currently calls useAttribute(inum)
immediately, which can fire a protected request before Cedarling has resolved
permissions; change the call so the attribute fetch is gated by the resolved
read permission from useCedarling (hasCedarReadPermission). Keep computing
canRead with useMemo (as now), then pass a falsy id (e.g., null or '') to
useAttribute when canRead is not true (for example: const { data: attribute,
isLoading, error } = useAttribute(canRead ? inum : null)), ensuring the fetch
only runs once hasCedarReadPermission granted access; reference useCedarling,
hasCedarReadPermission, canRead, inum, and useAttribute when making the change.

In `@admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx`:
- Around line 83-97: The attributes query is starting before authorization
finishes; modify the component to wait for the authorizeHelper result (the
resolved read decision, e.g., canRead) and the attributeScopes resolution before
running useAttributes. Specifically, ensure authorizeHelper(attributeScopes) is
awaited or its derived boolean (canRead) is tracked in state/effect and only
call or enable useAttributes when that boolean is true (and attributeScopes
length > 0); target the authorizeHelper, attributeScopes, and useAttributes
usage to add this gating so the list query is not issued until read access is
confirmed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6f5bd158-c94e-453b-b528-b19ca9c0e418

📥 Commits

Reviewing files that changed from the base of the PR and between bcc8b6b and 391ec54.

📒 Files selected for processing (8)
  • admin-ui/app/locales/en/translation.json
  • admin-ui/app/routes/Apps/Gluu/GluuMultiSelectRow.tsx
  • admin-ui/plugins/schema/__tests__/components/UserClaimsListPage.test.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsEditPage.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsForm.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsViewPage.tsx
  • admin-ui/plugins/schema/hooks/useAttributeApi.ts

Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Copy link
Contributor

@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: 4

♻️ Duplicate comments (3)
admin-ui/app/locales/es/translation.json (1)

806-808: ⚠️ Potential issue | 🟡 Minor

Add messages.no_data to Spanish locale.

messages.no_data is still missing in this locale, so empty-state text that resolves t('messages.no_data') can fall back to raw key text.

🌐 Suggested fix
   "messages": {
     "multi_select_hint": "Ingrese varios elementos seleccionando del menú desplegable que aparece después de ingresar cada elemento.",
+    "no_data": "Sin datos",
     "add_permission": "Agregar Permiso",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@admin-ui/app/locales/es/translation.json` around lines 806 - 808, Add the
missing messages.no_data key to the Spanish translations by inserting "no_data"
under the existing "messages" object (next to "multi_select_hint" and
"add_permission"); set its value to an appropriate Spanish empty-state string
(e.g., "No hay datos disponibles" or similar) so t('messages.no_data') resolves
correctly in the UI.
admin-ui/plugins/schema/components/Person/UserClaimsViewPage.tsx (1)

49-65: ⚠️ Potential issue | 🟠 Major

Gate the attribute query by read permission before calling the hook.

At Line 64, useAttribute(inum) still runs regardless of canRead, so a protected read can fire before Cedar authorization is resolved.

🔧 Suggested fix
-  const inum = gid || ''
-
-  const { data: attribute, isLoading, error: queryError } = useAttribute(inum)
+  const inum = gid ?? ''
+  const canQueryAttribute = canRead && inum.length > 0
+
+  const { data: attribute, isLoading, error: queryError } = useAttribute(
+    canQueryAttribute ? inum : '',
+  )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@admin-ui/plugins/schema/components/Person/UserClaimsViewPage.tsx` around
lines 49 - 65, The attribute query is running regardless of Cedar read
permission because useAttribute(inum) is called unconditionally; change the call
so the hook is disabled until canRead is true — e.g. update the invocation of
useAttribute to either accept an options flag useAttribute(inum, { enabled:
canRead }) or pass a falsy id when read is not allowed (useAttribute(canRead ?
inum : undefined)), and keep the hook call and dependencies (canRead, inum)
stable so the query does not fire before authorization completes.
admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx (1)

83-87: ⚠️ Potential issue | 🟠 Major

Gate list fetching until authorization is resolved.

At Line 83, authorization is triggered after first render, but at Line 96 the list query starts immediately. This can call the API before read access is known.

#!/bin/bash
# Verify authorization timing vs query start in UserClaimsListPage
rg -n "authorizeHelper\\(|useAttributes\\(|hasCedarReadPermission|GluuViewWrapper" admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx -C3

# Verify current hook-level enablement in useAttributes
rg -n "export const useAttributes|enabled:" admin-ui/plugins/schema/hooks/useAttributeApi.ts -C4

Also applies to: 91-102

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

In `@admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx` around
lines 83 - 87, The list query in UserClaimsListPage is starting before
authorization finishes; ensure the API call is gated until authorizeHelper has
completed for the current attributeScopes. Add an explicit "authorization
resolved" boolean (e.g., isAuthResolved / isAuthorized) updated after
authorizeHelper(attributeScopes) finishes, and pass that into the data-fetch
hook (useAttributes or the list query's enabled option) so the query only runs
when isAuthResolved && isAuthorized is true; update the useEffect that calls
authorizeHelper to set that flag when done and reference authorizeHelper,
attributeScopes, and useAttributes (or the specific list query hook) to locate
the changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@admin-ui/app/locales/fr/translation.json`:
- Around line 915-917: Replace the French noun “Attribut” with “réclamation
utilisateur” in the user-claims strings: update the values for
"attribute_added_successfully", "attribute_updated_successfully", and
"attribute_deleted_successfully" to use “réclamation utilisateur” (e.g.,
"Réclamation utilisateur ajoutée avec succès" / "Réclamation utilisateur mise à
jour avec succès" / "Réclamation utilisateur supprimée avec succès"); also apply
the same replacement to the other user-claims strings in this file that mirror
these keys further down (the similar keys around the later occurrence noted in
the review).

In `@admin-ui/app/routes/Apps/Gluu/GluuMultiSelectRow.tsx`:
- Around line 128-133: In the onBlur handler inside the GluuMultiSelectRow
component replace usage of e.target with e.currentTarget so the name attribute
is set on the element the handler is attached to; specifically, in the arrow
function that checks formik.handleBlur and calls formik.handleBlur(e), call
e.currentTarget.setAttribute('name', name) before invoking formik.handleBlur(e)
to ensure consistent blur handling.
- Around line 175-203: Add Escape-key handling to close the open dropdown: when
isOpen is true, listen for the Escape key (either via a keyDown handler on the
trigger element or a short-lived document keydown listener) and close the
dropdown by calling the existing close mechanism (set isOpen to false or call
the component's closeDropdown/toggle function). Ensure the listener is
registered only while isOpen and removed when closing to avoid leaks; keep this
behavior alongside the existing per-option onKeyDown and handleOptionClick logic
so Escape only closes the list and does not trigger selection.

In `@admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx`:
- Around line 162-165: The call to handleDeleteConfirm inside handleDeleteAccept
is firing an async function without awaiting or returning its promise, causing
potential unhandled rejections when deleteAttributeMutation.mutateAsync() fails;
update handleDeleteAccept (the callback passed to GluuCommitDialog) to either
await handleDeleteConfirm(...) or return the promise from
handleDeleteConfirm(...) so GluuCommitDialog can properly await it and propagate
rejections (referencing handleDeleteAccept, handleDeleteConfirm, and
deleteAttributeMutation.mutateAsync to locate the relevant logic).

---

Duplicate comments:
In `@admin-ui/app/locales/es/translation.json`:
- Around line 806-808: Add the missing messages.no_data key to the Spanish
translations by inserting "no_data" under the existing "messages" object (next
to "multi_select_hint" and "add_permission"); set its value to an appropriate
Spanish empty-state string (e.g., "No hay datos disponibles" or similar) so
t('messages.no_data') resolves correctly in the UI.

In `@admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx`:
- Around line 83-87: The list query in UserClaimsListPage is starting before
authorization finishes; ensure the API call is gated until authorizeHelper has
completed for the current attributeScopes. Add an explicit "authorization
resolved" boolean (e.g., isAuthResolved / isAuthorized) updated after
authorizeHelper(attributeScopes) finishes, and pass that into the data-fetch
hook (useAttributes or the list query's enabled option) so the query only runs
when isAuthResolved && isAuthorized is true; update the useEffect that calls
authorizeHelper to set that flag when done and reference authorizeHelper,
attributeScopes, and useAttributes (or the specific list query hook) to locate
the changes.

In `@admin-ui/plugins/schema/components/Person/UserClaimsViewPage.tsx`:
- Around line 49-65: The attribute query is running regardless of Cedar read
permission because useAttribute(inum) is called unconditionally; change the call
so the hook is disabled until canRead is true — e.g. update the invocation of
useAttribute to either accept an options flag useAttribute(inum, { enabled:
canRead }) or pass a falsy id when read is not allowed (useAttribute(canRead ?
inum : undefined)), and keep the hook call and dependencies (canRead, inum)
stable so the query does not fire before authorization completes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: aa0cc260-4090-4488-a75c-0dcb3572cf58

📥 Commits

Reviewing files that changed from the base of the PR and between 8d344f0 and 2d4ae86.

📒 Files selected for processing (8)
  • admin-ui/app/locales/en/translation.json
  • admin-ui/app/locales/es/translation.json
  • admin-ui/app/locales/fr/translation.json
  • admin-ui/app/locales/pt/translation.json
  • admin-ui/app/routes/Apps/Gluu/GluuMultiSelectRow.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsForm.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx
  • admin-ui/plugins/schema/components/Person/UserClaimsViewPage.tsx

Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Copy link
Contributor

@duttarnab duttarnab left a comment

Choose a reason for hiding this comment

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

  1. I added a new claim testclaimName, in edit mode on change the fields the Apply button is activated.
Image
  1. I added a new claim testclaimName, theUsage Type in edit mode is not visible.
Image

Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
@sonarqubecloud
Copy link

@moabu moabu merged commit 4e394b5 into main Mar 18, 2026
8 checks passed
@moabu moabu deleted the admin-ui-issue-2632 branch March 18, 2026 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp-admin-ui Component affected by issue or PR kind-feature Issue or PR is a new feature request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(admin-ui) revamp the User Claims module as per Figma

4 participants