Skip to content

feat(admin-ui): revamp Jans Lock module as per Figma#2705

Closed
faisalsiddique4400 wants to merge 15 commits intomainfrom
admin-ui-issue-2637
Closed

feat(admin-ui): revamp Jans Lock module as per Figma#2705
faisalsiddique4400 wants to merge 15 commits intomainfrom
admin-ui-issue-2637

Conversation

@faisalsiddique4400
Copy link
Contributor

@faisalsiddique4400 faisalsiddique4400 commented Mar 18, 2026

feat(admin-ui): revamp Jans Lock module as per Figma (#2637)

Summary

This PR revamps the Jans Lock 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 structure and information hierarchy.
  • Standardized spacing, typography, and alignment with the updated design system.
  • Enhanced usability for Jans Lock configuration workflows.
  • Ensured consistent UI behavior and responsiveness.

Result

  • Modernized and visually consistent Jans Lock module.
  • Improved clarity and usability for administrators managing lock 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: #2637

Summary by CodeRabbit

  • New Features

    • Added User Claims management interface with create, edit, view, and list capabilities.
    • Introduced multi-select component with chip-style selections for enhanced form interactions.
  • Enhancements

    • Improved Jans Lock configuration UI with data-driven field rendering and theme-aware styling.
    • Expanded internationalization support for User Claims operations and validation messages across multiple languages.
  • Bug Fixes

    • Fixed input autofill and focus state styling for better visual consistency.
  • Tests

    • Added comprehensive test coverage for Cedarling authorization, Lock configuration, and User Claims functionality.

faisalsiddique4400 and others added 13 commits March 16, 2026 16:43
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
@mo-auto mo-auto added comp-admin-ui Component affected by issue or PR kind-feature Issue or PR is a new feature request labels Mar 18, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 18, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f98162ee-45d3-4f25-80ac-6c4b4f5279be

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR introduces comprehensive testing for Cedarling functionality, refactors the Jans-lock module with new form components and styling, migrates the schema plugin from Attribute to UserClaims-based components, adds localization strings across multiple languages, and introduces new UI components including a multi-select row component with theming support.

Changes

Cohort / File(s) Summary
Cedarling Tests
admin-ui/app/cedarling/__tests__/*
Added comprehensive test suites validating cedarling client initialization, token authorization, resource scopes, logging types, hooks, and utility functions including permission checks and cached decisions.
Lock Module Tests
admin-ui/plugins/jans-lock/__tests__/components/*
New test suites for JansLock component, configuration, field renderer, constants, helper utilities, and validations covering form population, permissions, field rendering, and validation schema behavior.
Lock Module Components & Types
admin-ui/plugins/jans-lock/components/*, admin-ui/plugins/jans-lock/types/*
Refactored JansLock and JansLockConfiguration to use data-driven field rendering via new JansLockFieldRenderer; updated JansLockConfigFormValues type with new fields (metricChannel, policiesJsonUris*, disableExternalLoggerConfiguration) and removed legacy fields; introduced FieldType, FieldConfig, and JansLockConfigurationProps types.
Lock Module Styling & Utilities
admin-ui/plugins/jans-lock/components/styles/*, admin-ui/plugins/jans-lock/helper/*
Added JansLockFormPage.style.ts with responsive theming-aware styles; updated validation and utilities to support URL validation, cedarling policy sources, and dynamic schema generation via getLockValidationSchema factory function.
GluuMultiSelectRow Component
admin-ui/app/routes/Apps/Gluu/GluuMultiSelectRow.*
New multi-select component with dropdown toggle, chip-style selections, keyboard/mouse interactions, theming support, and Formik integration including types, styling, and memoization.
Schema Plugin Migration
admin-ui/plugins/schema/components/Person/*, admin-ui/plugins/schema/__tests__/components/*
Migrated from Attribute* components (removed AttributeAddPage, AttributeEditPage, AttributeListPage, AttributeViewPage, AttributeDetailPage, AttributeForm) to UserClaims* equivalents with updated form handling, API hooks, and comprehensive test coverage.
Schema Plugin Hooks & Utilities
admin-ui/plugins/schema/hooks/*, admin-ui/plugins/schema/utils/*
Added useAttributeApi hooks (useAttributes, useAttribute, useCreateAttribute, useUpdateAttribute, useDeleteAttribute) with React Query integration; introduced useMutationEffects for handling mutation side effects; updated validation to use static error keys instead of translation functions.
Schema Plugin Styling & Configuration
admin-ui/plugins/schema/components/Person/styles/*, admin-ui/plugins/schema/constants/*, admin-ui/plugins/schema/plugin-metadata.ts
Added UserClaimsFormPage.style.ts and UserClaimsListPage.style.ts; introduced QUERY_KEY_PREFIX_ATTRIBUTES and ATTRIBUTE_CACHE_CONFIG constants; updated plugin routes to reference UserClaims* pages.
Localization Updates
admin-ui/app/locales/{en,es,fr,pt}/translation.json
Added translation keys for user claim operations (add_attribute, attribute_added/updated/deleted_successfully), validation messages (required, name_no_spaces, positive_number, etc.), placeholders (enter_base_dn, enter_metric_, enter_policies_), and UI titles (edit_attribute, view_attribute).
UI Constants & Styling
admin-ui/app/constants/ui.ts, admin-ui/app/customColors.ts, admin-ui/app/styles/main.scss
Added OPACITY.FULL constant (value 1); added statusActiveBgDark color (#b6f6da); added WebKit autofill styling for input/textarea elements.
Minor Formatting & Type Updates
admin-ui/app/redux/types/index.ts, admin-ui/app/utilities.tsx, admin-ui/plugins/admin/components/Assets/types/FormTypes.ts, admin-ui/routes/Apps/Gluu/GluuTabs.tsx, admin-ui/plugins/saml/components/Website*.tsx, admin-ui/plugins/user-management/utils/attributeTransformUtils.ts, admin-ui/plugins/scripts/components/CustomScripts/styles/CustomScriptFormPage.style.ts
Type declaration and formatting adjustments with no semantic logic changes; RootState extends reformatted, require.context type simplified, AssetFormValues extends expanded, focus styles updated with !important and focus-visible selectors.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • duttarnab

🐰 Through tests and new forms we hop,
GluuMultiSelect makes our UI pop!
Lock refactored, claims now bright,
UserClaims pages set things right!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR contains significant out-of-scope changes including User Claims module creation/refactoring, translation updates, utility changes, and schema plugin modifications unrelated to Jans Lock revamp. Separate User Claims feature changes into a dedicated PR; retain only Jans Lock-specific modifications (components, styles, types, tests, helpers) in this PR to maintain focus on issue #2637.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 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: revamping the Jans Lock module to match Figma designs.
Linked Issues check ✅ Passed The PR substantially addresses the linked issue #2637 objective to revamp Jans Lock module UI per Figma designs through layout updates, styling, component refactoring, and test coverage.

✏️ 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-2637
📝 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.

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: 35

Caution

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

⚠️ Outside diff range comments (1)
admin-ui/plugins/scripts/components/CustomScripts/styles/CustomScriptFormPage.style.ts (1)

320-331: 🧹 Nitpick | 🔵 Trivial

Accessibility consideration for removed focus outlines.

The addition of focus-visible selectors is a good practice for distinguishing keyboard navigation from mouse clicks. However, removing outlines entirely (even with !important) can make the form difficult to navigate for keyboard users if no alternative visual focus indicator is provided.

Ensure that either:

  1. The border style change on focus (line 324) provides sufficient visual differentiation, or
  2. A custom focus ring/indicator is applied elsewhere
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@admin-ui/plugins/scripts/components/CustomScripts/styles/CustomScriptFormPage.style.ts`
around lines 320 - 331, The current focus rules ('& input:focus, & input:active,
& select:focus, & select:active, & .custom-select:focus, &
.custom-select:active' and '& input:focus-visible, & select:focus-visible')
remove outlines entirely which removes keyboard focus affordance; update the
focus-visible rule(s) so keyboard users get a clear visual indicator (e.g. keep
or replace outline with a visible style such as a distinct border color/width or
a subtle box-shadow focus ring) instead of `outline: none`/`boxShadow: none` —
modify the selectors in CustomScriptFormPage.style (the focus/focus-visible
rules) to apply that accessible focus ring (or ensure the existing border change
on focus is perceptibly stronger) so focus is always visually distinguishable
for keyboard navigation.
🤖 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/cedarling/__tests__/client/CedarlingClient.test.ts`:
- Around line 17-20: The test should assert idempotency by verifying the
underlying initialization helper is only invoked once: create a spy (e.g.,
jest.spyOn(CedarlingClient.prototype, '_initialize') or the actual internal
helper used by cedarlingClient.initialize) before the first call, call
cedarlingClient.initialize({}) and expect the spy to have been called once, then
call cedarlingClient.initialize({}) again and expect the spy call count to
remain unchanged (still 1) and the second call to resolve to undefined; restore
the spy after the test.

In `@admin-ui/app/cedarling/__tests__/constants/resourceScopes.test.ts`:
- Around line 40-48: The test titles claim specific scope types but only assert
counts; update the tests referencing CEDAR_RESOURCE_SCOPES.SMTP and
CEDAR_RESOURCE_SCOPES.Dashboard to either (A) rename the it(...) descriptions to
reflect what is actually asserted (e.g., "SMTP has 3 scopes" and "Dashboard has
2 scopes") or (B) strengthen the assertions to verify actual scope strings/types
match the descriptions by asserting the arrays contain the expected scope names
(use expect(...).toEqual(...) or
expect(...).toEqual(expect.arrayContaining([...])) / expect(...).toContain(...)
against the known scope strings such as the SMTP scopes and the Dashboard stat
scope).
- Around line 33-38: The test CEDAR_RESOURCE_SCOPES.Lock currently only checks
length and that some permission contains 'read' or 'lock', which doesn't verify
both read and write scopes exist; update the assertion in the test that uses
lockScopes / permissions to explicitly assert that one permission includes
'read' and another includes 'write' (or adapt to the actual 'lock' naming if
write is represented by 'lock') so the test name "Lock has read and write
scopes" matches the checked conditions.

In `@admin-ui/app/cedarling/__tests__/hooks/useCedarling.test.ts`:
- Around line 185-194: The test in useCedarling.test.ts duplicates the earlier
case by passing an empty array to authorizeHelper; either remove this duplicate
test or change it to pass an actual undefined-like value and update its
description. Specifically, in the test case referencing useCedarling() and
result.current.authorizeHelper, replace the [] argument with undefined (or null)
and assert the expected empty-array result, and update the it(...) title to
"returns empty array for undefined input" (or delete the whole it(...) block if
you prefer to remove the duplicate).

In `@admin-ui/app/cedarling/__tests__/utility/resources.test.ts`:
- Around line 46-48: The test hardcodes 27 in the assertion which duplicates the
length of expectedResources; update the test (the "contains all 27 resources"
spec) to compute the expected length dynamically by comparing
Object.keys(ADMIN_UI_RESOURCES).length to expectedResources.length (or
Object.keys(expectedResources).length) instead of the magic number 27 so the
assertion stays correct when expectedResources changes.

In `@admin-ui/app/locales/en/translation.json`:
- Around line 1143-1155: The translation keys add_attribute, delete_attribute,
edit_attribute, and view_attribute currently use inconsistent casing ("Add User
Claim" vs "Delete user claim"); update their values to sentence case to match
similar entries (e.g., "Add user claim", "Delete user claim", "Edit user claim",
"View user claim") by editing the corresponding entries in translation.json so
all four labels use lowercase 'user claim'.

In `@admin-ui/app/locales/fr/translation.json`:
- Line 774: Update the French translation for the "multi_select_hint" key to
reflect the dropdown interaction instead of typing; replace the current string
that instructs typing with a concise phrase such as "Sélectionnez plusieurs
éléments dans la liste déroulante" (or similar) in the translation.json entry
for "multi_select_hint" so the copy matches the actual multi-select dropdown
control.

In `@admin-ui/app/locales/pt/translation.json`:
- Line 766: Update the "multi_select_hint" translation to reflect the new
click-to-select dropdown behavior (no text entry) by replacing the current
instruction about "inserir" each item with a concise hint that users should
select multiple items from the dropdown (e.g., "Selecione vários itens no menu
suspenso; cada clique adiciona um item"). Locate the "multi_select_hint" key in
the translation.json and change its value to a phrase that explicitly mentions
clicking/selecting from the dropdown rather than typing/inserting.

In `@admin-ui/app/routes/Apps/Gluu/GluuMultiSelectRow.tsx`:
- Around line 165-175: The aria-label on the remove button is hard-coded in
English; update GluuMultiSelectRow.tsx to build the label via i18n so
screen-reader text follows locale: use the component's translation function
(e.g., the useTranslation hook or existing t prop) to produce the label (either
by calling t('remove', { item: getOptionLabel(val) }) or by concatenating
t('remove') + ' ' + getOptionLabel(val)), update the aria-label expression
accordingly, and ensure a corresponding translation key (like "remove" or
"remove_item") exists for all locales; keep handleRemoveChip, getOptionLabel,
and classes.chipRemove references unchanged.
- Around line 140-145: The current inline onBlur on the trigger in
GluuMultiSelectRow.tsx doesn't work because formik.handleBlur reads
event.target.name and blurs from buttons/options outside the trigger never reach
it; move blur logic into a container-level onBlur/onFocusOut handler on the
composite field wrapper (the component that renders the trigger, popup, chips
and listbox) and on blur check via event.relatedTarget or
container.contains(event.relatedTarget) (or use setTimeout+contains) to detect
when focus actually leaves the whole composite; when focus leaves call
formik.handleBlur with a synthetic event whose target/name is the field name
(same name used previously) so Formik marks touched and closes the popup; apply
the same change to the duplicate handlers around lines 187-217.
- Around line 127-157: The combobox div rendered inside GluuMultiSelectRow (the
element using triggerClasses, toggleDropdown, containerRef, name, isOpen,
disabled, and formik.handleBlur) needs ARIA connections: add a stable id to that
combobox element and set aria-labelledby to the label element id, add
aria-controls pointing to the listbox id used for the dropdown, and set
aria-invalid="true" when showError is true; also assign ids to the error and
helper text elements and include them in aria-describedby on the combobox so
screen readers announce validation/help text. Locate the error/helper renderers
(where showError is computed) and give them unique ids, then wire those ids into
aria-describedby, and ensure the listbox component uses the same id referenced
by aria-controls.

In `@admin-ui/app/routes/Apps/Gluu/styles/GluuMultiSelectRow.style.ts`:
- Around line 24-40: selectTrigger currently removes the browser outline and
lacks a keyboard focus indicator; add a dedicated :focus-visible style for
selectTrigger (e.g., "&:focus-visible") that replaces the removed outline with
an accessible visible focus treatment such as changing borderColor and/or adding
a subtle boxShadow ring using an accessible focus color (use existing theme
token or derive from inputBorderColor/fontColor), keep outline: 'none' but
ensure transition is preserved so keyboard focus is visually clear and
consistent with selectTrigger's existing styles.

In `@admin-ui/app/routes/Apps/Gluu/types/GluuMultiSelectRow.types.ts`:
- Around line 6-9: The type alias GluuMultiSelectRowFormik references
React.FocusEvent<HTMLElement> but the file lacks a React type import; add an
explicit type import (e.g., import type React from 'react') or replace
React.FocusEvent with the DOM/React FocusEvent type by importing FocusEvent from
'react' so the GluuMultiSelectRowFormik definition compiles correctly.

In `@admin-ui/plugins/jans-lock/__tests__/components/JansLock.test.tsx`:
- Around line 105-147: Tests only assert that the component didn't crash
(document.body truthy or generic form present); update the three tests to assert
specific outputs for each branch: for the "no read permission" case, mock
useCedarling as done and expect JansLock to render the access-denied UI by
querying for a stable selector or text (e.g., an "access denied" message or a
data-testid you add to the access-denied component); for the "renders loading
state" case, mock useGetLockProperties to return isLoading: true and assert the
loader is present by querying a stable selector (e.g., the GluuLoader's text,
role="status", or a data-testid on the loader); for the "renders with empty
config" case, mock data: undefined and isLoading: false and assert the
empty-state UI is shown by checking for specific empty-state content or a
data-testid; add data-testid attributes to JansLock's access-denied, loader, and
empty-state if no stable selectors exist, and update the tests to query those
identifiers instead of document.body or a generic form.

In
`@admin-ui/plugins/jans-lock/__tests__/components/JansLockConfiguration.test.tsx`:
- Around line 174-188: The test "detects form changes after field modification"
only asserts the input value change; update it to also assert the form
dirty-state side-effect by locating the form submit/apply button associated with
JansLockConfiguration (e.g., the primary action button rendered by the
component) and asserting it transitions from disabled to enabled after changing
the input "baseDN". In the test, after fireEvent.change on input[name="baseDN"]
and the waitFor confirming the value, add an assertion that the button (found
via getByRole('button', { name: /apply|save|submit/i }) or a specific label used
in JansLockConfiguration) was initially disabled and becomes enabled, ensuring
the component's dirty-state is validated.

In
`@admin-ui/plugins/jans-lock/__tests__/components/JansLockFieldRenderer.test.tsx`:
- Around line 192-194: The test currently only checks for '.field-item'
(variable toggle) which verifies layout but not the actual control; update the
assertion to locate the toggle control itself (e.g., use
container.querySelector('input[type="checkbox"]') or screen.getByRole('switch')
to find the renderer's switch element) and assert that that element is in the
document (and optionally has the expected attributes like aria-checked) so the
JansLockFieldRenderer toggle presence is validated directly.

In `@admin-ui/plugins/jans-lock/__tests__/components/validations.test.ts`:
- Around line 35-39: Add explicit tests that pass null for optional numeric and
URI fields (not just empty strings) and assert
schema.validateAt('metricReporterInterval', { metricReporterInterval: null })
resolves to null; do the same for the other cases mentioned (the blocks around
lines 61-65, 94-97, 132-135). Ensure the Yup schema used in these tests marks
those fields as nullable() and omits required() so the schema accepts backend
DTO nulls; locate and update the schema definitions referenced by
schema.validateAt in this test file to include nullable() for the optional
numeric/URI fields.

In `@admin-ui/plugins/jans-lock/components/JansLock.tsx`:
- Around line 41-45: The useEffect in JansLock.tsx currently lists only
authorizeHelper in its dependency array; update the dependency array to include
lockScopes as well (i.e., [authorizeHelper, lockScopes]) so the hook explicitly
depends on both authorizeHelper and lockScopes; locate the useEffect block that
calls authorizeHelper(lockScopes) and add lockScopes to its dependencies to
satisfy exhaustive-deps and document the dependency.

In `@admin-ui/plugins/jans-lock/components/JansLockConfiguration.tsx`:
- Around line 100-109: The submitForm callback currently ignores its
_userMessage parameter; update submitForm and the onUpdate usage so the commit
message is forwarded for audit logging: modify submitForm(_userMessage) to pass
_userMessage along with the patchOperations to onUpdate (e.g., call
onUpdate(patchOperations, _userMessage)), update the onUpdate function/type
signature and all call sites to accept the optional message, and ensure
trimmedValuesAndPatches and patchOperations are still used as before inside
submitForm.
- Around line 95-98: The current tokenChannelOptions useMemo unsafely asserts
lockConfig?.tokenChannels as string[]; update it to defensively handle
unexpected types by checking Array.isArray(lockConfig?.tokenChannels) and
filtering for string entries before mapping. For example, in tokenChannelOptions
replace the assertion with a channels value computed as
Array.isArray(lockConfig?.tokenChannels) ? lockConfig.tokenChannels.filter(item
=> typeof item === 'string') : [] and then map to {value,label} pairs; keep the
useMemo and its dependency on lockConfig?.tokenChannels.

In `@admin-ui/plugins/jans-lock/components/JansLockFieldRenderer.tsx`:
- Around line 102-120: The JSX in JansLockFieldRenderer passes both
disabled={isDisabled} and viewOnly={isDisabled} to GluuToggleRow which may be
redundant; inspect GluuToggleRow to determine whether viewOnly and disabled have
distinct behavior and then either remove the redundant prop or pass the correct
value. If viewOnly should mirror disabled keep both, otherwise remove
viewOnly={isDisabled} from the toggle case (or set viewOnly to the intended
conditional) so only the appropriate prop controls the component.

In `@admin-ui/plugins/jans-lock/components/styles/JansLockFormPage.style.ts`:
- Around line 147-167: The focus styles for typeaheads and multi-inputs
(selectors: '.rbt .form-control', '.rbt .form-control:active',
'.rbt-input-main', '.rbt-input-main:active', '.rbt-input-multi', and
'.rbt-input-multi:focus-within') currently remove outline/box-shadow and keep
the same border color, making keyboard focus invisible; restore a visible focus
indicator by removing the rules that set outline: 'none' and boxShadow: 'none'
for these selectors and instead apply a distinct focus style (for example a
stronger border color or a visible box-shadow/outline using a focus color
variable such as themeColors.focus or an inputFocusColor) when :focus or
:focus-within is active so focused controls are clearly distinguishable for
keyboard users.

In `@admin-ui/plugins/jans-lock/helper/utils.ts`:
- Around line 145-161: The policySources array is built by conditional pushes
which shifts indices and breaks transformToFormValues that expects JSON at index
0 and ZIP at index 1; replace the push-based construction with a fixed
two-element array (first element = JSON source object, second element = ZIP
source object) using empty strings for missing authorizationToken/policyStoreUri
so positions are preserved, and keep references to policySources and
transformToFormValues consistent when updating this logic.

In `@admin-ui/plugins/jans-lock/helper/validations.ts`:
- Around line 17-25: The validation for cleanServiceInterval in
getLockValidationSchema is confusing because .nullable() is called before
.transform(emptyStringToNull) and .required(); move
.transform(emptyStringToNull) before .nullable() (i.e., apply transform first,
then call .nullable()) so empty strings are converted to null prior to
nullability checks, and then either keep .required() to reject nulls or
remove/adjust .required() to match the backend DTO if null is permitted by the
API; update the logic for the cleanServiceInterval field (and any similar
fields) accordingly.

In `@admin-ui/plugins/jans-lock/types/jans-lock-types.ts`:
- Around line 45-51: lockConfig is currently typed as Record<string, unknown>
which loses type safety; define a concrete interface (e.g., JansLockConfig) that
matches the backend response shape and use that in JansLockConfigurationProps
instead of Record<string, unknown>, then validate/narrow incoming data at the
component boundary (e.g., in the parent or a parse/deserialize function) with a
runtime check or type guard before passing to components so consumers of
JansLockConfigurationProps get proper typings for properties used in the
component.

In `@admin-ui/plugins/schema/__tests__/components/UserClaimsForm.test.tsx`:
- Line 49: The import for UserClaimsForm is declared after test fixture
declarations; move the import statement for UserClaimsForm (import
UserClaimsForm from 'Plugins/schema/components/Person/UserClaimsForm') up into
the top-level imports section alongside the other imports so all module imports
are grouped before any test fixture or setup code, keeping the same import path
and only changing its position.

In
`@admin-ui/plugins/schema/components/Person/styles/UserClaimsFormPage.style.ts`:
- Around line 42-58: The formGrid currently forces two columns and the content
wrapper keeps fixed side padding so the layout will squeeze on narrow viewports;
update the styles for content and formGrid so they respond to small screens:
change formGrid's gridTemplateColumns to a responsive pattern (e.g., use
repeat/auto-fit with a minmax breakpoint or switch to a single column under a
small-screen media query) and make content's horizontal padding adapt (reduce or
switch to smaller padding at narrow widths) so fields stack instead of
overflowing; modify the objects named content and formGrid in
UserClaimsFormPage.style.ts to implement these responsive grid and padding
adjustments.
- Around line 180-188: The focus style block for inputs in
UserClaimsFormPage.style.ts currently removes both outline and boxShadow
(selector starting with '& input:not([type="checkbox"]):focus...'), leaving no
visible focus indicator; restore an accessible focus state by removing the lines
that clear outline/boxShadow or replacing them with a visible focus rule (e.g.,
set outline: '2px solid var(--theme-focus-color)' or boxShadow: `0 0 0 3px
rgba(...)`) and ensure the border/box shadow uses a contrasting color (use
inputBorderColor or a --theme-focus-color variable) so keyboard users can see
focused fields.

In `@admin-ui/plugins/schema/components/Person/UserClaimsAddPage.tsx`:
- Around line 61-72: The add form uses a hard-coded partial object named
defaultAttribute which only populates a subset of AttributeItem and risks
missing new required fields; replace that literal with a call to the shared
factory getDefaultAttributeItem() (optionally merge/override any specific
defaults needed) so the add path uses the same full defaults as edit—update the
usage in UserClaimsAddPage (replace defaultAttribute with
getDefaultAttributeItem() or { ...getDefaultAttributeItem(), /* overrides */ })
to avoid unsafe casting and keep defaults aligned.

In `@admin-ui/plugins/schema/components/Person/UserClaimsEditPage.tsx`:
- Around line 41-52: The attribute query is currently fired unconditionally;
update the useAttribute call to only run when the user can read and we have a
valid id by passing an enabled flag or gating the hook: useAttribute(inum, {
enabled: canRead && Boolean(inum) }) (or equivalent enabled option used by your
hook), ensuring the hook invocation or options reference useAttribute, inum, and
canRead so the query won’t execute before the read check (apply the same change
to the other occurrence around lines 112-123).

In `@admin-ui/plugins/schema/components/Person/UserClaimsForm.tsx`:
- Line 488: The hardcoded isLoading={false} in UserClaimsForm should be made
dynamic: add an isLoading or isSubmitting boolean prop to the UserClaimsForm
component (update its props interface) and use that prop when rendering the
footer control (where isLoading is currently set) — e.g., pass props.isLoading
(or internal submitting state) into the FormFooter/Button isLoading prop so
footer buttons disable and show loading during submission; if you intentionally
don't need a loading state, add a concise comment near the isLoading line
explaining why it's fixed false.

In `@admin-ui/plugins/schema/components/Person/UserClaimsListPage.tsx`:
- Around line 148-160: The handleDeleteConfirm callback should ensure modal
state is updated even when deleteAttributeMutation.mutateAsync fails: wrap the
await deleteAttributeMutation.mutateAsync(...) call in a try/catch (or
try/finally) inside handleDeleteConfirm (referencing handleDeleteConfirm,
deleteAttributeMutation.mutateAsync, setModal, setItemToDelete) and move
setModal(false) and setItemToDelete(null) into a finally block (or execute them
in both success and error branches); optionally surface the error via the
mutation's error handler or rethrow after cleaning up so the UI doesn't remain
stuck open on failure.

In `@admin-ui/plugins/schema/components/Person/UserClaimsViewPage.tsx`:
- Around line 44-47: The useMemo calls for attributeScopes and canRead include
attributeResourceId in their dependency arrays even though attributeResourceId
is a module-level constant that never changes; remove attributeResourceId from
the dependencies and replace with an empty array (or only include real reactive
dependencies) so the hooks correctly reflect their stable inputs: update the
useMemo that defines attributeScopes (which references CEDAR_RESOURCE_SCOPES and
attributeResourceId) and the useMemo that computes canRead to drop
attributeResourceId from the dependency arrays.

In `@admin-ui/plugins/schema/hooks/useAttributeApi.ts`:
- Around line 82-88: The wrapper currently calls mutateAsync(...args).catch(()
=> {}) which swallows any errors from the post-write side-effect chain; change
the wrapper for mutate (and the analogous wrappers around mutateAsync at the
other spots) to return the promise from mutateAsync and handle failures by
either rethrowing or at minimum logging the error so callers see/report
failures: update the mutate implementation (and the other two wrappers) so it
does return mutateAsync(...args).catch(err => { console.error('post-write
side-effect failed', err); throw err; }) or otherwise propagate the rejection
instead of swallowing it, ensuring baseMutation and mutateAsync behavior is
preserved.

In `@admin-ui/plugins/schema/hooks/useMutationEffects.ts`:
- Around line 25-27: The hook useMutationEffects currently hard-codes navigation
to ROUTES.ATTRIBUTES_LIST on success (lines around the success handling) which
prevents callers from choosing a different destination; modify the hook
signature to accept a success destination/callback option (e.g.,
successDestination?: string | (data: any) => void or onSuccessNavigate?:
(data)=>void) alongside the existing
successMessage/errorMessage/navigateOnSuccess options, and replace the direct
call to navigate(ROUTES.ATTRIBUTES_LIST) with logic that calls the provided
destination or callback when present (falling back to navigateOnSuccess behavior
if you must preserve it); update callers to pass the desired route or callback
instead of relying on the hard-coded ROUTES.ATTRIBUTES_LIST.

---

Outside diff comments:
In
`@admin-ui/plugins/scripts/components/CustomScripts/styles/CustomScriptFormPage.style.ts`:
- Around line 320-331: The current focus rules ('& input:focus, & input:active,
& select:focus, & select:active, & .custom-select:focus, &
.custom-select:active' and '& input:focus-visible, & select:focus-visible')
remove outlines entirely which removes keyboard focus affordance; update the
focus-visible rule(s) so keyboard users get a clear visual indicator (e.g. keep
or replace outline with a visible style such as a distinct border color/width or
a subtle box-shadow focus ring) instead of `outline: none`/`boxShadow: none` —
modify the selectors in CustomScriptFormPage.style (the focus/focus-visible
rules) to apply that accessible focus ring (or ensure the existing border change
on focus is perceptibly stronger) so focus is always visually distinguishable
for keyboard navigation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7d04bfdc-1b42-4d48-80c9-45682ace5050

📥 Commits

Reviewing files that changed from the base of the PR and between 485d48f and 52468df.

📒 Files selected for processing (71)
  • admin-ui/app/cedarling/__tests__/client/CedarlingClient.test.ts
  • admin-ui/app/cedarling/__tests__/constants/resourceScopes.test.ts
  • admin-ui/app/cedarling/__tests__/enums/CedarlingLogType.test.ts
  • admin-ui/app/cedarling/__tests__/hooks/useCedarling.test.ts
  • admin-ui/app/cedarling/__tests__/utility/resources.test.ts
  • admin-ui/app/constants/ui.ts
  • 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/admin/components/Assets/types/FormTypes.ts
  • admin-ui/plugins/jans-lock/__tests__/components/JansLock.test.tsx
  • admin-ui/plugins/jans-lock/__tests__/components/JansLockConfiguration.test.tsx
  • admin-ui/plugins/jans-lock/__tests__/components/JansLockFieldRenderer.test.tsx
  • admin-ui/plugins/jans-lock/__tests__/components/constants.test.ts
  • admin-ui/plugins/jans-lock/__tests__/components/helperConstants.test.ts
  • admin-ui/plugins/jans-lock/__tests__/components/utils.test.ts
  • admin-ui/plugins/jans-lock/__tests__/components/validations.test.ts
  • admin-ui/plugins/jans-lock/components/JansLock.tsx
  • admin-ui/plugins/jans-lock/components/JansLockConfiguration.tsx
  • admin-ui/plugins/jans-lock/components/JansLockFieldRenderer.tsx
  • admin-ui/plugins/jans-lock/components/constants.ts
  • admin-ui/plugins/jans-lock/components/styles/JansLockFormPage.style.ts
  • admin-ui/plugins/jans-lock/helper/index.ts
  • admin-ui/plugins/jans-lock/helper/utils.ts
  • admin-ui/plugins/jans-lock/helper/validations.ts
  • admin-ui/plugins/jans-lock/types/jans-lock-types.ts
  • admin-ui/plugins/saml/components/WebsiteSsoIdentityProviderForm.tsx
  • admin-ui/plugins/saml/components/WebsiteSsoServiceProviderForm.tsx
  • admin-ui/plugins/schema/__tests__/components/AttributeAddPage.test.js
  • admin-ui/plugins/schema/__tests__/components/AttributeDetailPage.test.js
  • admin-ui/plugins/schema/__tests__/components/AttributeEditPage.test.js
  • admin-ui/plugins/schema/__tests__/components/AttributeListPage.test.js
  • 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/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/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/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/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
💤 Files with no reviewable changes (10)
  • admin-ui/plugins/schema/components/Person/AttributeForm.tsx
  • admin-ui/plugins/schema/components/Person/AttributeAddPage.tsx
  • admin-ui/plugins/schema/tests/components/AttributeDetailPage.test.js
  • admin-ui/plugins/schema/components/Person/AttributeDetailPage.tsx
  • admin-ui/plugins/schema/components/Person/AttributeViewPage.tsx
  • admin-ui/plugins/schema/tests/components/AttributeEditPage.test.js
  • admin-ui/plugins/schema/tests/components/AttributeListPage.test.js
  • admin-ui/plugins/schema/tests/components/AttributeAddPage.test.js
  • admin-ui/plugins/schema/components/Person/AttributeListPage.tsx
  • admin-ui/plugins/schema/components/Person/AttributeEditPage.tsx

showApply={!hideButtons?.save}
applyButtonType="submit"
disableApply={!canApply}
isLoading={false}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Consider making isLoading dynamic.

isLoading={false} is hardcoded. If the parent component passes a loading state (e.g., during submission), this should reflect it to disable the footer buttons and show appropriate feedback.

🔧 Suggested improvement

Consider accepting an isLoading or isSubmitting prop:

+// In props interface
+isLoading?: boolean

 <GluuThemeFormFooter
   // ...
-  isLoading={false}
+  isLoading={props.isLoading ?? false}
 />

Alternatively, if this form is only used in contexts where loading state is not needed, document this intentional choice with a comment.

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

In `@admin-ui/plugins/schema/components/Person/UserClaimsForm.tsx` at line 488,
The hardcoded isLoading={false} in UserClaimsForm should be made dynamic: add an
isLoading or isSubmitting boolean prop to the UserClaimsForm component (update
its props interface) and use that prop when rendering the footer control (where
isLoading is currently set) — e.g., pass props.isLoading (or internal submitting
state) into the FormFooter/Button isLoading prop so footer buttons disable and
show loading during submission; if you intentionally don't need a loading state,
add a concise comment near the isLoading line explaining why it's fixed false.

Comment on lines +82 to +88
return {
...baseMutation,
mutate: (...args: Parameters<typeof mutateAsync>) => {
mutateAsync(...args).catch(() => {})
},
mutateAsync,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t swallow failures from the post-write side-effect chain.

These wrappers still expose ...baseMutation, so callers can observe success as soon as the HTTP write finishes. The wrapper then keeps doing invalidation/webhook/audit work, but Lines 85, 135, and 182 drop any rejection from that second phase. That can produce a success toast/navigation even when the follow-up work failed. Please surface or at least log those errors instead of ignoring them.

Also applies to: 132-138, 179-185

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

In `@admin-ui/plugins/schema/hooks/useAttributeApi.ts` around lines 82 - 88, The
wrapper currently calls mutateAsync(...args).catch(() => {}) which swallows any
errors from the post-write side-effect chain; change the wrapper for mutate (and
the analogous wrappers around mutateAsync at the other spots) to return the
promise from mutateAsync and handle failures by either rethrowing or at minimum
logging the error so callers see/report failures: update the mutate
implementation (and the other two wrappers) so it does return
mutateAsync(...args).catch(err => { console.error('post-write side-effect
failed', err); throw err; }) or otherwise propagate the rejection instead of
swallowing it, ensuring baseMutation and mutateAsync behavior is preserved.

Comment on lines +25 to +27
successMessage: string
errorMessage: string
navigateOnSuccess?: boolean
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Inject the success destination instead of hard-coding it.

useMutationEffects is generic and exported from the schema hooks, but Line 52 always navigates to ROUTES.ATTRIBUTES_LIST. That means any other flow can only disable navigation entirely, not choose the correct destination. Please make the target route/callback part of the hook options.

Also applies to: 51-53

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

In `@admin-ui/plugins/schema/hooks/useMutationEffects.ts` around lines 25 - 27,
The hook useMutationEffects currently hard-codes navigation to
ROUTES.ATTRIBUTES_LIST on success (lines around the success handling) which
prevents callers from choosing a different destination; modify the hook
signature to accept a success destination/callback option (e.g.,
successDestination?: string | (data: any) => void or onSuccessNavigate?:
(data)=>void) alongside the existing
successMessage/errorMessage/navigateOnSuccess options, and replace the direct
call to navigate(ROUTES.ATTRIBUTES_LIST) with logic that calls the provided
destination or callback when present (falling back to navigateOnSuccess behavior
if you must preserve it); update callers to pass the desired route or callback
instead of relying on the hard-coded ROUTES.ATTRIBUTES_LIST.

Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
@faisalsiddique4400 faisalsiddique4400 marked this pull request as draft March 18, 2026 08:37
Signed-off-by: faisalsiddique4400 <faisalsiddique10886@gmail.com>
@sonarqubecloud
Copy link

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 Jans-lock module as per Figma

2 participants