Skip to content

Conversation

@faisalsiddique4400
Copy link
Contributor

@faisalsiddique4400 faisalsiddique4400 commented Nov 5, 2025

feat(admin): adding uniformity in cancel and back buttons present in Users and App-wide navigation via named ROUTES with navigate helpers.

Summary

This update introduces consistent behavior for Cancel, Back, and Apply buttons across Admin UI forms, including correct enabling and disabling based on form state.

Improvements

Button Updated Behavior
Cancel Resets all fields to their previous values without navigating away. Disabled until a change is made.
Back Navigates to the previous page. If there is no navigation history, returns to Dashboard. Always enabled.
Apply Saves the changes without leaving the page. Enabled only when the form has unsaved changes.

Additional Enhancements

  • Buttons now correctly detect dirty form states.
  • Apply button is dynamically enabled and disabled based on whether changes exist.
  • Cancel button is disabled until a field is modified.
  • Prevents accidental navigation or state loss in multi step configuration pages.

Affected Modules

This change is applied across all forms where configuration changes are possible, including but not limited to:

  • Users

Parent issue: #2268

Testing Steps

  1. Open suggested config form.
  2. Modify any field.
  3. Verify that:
    • Apply and Cancel buttons become enabled.
    • Apply saves configuration and stays on page.
    • Cancel reverts values and disables itself afterward.
  4. Back button should navigate appropriately.

Summary by CodeRabbit

  • New Features

    • Manage user 2FA devices (FIDO2 & OTP) from a dedicated modal.
    • Improved password-change flow with confirmation, validation and audit-friendly handling.
  • Improvements

    • Many forms now use validated, commit/confirm workflows with a unified form footer and better submit/cancel behavior.
    • Centralized navigation with named routes and back helpers; numerous pages updated to use it.
    • New initializers/helpers and memoization across scopes, assets, webhooks and settings for performance and stability.
  • Localization

    • Added "Confirm Password" and additional-parameters validation messages in EN/ES/FR/PT.

✏️ Tip: You can customize this high-level summary in your review settings.

faisalsiddique4400 and others added 30 commits October 30, 2025 13:55
…Jans Lock (#2405)

* feat(admin): adding uniformity in cancel and back buttons present in Jans Lock

* feat(admin): adding uniformity in cancel and back buttons present in Jans Lock

* Code Rabbit fixes
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: 7

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/services/Components/Configuration/LdapAddPage.js (1)

15-23: Add missing dependencies to useEffect.

The useEffect hook uses navigateBack and dispatch but doesn't include them in the dependency array. This violates the React hooks exhaustive-deps rule and could lead to stale closures.

Apply this diff to fix the dependency array:

     return () => {
       dispatch(toggleSavedFormFlag(false))
     }
-  }, [savedForm])
+  }, [savedForm, navigateBack, dispatch])
♻️ Duplicate comments (4)
admin-ui/plugins/auth-server/components/Configuration/ConfigApiConfiguration/ApiConfigForm.tsx (1)

76-78: Use navigateBack with dashboard fallback for Back button

The Back button currently always routes directly to HOME_DASHBOARD, ignoring browser history. Using navigateBack(ROUTES.HOME_DASHBOARD) would honor actual navigation history when available while maintaining the dashboard fallback.

Apply this diff:

-  const { navigateToRoute } = useAppNavigation()
+  const { navigateBack } = useAppNavigation()

   const handleBack = () => {
-    navigateToRoute(ROUTES.HOME_DASHBOARD)
+    navigateBack(ROUTES.HOME_DASHBOARD)
   }

Also update line 34 to destructure navigateBack instead of navigateToRoute.

admin-ui/plugins/user-management/components/UserEditPage.tsx (1)

43-43: Type casting via unknown is a workaround.

Similar to UserAddPage.tsx, the double cast as unknown as PersonAttribute[] works around a type mismatch. Consider the same refactoring approach suggested for UserAddPage to improve type safety.

admin-ui/plugins/user-management/components/UserList.tsx (1)

120-123: Use stable domain identifier (inum) instead of tableData.uuid for edit navigation

The edit action currently derives the route id as:

const userId = row.tableData?.uuid || row.inum

tableData.uuid is a MaterialTable‑internal identifier, not a stable domain key, while the table explicitly configures idSynonym: 'inum'. Routing via an internal uuid risks breakage if MaterialTable changes its internals or if uuid differs from the backend user identifier.

Prefer the domain identifier (e.g., inum, or userId if that is the real key) and drop reliance on tableData.uuid:

-      const userData = row as unknown as CustomUser
-      const userId = row.tableData?.uuid || row.inum
+      const userData = row as unknown as CustomUser
+      const userId = row.inum || row.userId
       if (!userId) return
       navigateToRoute(ROUTES.USER_EDIT(userId), { state: { selectedUser: userData } })

Please align userId with what ROUTES.USER_EDIT and the backend expect.

Also applies to: 146-154, 219-233

admin-ui/plugins/user-management/components/UserForm.tsx (1)

34-79: Cancel still doesn’t fully revert dynamically added custom claims

setupCustomAttributes appends attributes from userDetails.customAttributes onto the existing selectedClaims:

setSelectedClaims((prevSelectedClaims) => {
  const existingClaimNames = new Set(prevSelectedClaims.map((claim) => claim.name))
  const tempList = [...prevSelectedClaims]
  ...
  tempList.push(data)
  ...
  return tempList
})

handleCancel calls setupCustomAttributes without clearing selectedClaims first:

const handleCancel = useCallback(() => {
  const resetValues = initializeCustomAttributes(...)
  formik.resetForm({ values: resetValues })
  setModifiedFields({})
  if (userDetails) {
    setupCustomAttributes(userDetails, memoizedPersonAttributes, setSelectedClaims)
    initializedRef.current = userDetails.inum || 'new'
  } else {
    setSelectedClaims([])
    initializedRef.current = 'new'
  }
}, ...)

If the user added new custom claims during this session that are not present in userDetails.customAttributes, those extra claims remain in selectedClaims after Cancel, so their rows stay visible even though the form values were reset. This means Cancel does not fully restore the original dynamic-claims UI state.

Reset selectedClaims before repopulating from userDetails so Cancel truly reverts to the initial set of claims:

 const handleCancel = useCallback(() => {
   const resetValues = initializeCustomAttributes(userDetails || null, memoizedPersonAttributes)
   formik.resetForm({ values: resetValues })
   setModifiedFields({})
   if (userDetails) {
-    setupCustomAttributes(userDetails, memoizedPersonAttributes, setSelectedClaims)
-    initializedRef.current = userDetails.inum || 'new'
+    // Drop any newly added claims and restore from original userDetails
+    setSelectedClaims([])
+    setupCustomAttributes(userDetails, memoizedPersonAttributes, setSelectedClaims)
+    initializedRef.current = userDetails.inum || 'new'
   } else {
     setSelectedClaims([])
     initializedRef.current = 'new'
   }
 }, [formik, userDetails, memoizedPersonAttributes, setSelectedClaims])

This keeps the initialization guard while ensuring Cancel resets both field values and dynamic claim rows.

Also applies to: 155-167, 182-185, 186-203, 383-393

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c12b3ef and 90b709e.

📒 Files selected for processing (28)
  • admin-ui/app/helpers/navigation.ts (1 hunks)
  • admin-ui/app/routes/Apps/Gluu/GluuAppSidebar.tsx (3 hunks)
  • admin-ui/app/routes/Apps/Gluu/GluuFormFooter.tsx (5 hunks)
  • admin-ui/app/routes/Apps/Gluu/GluuSessionTimeout.tsx (3 hunks)
  • admin-ui/app/routes/Apps/Gluu/GluuTabs.tsx (4 hunks)
  • admin-ui/app/routes/Apps/Profile/ProfilePage.tsx (2 hunks)
  • admin-ui/app/routes/Dashboards/DashboardPage.tsx (3 hunks)
  • admin-ui/app/routes/License/LicenseDetailsPage.tsx (2 hunks)
  • admin-ui/app/routes/components/Dropdowns/DropdownProfile.tsx (1 hunks)
  • admin-ui/plugins/auth-server/components/Configuration/ConfigApiConfiguration/ApiConfigForm.tsx (3 hunks)
  • admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js (2 hunks)
  • admin-ui/plugins/saml/components/SamlIdentityList.js (3 hunks)
  • admin-ui/plugins/saml/components/SamlIdpForm.js (3 hunks)
  • admin-ui/plugins/saml/components/TrustRelationForm.js (3 hunks)
  • admin-ui/plugins/saml/components/TrustRelationshipList.js (3 hunks)
  • admin-ui/plugins/schema/components/Person/AttributeAddPage.tsx (2 hunks)
  • admin-ui/plugins/schema/components/Person/AttributeEditPage.tsx (3 hunks)
  • admin-ui/plugins/schema/components/Person/AttributeListPage.tsx (4 hunks)
  • admin-ui/plugins/services/Components/Configuration/LdapAddPage.js (1 hunks)
  • admin-ui/plugins/services/Components/Configuration/LdapEditPage.js (1 hunks)
  • admin-ui/plugins/services/Components/Configuration/LdapListPage.js (5 hunks)
  • admin-ui/plugins/services/Components/Configuration/SqlAddPage.js (1 hunks)
  • admin-ui/plugins/services/Components/Configuration/SqlEditPage.js (1 hunks)
  • admin-ui/plugins/services/Components/Configuration/SqlListPage.js (4 hunks)
  • admin-ui/plugins/user-management/components/UserAddPage.tsx (3 hunks)
  • admin-ui/plugins/user-management/components/UserEditPage.tsx (4 hunks)
  • admin-ui/plugins/user-management/components/UserForm.tsx (5 hunks)
  • admin-ui/plugins/user-management/components/UserList.tsx (6 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.
📚 Learning: 2025-11-05T19:57:35.143Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2415
File: admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx:148-153
Timestamp: 2025-11-05T19:57:35.143Z
Learning: In the SSA Add page (admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx), the Back button should fall back to '/auth-server/config/ssa' when browser history is unavailable, not '/home/dashboard', as this keeps users in the SSA management context.

Applied to files:

  • admin-ui/plugins/services/Components/Configuration/SqlAddPage.js
  • admin-ui/plugins/auth-server/components/Configuration/ConfigApiConfiguration/ApiConfigForm.tsx
  • admin-ui/plugins/user-management/components/UserAddPage.tsx
  • admin-ui/app/routes/Apps/Profile/ProfilePage.tsx
  • admin-ui/plugins/schema/components/Person/AttributeEditPage.tsx
  • admin-ui/app/routes/Apps/Gluu/GluuAppSidebar.tsx
  • admin-ui/plugins/user-management/components/UserForm.tsx
  • admin-ui/plugins/saml/components/TrustRelationForm.js
  • admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js
  • admin-ui/plugins/services/Components/Configuration/LdapListPage.js
  • admin-ui/plugins/services/Components/Configuration/LdapEditPage.js
  • admin-ui/plugins/saml/components/SamlIdpForm.js
  • admin-ui/app/routes/Apps/Gluu/GluuFormFooter.tsx
  • admin-ui/app/routes/Apps/Gluu/GluuSessionTimeout.tsx
  • admin-ui/plugins/saml/components/SamlIdentityList.js
  • admin-ui/app/helpers/navigation.ts
  • admin-ui/app/routes/Dashboards/DashboardPage.tsx
  • admin-ui/plugins/services/Components/Configuration/LdapAddPage.js
  • admin-ui/plugins/schema/components/Person/AttributeAddPage.tsx
  • admin-ui/plugins/services/Components/Configuration/SqlEditPage.js
📚 Learning: 2025-11-06T08:23:20.948Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.

Applied to files:

  • admin-ui/plugins/services/Components/Configuration/SqlAddPage.js
  • admin-ui/plugins/user-management/components/UserEditPage.tsx
  • admin-ui/plugins/auth-server/components/Configuration/ConfigApiConfiguration/ApiConfigForm.tsx
  • admin-ui/plugins/schema/components/Person/AttributeListPage.tsx
  • admin-ui/app/routes/License/LicenseDetailsPage.tsx
  • admin-ui/plugins/user-management/components/UserAddPage.tsx
  • admin-ui/app/routes/Apps/Profile/ProfilePage.tsx
  • admin-ui/plugins/schema/components/Person/AttributeEditPage.tsx
  • admin-ui/app/routes/Apps/Gluu/GluuAppSidebar.tsx
  • admin-ui/plugins/user-management/components/UserForm.tsx
  • admin-ui/plugins/saml/components/TrustRelationForm.js
  • admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js
  • admin-ui/plugins/services/Components/Configuration/LdapListPage.js
  • admin-ui/plugins/user-management/components/UserList.tsx
  • admin-ui/plugins/services/Components/Configuration/LdapEditPage.js
  • admin-ui/plugins/saml/components/SamlIdpForm.js
  • admin-ui/app/routes/Apps/Gluu/GluuFormFooter.tsx
  • admin-ui/app/routes/Apps/Gluu/GluuSessionTimeout.tsx
  • admin-ui/plugins/saml/components/SamlIdentityList.js
  • admin-ui/app/routes/components/Dropdowns/DropdownProfile.tsx
  • admin-ui/app/helpers/navigation.ts
  • admin-ui/app/routes/Dashboards/DashboardPage.tsx
  • admin-ui/plugins/services/Components/Configuration/LdapAddPage.js
  • admin-ui/plugins/schema/components/Person/AttributeAddPage.tsx
  • admin-ui/plugins/services/Components/Configuration/SqlEditPage.js
📚 Learning: 2025-11-03T08:47:33.943Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.

Applied to files:

  • admin-ui/plugins/services/Components/Configuration/SqlAddPage.js
  • admin-ui/plugins/auth-server/components/Configuration/ConfigApiConfiguration/ApiConfigForm.tsx
  • admin-ui/app/routes/Apps/Gluu/GluuAppSidebar.tsx
  • admin-ui/plugins/user-management/components/UserForm.tsx
  • admin-ui/plugins/saml/components/TrustRelationForm.js
  • admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js
  • admin-ui/plugins/services/Components/Configuration/LdapEditPage.js
  • admin-ui/plugins/saml/components/SamlIdpForm.js
  • admin-ui/app/routes/Apps/Gluu/GluuFormFooter.tsx
  • admin-ui/app/routes/Apps/Gluu/GluuSessionTimeout.tsx
  • admin-ui/app/helpers/navigation.ts
  • admin-ui/plugins/services/Components/Configuration/LdapAddPage.js
  • admin-ui/plugins/services/Components/Configuration/SqlEditPage.js
🧬 Code graph analysis (21)
admin-ui/plugins/services/Components/Configuration/SqlAddPage.js (2)
admin-ui/app/helpers/navigation.ts (1)
  • useAppNavigation (66-95)
admin-ui/app/utils/PermChecker.ts (1)
  • buildPayload (153-160)
admin-ui/plugins/schema/components/Person/AttributeListPage.tsx (12)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js (1)
  • useAppNavigation (29-29)
admin-ui/plugins/saml/components/SamlIdentityList.js (1)
  • useAppNavigation (59-59)
admin-ui/plugins/saml/components/SamlIdpForm.js (1)
  • useAppNavigation (37-37)
admin-ui/plugins/saml/components/TrustRelationForm.js (1)
  • useAppNavigation (47-47)
admin-ui/plugins/saml/components/TrustRelationshipList.js (1)
  • useAppNavigation (36-36)
admin-ui/plugins/services/Components/Configuration/LdapAddPage.js (1)
  • useAppNavigation (12-12)
admin-ui/plugins/services/Components/Configuration/LdapEditPage.js (1)
  • useAppNavigation (14-14)
admin-ui/plugins/services/Components/Configuration/LdapListPage.js (1)
  • useAppNavigation (46-46)
admin-ui/plugins/services/Components/Configuration/SqlAddPage.js (1)
  • useAppNavigation (13-13)
admin-ui/plugins/services/Components/Configuration/SqlEditPage.js (1)
  • useAppNavigation (15-15)
admin-ui/plugins/services/Components/Configuration/SqlListPage.js (1)
  • useAppNavigation (76-76)
admin-ui/app/routes/License/LicenseDetailsPage.tsx (2)
admin-ui/app/redux/features/licenseDetailsSlice.ts (1)
  • LicenseDetailsState (21-24)
admin-ui/app/helpers/navigation.ts (1)
  • useAppNavigation (66-95)
admin-ui/plugins/user-management/components/UserAddPage.tsx (4)
admin-ui/app/helpers/navigation.ts (1)
  • useAppNavigation (66-95)
admin-ui/plugins/user-management/types/UserApiTypes.ts (1)
  • PersonAttribute (6-6)
admin-ui/plugins/user-management/helper/userAuditHelpers.ts (1)
  • logUserCreation (100-128)
admin-ui/plugins/user-management/helper/userWebhookHelpers.ts (1)
  • triggerUserWebhook (14-26)
admin-ui/app/routes/Apps/Profile/ProfilePage.tsx (2)
admin-ui/app/routes/Apps/Profile/types.ts (2)
  • ProfileDetails (8-15)
  • AppDispatch (44-44)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/schema/components/Person/AttributeEditPage.tsx (2)
admin-ui/plugins/services/Components/Configuration/LdapAddPage.js (2)
  • dispatch (10-10)
  • useAppNavigation (12-12)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/app/routes/Apps/Gluu/GluuAppSidebar.tsx (1)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/saml/components/TrustRelationForm.js (1)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js (1)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/saml/components/TrustRelationshipList.js (2)
admin-ui/app/helpers/navigation.ts (1)
  • useAppNavigation (66-95)
admin-ui/plugins/saml/components/SamlIdentityList.js (1)
  • useAppNavigation (59-59)
admin-ui/app/routes/Apps/Gluu/GluuTabs.tsx (1)
admin-ui/app/customColors.ts (1)
  • customColors (4-25)
admin-ui/plugins/user-management/components/UserList.tsx (4)
admin-ui/plugins/user-management/types/ComponentTypes.ts (1)
  • UserTableRowData (54-77)
admin-ui/plugins/user-management/types/CommonTypes.ts (1)
  • ThemeContext (13-17)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/user-management/types/UserApiTypes.ts (1)
  • CustomUser (5-5)
admin-ui/plugins/services/Components/Configuration/LdapEditPage.js (1)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/saml/components/SamlIdpForm.js (2)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/services/Components/Configuration/LdapListPage.js (1)
  • useAppNavigation (46-46)
admin-ui/app/routes/Apps/Gluu/GluuSessionTimeout.tsx (12)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js (1)
  • useAppNavigation (29-29)
admin-ui/plugins/saml/components/SamlIdentityList.js (1)
  • useAppNavigation (59-59)
admin-ui/plugins/saml/components/SamlIdpForm.js (1)
  • useAppNavigation (37-37)
admin-ui/plugins/saml/components/TrustRelationForm.js (1)
  • useAppNavigation (47-47)
admin-ui/plugins/saml/components/TrustRelationshipList.js (1)
  • useAppNavigation (36-36)
admin-ui/plugins/services/Components/Configuration/LdapAddPage.js (1)
  • useAppNavigation (12-12)
admin-ui/plugins/services/Components/Configuration/LdapEditPage.js (1)
  • useAppNavigation (14-14)
admin-ui/plugins/services/Components/Configuration/LdapListPage.js (1)
  • useAppNavigation (46-46)
admin-ui/plugins/services/Components/Configuration/SqlAddPage.js (1)
  • useAppNavigation (13-13)
admin-ui/plugins/services/Components/Configuration/SqlEditPage.js (1)
  • useAppNavigation (15-15)
admin-ui/plugins/services/Components/Configuration/SqlListPage.js (1)
  • useAppNavigation (76-76)
admin-ui/plugins/saml/components/SamlIdentityList.js (13)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js (1)
  • useAppNavigation (29-29)
admin-ui/plugins/saml/components/SamlIdpForm.js (1)
  • useAppNavigation (37-37)
admin-ui/plugins/saml/components/TrustRelationForm.js (1)
  • useAppNavigation (47-47)
admin-ui/plugins/saml/components/TrustRelationshipList.js (1)
  • useAppNavigation (36-36)
admin-ui/plugins/services/Components/Configuration/LdapAddPage.js (1)
  • useAppNavigation (12-12)
admin-ui/plugins/services/Components/Configuration/LdapEditPage.js (1)
  • useAppNavigation (14-14)
admin-ui/plugins/services/Components/Configuration/LdapListPage.js (1)
  • useAppNavigation (46-46)
admin-ui/plugins/services/Components/Configuration/SqlAddPage.js (1)
  • useAppNavigation (13-13)
admin-ui/plugins/services/Components/Configuration/SqlEditPage.js (1)
  • useAppNavigation (15-15)
admin-ui/plugins/services/Components/Configuration/SqlListPage.js (1)
  • useAppNavigation (76-76)
admin-ui/plugins/admin/components/Webhook/WebhookListPage.js (1)
  • useAppNavigation (31-31)
admin-ui/plugins/auth-server/components/Clients/ClientEditPage.js (1)
  • viewOnly (16-16)
admin-ui/app/routes/components/Dropdowns/DropdownProfile.tsx (1)
admin-ui/app/helpers/navigation.ts (1)
  • useAppNavigation (66-95)
admin-ui/plugins/services/Components/Configuration/SqlListPage.js (4)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/services/Components/Configuration/SqlAddPage.js (3)
  • useAppNavigation (13-13)
  • dispatch (10-10)
  • userAction (12-12)
admin-ui/plugins/services/Components/Configuration/SqlEditPage.js (3)
  • useAppNavigation (15-15)
  • dispatch (12-12)
  • userAction (14-14)
admin-ui/app/utils/PermChecker.ts (1)
  • buildPayload (153-160)
admin-ui/app/routes/Dashboards/DashboardPage.tsx (1)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/services/Components/Configuration/LdapAddPage.js (1)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/services/Components/Configuration/SqlEditPage.js (2)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/app/utils/PermChecker.ts (1)
  • buildPayload (153-160)
🔇 Additional comments (30)
admin-ui/app/routes/components/Dropdowns/DropdownProfile.tsx (1)

3-3: LGTM! Clean migration to centralized navigation.

The refactoring successfully migrates from direct useNavigate usage to the centralized useAppNavigation hook and replaces hardcoded paths with ROUTES constants. The changes improve maintainability while preserving all original functionality:

  • Logout flow remains intact (audit log → navigate on success)
  • Profile link correctly uses ROUTES.PROFILE
  • Effect dependencies properly updated to include navigateToRoute

This aligns well with the PR's objective to standardize navigation patterns across the admin UI.

Also applies to: 7-7, 13-13, 21-21, 23-23, 31-31

admin-ui/plugins/schema/components/Person/AttributeAddPage.tsx (1)

16-32: Attribute add success navigation correctly uses centralized helper

Using navigateBack(ROUTES.ATTRIBUTES_LIST) on successful create gives the expected “back to where I came from, else to attributes list” behavior and aligns with the pattern of falling back to the relevant listing screen instead of the dashboard.
Based on learnings, this matches the intended listing‑screen fallback behavior for schema-related forms.

admin-ui/app/routes/License/LicenseDetailsPage.tsx (1)

22-55: License expiry logout flow is correctly centralized

Redirecting on item.licenseExpired via navigateToRoute(ROUTES.LOGOUT) cleanly reuses the shared navigation helper and centralized route constants, with a safe dependency list on the effect. Behavior and wiring look good.

admin-ui/app/routes/Apps/Gluu/GluuSessionTimeout.tsx (1)

6-7: Session timeout logout navigation is consistent with shared helper

Hooking logoutAuditSucceeded to navigateToRoute(ROUTES.LOGOUT) makes the timeout flow use the same centralized logout route as the rest of the app, with correct effect dependencies.

Also applies to: 22-24, 79-84

admin-ui/app/helpers/navigation.ts (1)

1-97: Navigation helper and ROUTES centralization look solid and fix prior footguns

The new ROUTES constant plus useAppNavigation (navigateToRoute, navigateBack, navigate) provide a clear, centralized navigation API. Dynamic routes correctly use encodeURIComponent, and navigateBack(fallbackRoute) cleanly supports “back with listing-screen fallback” behavior. Importantly, navigateToRoute now only accepts a string path and no longer auto‑invokes function‑valued routes with empty parameters, addressing the earlier USER_EDIT footgun from previous reviews.
Based on learnings, this aligns with the agreed back‑navigation semantics for dashboard and listing screens.

admin-ui/app/routes/Apps/Gluu/GluuAppSidebar.tsx (1)

32-33: Sidebar logout redirect correctly uses shared navigation helper

Redirecting from the sidebar on logoutAuditSucceeded === true via navigateToRoute(ROUTES.LOGOUT) is consistent with other parts of the app and centralizes logout routing through the navigation helper. Dependencies are correct.

Also applies to: 92-93, 179-183

admin-ui/app/routes/Dashboards/DashboardPage.tsx (1)

30-31: Dashboard permission-based logout wiring is correct

Switching the “no access token” branch in handleLogout to navigateToRoute(ROUTES.LOGOUT) keeps the existing behavior while centralizing the logout path through the shared navigation helper. Dependencies on access_token, dispatch, and navigateToRoute are appropriate.

Also applies to: 64-65, 342-353

admin-ui/plugins/services/Components/Configuration/LdapEditPage.js (1)

8-25: LGTM! Navigation implementation follows best practices.

The implementation correctly uses navigateBack(ROUTES.LDAP_LIST) to navigate after save, keeping users in the LDAP management context. The dependency array is properly updated to include navigateBack and dispatch.

Based on learnings, this aligns with the requirement that users should be redirected to the respective listing screen rather than the dashboard.

admin-ui/plugins/schema/components/Person/AttributeEditPage.tsx (1)

28-101: LGTM! Navigation implementation follows best practices.

The implementation correctly uses navigateBack(ROUTES.ATTRIBUTES_LIST) after successful attribute update, keeping users in the attribute management context. The dependency array is properly updated to include navigateBack.

Based on learnings, this aligns with the requirement that users should be redirected to the respective listing screen rather than the dashboard.

admin-ui/plugins/saml/components/SamlIdentityList.js (1)

86-95: LGTM! Forward navigation correctly uses navigateToRoute.

The handlers correctly use navigateToRoute for forward navigation to edit and add pages. This is the appropriate choice for list-to-detail navigation (as opposed to navigateBack which is for returning from detail to list).

admin-ui/plugins/services/Components/Configuration/SqlEditPage.js (1)

7-23: LGTM! Navigation implementation follows best practices.

The implementation correctly uses navigateBack(ROUTES.SQL_LIST) after form submission, keeping users in the SQL database configuration context.

Based on learnings, this aligns with the requirement that users should be redirected to the respective listing screen rather than the dashboard.

admin-ui/plugins/saml/components/TrustRelationForm.js (1)

214-223: LGTM! Navigation implementation follows best practices.

The implementation correctly uses navigateBack(ROUTES.SAML_SP_LIST) after saving the trust relationship, keeping users in the SAML service provider context. The dependency array is properly updated to include navigateBack and dispatch.

Based on learnings, this aligns with the requirement that users should be redirected to the respective listing screen rather than the dashboard.

admin-ui/plugins/saml/components/SamlIdpForm.js (1)

162-170: LGTM! Navigation implementation follows best practices.

The implementation correctly uses navigateBack(ROUTES.SAML_IDP_LIST) after saving the identity provider, keeping users in the SAML identity provider context. The dependency array is properly updated to include navigateBack and dispatch.

Based on learnings, this aligns with the requirement that users should be redirected to the respective listing screen rather than the dashboard.

admin-ui/plugins/services/Components/Configuration/SqlAddPage.js (2)

7-7: LGTM: Navigation imports are correct.

The centralized navigation approach using useAppNavigation and ROUTES aligns with the PR objectives.


13-20: LGTM: Back navigation with context-appropriate fallback.

Using navigateBack(ROUTES.SQL_LIST) after successful submission keeps users in the SQL configuration context, which aligns with the established pattern. Based on learnings, fallback routes should direct users to the respective listing screen rather than the dashboard.

admin-ui/app/routes/Apps/Gluu/GluuFormFooter.tsx (1)

7-7: LGTM: Footer navigation refactor with extensible API.

The addition of backIconClass prop and the switch to useAppNavigation provides a clean, extensible API. The default fallback to ROUTES.HOME_DASHBOARD is sensible for the global component while allowing context-specific overrides via the onBack prop.

Also applies to: 21-21, 58-58

admin-ui/plugins/saml/components/TrustRelationshipList.js (2)

21-21: LGTM: Navigation imports are correct.

The centralized navigation approach is consistent with the PR objectives.

Also applies to: 36-36


62-71: LGTM: Navigation handlers updated correctly.

The callbacks use navigateToRoute with ROUTES constants and have proper dependency arrays including navigateToRoute. The state passing is preserved correctly.

admin-ui/app/routes/Apps/Profile/ProfilePage.tsx (1)

17-17: LGTM: Navigation imports are correct.

The centralized navigation approach is consistent across the codebase.

Also applies to: 27-27

admin-ui/plugins/schema/components/Person/AttributeListPage.tsx (2)

4-4: LGTM: Navigation imports are correct.

The centralized navigation approach aligns with the PR objectives.

Also applies to: 139-139


195-221: LGTM: Navigation handlers with proper guards.

The early return checks (if (!row?.inum) return) prevent navigation with invalid data, and dependency arrays are correctly updated to include navigateToRoute. This is a defensive coding practice that prevents potential runtime errors.

admin-ui/plugins/services/Components/Configuration/LdapAddPage.js (1)

7-7: LGTM: Navigation imports are correct.

The centralized navigation approach is consistent with other add pages.

Also applies to: 12-12

admin-ui/plugins/user-management/components/UserAddPage.tsx (2)

2-2: LGTM: Navigation refactor is correct.

Using useAppNavigation and navigating to ROUTES.USER_MANAGEMENT keeps users in the user-management context, consistent with the established pattern.

Also applies to: 25-25


124-126: LGTM: Loader wraps form content.

The GluuLoader now wraps the UserForm with blocking={loadingAttributes}, which provides a consistent loading UX while attributes are fetched.

admin-ui/plugins/user-management/components/UserEditPage.tsx (2)

3-3: LGTM: Navigation refactor is correct.

Replacing useNavigate with useAppNavigation and using ROUTES constants aligns with the PR objectives.

Also applies to: 27-27


60-60: LGTM: Consistent navigation and loader pattern.

Navigation to ROUTES.USER_MANAGEMENT after successful update keeps users in the user-management context. The loader wrapper provides consistent UX during attribute loading.

Also applies to: 185-187

admin-ui/plugins/services/Components/Configuration/SqlListPage.js (1)

4-4: Navigation refactor and guard look correct

Using useAppNavigation with navigateToRoute / navigateBack and the ROUTES.SQL_* constants is consistent, and the !row?.configId guard in handleGoToSqlEditPage prevents invalid navigation. The deletion confirm handler correctly routes back to the SQL list via navigateBack(ROUTES.SQL_LIST) with appropriate dependencies.

Also applies to: 76-76, 154-161, 168-171, 172-180

admin-ui/plugins/user-management/components/UserList.tsx (1)

47-48: 2FA devices modal integration and loading/deletion flow look consistent

The new User2FADevicesModal wiring with selectedUserFor2FA / isViewDetailModalOpen, and the useDeleteUser mutation with toast, audit logging, webhook triggering, and query invalidation, are coherently hooked into the list and appear consistent with the rest of the users module.

Also applies to: 97-111, 330-337

admin-ui/plugins/user-management/components/UserForm.tsx (2)

81-92: Back/Apply/Cancel footer wiring aligns with the new UX contract

The combination of:

  • navigateBack(ROUTES.USER_MANAGEMENT) in handleNavigateBack,
  • handleCancel resetting Formik values and modifiedFields,
  • handleApply building operations and opening GluuCommitDialog, and
  • disableCancel={!formik.dirty}, disableApply={!formik.dirty || !formik.isValid}

gives the expected behavior: Back returns to the user listing (via history, with a /user/usersmanagement fallback via ROUTES.USER_MANAGEMENT), Cancel/Apply are enabled only when the form is dirty, and Apply saves without leaving the page. Based on learnings, this matches the updated requirement to fall back to the component’s listing screen rather than the dashboard.

Also applies to: 108-129, 151-154, 168-178, 417-428


93-107: Custom attributes initialization and AvailableClaimsPanel wiring look solid

The use of personAttributes from Redux, the derived personAttributesKey + memoizedPersonAttributes, and the initializedRef guard in the useEffect that calls setupCustomAttributes all work together to avoid redundant recomputation while still reacting to user/attribute changes. The right‑side AvailableClaimsPanel and setSelectedClaimsToState/removeSelectedClaimsFromState hooks are wired coherently to manage dynamic claims.

Also applies to: 110-121, 186-203, 395-415

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

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/services/Components/Configuration/LdapListPage.js (1)

197-205: Past dependency issue resolved, but consider removing unnecessary navigation.

The dependency array now correctly references navigateBack instead of the previously undefined navigate, resolving the past critical issue.

However, calling navigateBack(ROUTES.LDAP_LIST) after deletion appears unnecessary. Since the user is already on the LDAP list page when confirming deletion, the Redux state update from dispatch(deleteLdap(...)) should automatically refresh the table, and toggle() closes the modal. The navigation call could cause unexpected behavior:

  • If browser history exists, it might navigate away from the list page.
  • If no history, it reloads the current page unnecessarily.

Consider removing the navigation call:

 const onDeletionConfirmed = useCallback(
   (message) => {
     buildPayload(userAction, message, item.configId)
     dispatch(deleteLdap({ configId: item.configId }))
-    navigateBack(ROUTES.LDAP_LIST)
     toggle()
   },
-  [item.configId, navigateBack, toggle, dispatch],
+  [item.configId, toggle, dispatch],
 )
♻️ Duplicate comments (8)
admin-ui/app/routes/Apps/Gluu/GluuTabs.tsx (1)

44-58: Previous review concern has been addressed.

The index misalignment issue flagged in the prior review is now resolved. The implementation correctly:

  • Operates on tabNames directly instead of a filtered navigationTabs subset
  • Uses isNavigationTab type guard consistently to handle mixed tab types
  • Keeps value indices aligned with the actual tabNames array

Also applies to: 79-90, 117-144

admin-ui/plugins/user-management/components/PasswordChangeModal.tsx (4)

122-131: Audit log fires before mutation success — may log failed attempts.

logPasswordChange is called immediately after changePasswordMutation.mutate() at lines 127-130, regardless of whether the mutation succeeds. This means failed password change attempts will still be recorded in the audit log as if they succeeded.

Move the audit logging into the mutation's onSuccess handler to ensure only successful changes are logged.

   const changePasswordMutation = usePatchUserByInum({
     mutation: {
-      onSuccess: async (data: CustomUser) => {
+      onSuccess: async (data: CustomUser, variables) => {
         dispatch(updateToast(true, 'success', t('messages.password_changed_successfully')))
-        await triggerUserWebhook(data as Record<string, unknown>)
+        triggerUserWebhook(data)
+        
+        // Log audit after successful password change
+        const auditPayload: Record<string, unknown> = {
+          ...variables.data,
+          inum: userDetails?.inum,
+          performedOn: {
+            user_inum: userDetails?.inum,
+            userId: userDetails?.userId || userDetails?.displayName,
+          },
+          message: 'Password changed', // Consider passing userMessage through context
+        }
+        logPasswordChange(userDetails?.inum || '', auditPayload).catch((error) => {
+          console.error('Failed to log password change:', error)
+        })
+        
         queryClient.invalidateQueries({ queryKey: getGetUserQueryKey() })

Note: You'll need to pass the userMessage through mutation context or reconstruct it in onSuccess.


261-264: disableCancel={false} inconsistent with PR objectives.

The PR aims to standardize Cancel button behavior: "Cancel: resets all fields to their previous values without navigating away; disabled until a change is made."

Currently, disableCancel is hardcoded to false, making Cancel always enabled. For consistency with other forms (UserForm, SmtpForm, ScopeForm, etc.), derive this from passwordFormik.dirty:

                 <GluuFormFooter
                   showBack={false}
                   showCancel={true}
                   showApply={true}
                   onCancel={handleCancel}
                   onApply={handleApply}
-                  disableCancel={false}
+                  disableCancel={!passwordFormik.dirty}
                   disableApply={isApplyDisabled}

31-37: selectedTheme prop is unused.

The prop is destructured as _selectedTheme but never used. If theming for this modal is handled elsewhere, consider removing this prop from both the interface and callers to avoid confusion.


54-70: Type mismatch in triggerUserWebhook call.

Line 58 casts data to Record<string, unknown>, but triggerUserWebhook now expects CustomUser as its parameter (see userWebhookHelpers.ts line 15). Since the mutation's onSuccess already receives data: CustomUser, the cast is unnecessary and introduces a type inconsistency.

       onSuccess: async (data: CustomUser) => {
         dispatch(updateToast(true, 'success', t('messages.password_changed_successfully')))
-        await triggerUserWebhook(data as Record<string, unknown>)
+        triggerUserWebhook(data)

Also, triggerUserWebhook returns void, so the await is unnecessary.

admin-ui/plugins/user-management/components/UserEditPage.tsx (1)

172-176: Typo: useId should be userId.

The property name useId appears to be a typo. Based on the pattern and context, this should be userId.

       performedOn: {
         user_inum: userDetails?.inum,
-        useId: userDetails?.displayName,
+        userId: userDetails?.displayName,
       },
admin-ui/plugins/user-management/helper/validations.ts (1)

113-167: Birthdate and custom-attribute initialization are now robust

The new helpers (processBirthdateAttribute, processMultiValuedAttribute, processSingleValuedAttribute) and initializeCustomAttributes:

  • Stop JSON‑stringifying birthdate before parsing, instead parsing the raw value and only assigning when moment(...).isValid().
  • Respect multi‑valued vs single‑valued attributes when seeding initialValues.
  • Implement the documented fallbacks (familyNamesn, jansStatusstatus) via getUserProperty, with clear JSDoc on initializeCustomAttributes.

This resolves the earlier “Invalid date” regression and keeps initialization behavior consistent with the previous utilities.

Based on prior review feedback, this directly addresses the birthdate and initialization issues that were previously raised.

Also applies to: 176-208

admin-ui/plugins/user-management/components/UserForm.tsx (1)

34-79: Cancel still doesn’t fully reset dynamically added claims

handleCancel now recomputes selectedClaims via setupCustomAttributes, but setupCustomAttributes builds on the previous selectedClaims state (tempList = [...prevSelectedClaims]) without clearing it first. Any custom claims added during the current session but absent from userDetails.customAttributes will remain after Cancel, so the UI doesn’t fully revert.

Make Cancel restore exactly the original claims set for existing users by clearing before re‑setup:

 const handleCancel = useCallback(() => {
   const resetValues = initializeCustomAttributes(userDetails || null, memoizedPersonAttributes)
   formik.resetForm({ values: resetValues })
   setModifiedFields({})
   if (userDetails) {
-    setupCustomAttributes(userDetails, memoizedPersonAttributes, setSelectedClaims)
+    // Ensure we drop any dynamically added claims and rebuild from userDetails
+    setSelectedClaims([])
+    setupCustomAttributes(userDetails, memoizedPersonAttributes, setSelectedClaims)
     initializedRef.current = userDetails.inum || 'new'
   } else {
     setSelectedClaims([])
     initializedRef.current = 'new'
   }
 }, [formik, userDetails, memoizedPersonAttributes, setSelectedClaims])

Alternatively, have setupCustomAttributes itself start by clearing selectedClaims before populating from userDetails.

This is the same behavioral issue previously flagged for Cancel not fully reverting dynamic claims.

Also applies to: 155-166, 186-202

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 90b709e and e786b7e.

📒 Files selected for processing (14)
  • admin-ui/app/routes/Apps/Gluu/GluuTabs.tsx (4 hunks)
  • admin-ui/app/routes/Apps/Profile/ProfilePage.tsx (2 hunks)
  • admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx (1 hunks)
  • admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js (2 hunks)
  • admin-ui/plugins/services/Components/Configuration/LdapListPage.js (5 hunks)
  • admin-ui/plugins/user-management/components/PasswordChangeModal.tsx (1 hunks)
  • admin-ui/plugins/user-management/components/UserAddPage.tsx (5 hunks)
  • admin-ui/plugins/user-management/components/UserEditPage.tsx (6 hunks)
  • admin-ui/plugins/user-management/components/UserForm.tsx (5 hunks)
  • admin-ui/plugins/user-management/helper/userAuditHelpers.ts (3 hunks)
  • admin-ui/plugins/user-management/helper/userWebhookHelpers.ts (1 hunks)
  • admin-ui/plugins/user-management/helper/validations.ts (1 hunks)
  • admin-ui/plugins/user-management/types/ComponentTypes.ts (1 hunks)
  • admin-ui/plugins/user-management/utils/userFormUtils.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.
📚 Learning: 2025-11-03T08:47:33.943Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.

Applied to files:

  • admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx
  • admin-ui/plugins/services/Components/Configuration/LdapListPage.js
  • admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js
  • admin-ui/plugins/user-management/components/UserForm.tsx
📚 Learning: 2025-11-06T08:23:20.948Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.

Applied to files:

  • admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx
  • admin-ui/app/routes/Apps/Profile/ProfilePage.tsx
  • admin-ui/plugins/services/Components/Configuration/LdapListPage.js
  • admin-ui/plugins/user-management/components/UserEditPage.tsx
  • admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js
  • admin-ui/plugins/user-management/components/PasswordChangeModal.tsx
  • admin-ui/plugins/user-management/components/UserForm.tsx
  • admin-ui/plugins/user-management/components/UserAddPage.tsx
📚 Learning: 2025-11-05T19:57:35.143Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2415
File: admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx:148-153
Timestamp: 2025-11-05T19:57:35.143Z
Learning: In the SSA Add page (admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx), the Back button should fall back to '/auth-server/config/ssa' when browser history is unavailable, not '/home/dashboard', as this keeps users in the SSA management context.

Applied to files:

  • admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx
  • admin-ui/plugins/services/Components/Configuration/LdapListPage.js
  • admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js
  • admin-ui/plugins/user-management/components/UserForm.tsx
  • admin-ui/plugins/user-management/components/UserAddPage.tsx
📚 Learning: 2025-11-10T14:18:58.310Z
Learnt from: kdhttps
Repo: GluuFederation/flex PR: 2378
File: admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx:107-109
Timestamp: 2025-11-10T14:18:58.310Z
Learning: In the Cedarling configuration page (admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx), console.error calls should be kept in catch blocks when there are multiple operations in the try block, as they help print the whole error object with details for debugging unexpected errors.

Applied to files:

  • admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx
📚 Learning: 2025-11-07T12:17:39.857Z
Learnt from: kdhttps
Repo: GluuFederation/flex PR: 2378
File: admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx:43-149
Timestamp: 2025-11-07T12:17:39.857Z
Learning: In the Cedarling configuration UI PR (#2378), the `configApiPolicyStoreUrl` field is intentionally out of scope. It relates to config API configuration and will be covered in a separate PR. The current PR focuses on the Admin UI policy store URL (`auiPolicyStoreUrl`).

Applied to files:

  • admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx
📚 Learning: 2025-11-07T12:55:26.241Z
Learnt from: kdhttps
Repo: GluuFederation/flex PR: 2378
File: admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx:93-104
Timestamp: 2025-11-07T12:55:26.241Z
Learning: In the Cedarling configuration feature (admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx), the sync role to scopes mappings operation depends on the `auiPolicyStoreUrl`. The backend fetches content from this URL and syncs roles based on the response. Therefore, the audit log for the sync operation should include the `auiPolicyStoreUrl` in its payload to provide proper audit context.

Applied to files:

  • admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx
  • admin-ui/plugins/user-management/components/PasswordChangeModal.tsx
🧬 Code graph analysis (9)
admin-ui/app/routes/Apps/Profile/ProfilePage.tsx (1)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/user-management/helper/validations.ts (3)
admin-ui/plugins/user-management/types/UserApiTypes.ts (2)
  • CustomUser (5-5)
  • PersonAttribute (6-6)
admin-ui/plugins/user-management/utils/userFormUtils.ts (2)
  • validatePassword (9-16)
  • initializeCustomAttributes (66-100)
admin-ui/plugins/user-management/types/ComponentTypes.ts (1)
  • UserEditFormValues (32-40)
admin-ui/plugins/services/Components/Configuration/LdapListPage.js (3)
admin-ui/app/helpers/navigation.ts (1)
  • useAppNavigation (66-95)
admin-ui/plugins/services/Components/Configuration/LdapAddPage.js (2)
  • useAppNavigation (12-12)
  • dispatch (10-10)
admin-ui/plugins/services/Components/Configuration/SqlListPage.js (2)
  • useAppNavigation (76-76)
  • dispatch (43-43)
admin-ui/plugins/user-management/components/UserEditPage.tsx (5)
admin-ui/app/helpers/navigation.ts (1)
  • useAppNavigation (66-95)
admin-ui/plugins/user-management/types/UserApiTypes.ts (2)
  • CustomUser (5-5)
  • PersonAttribute (6-6)
admin-ui/plugins/user-management/utils/userFormUtils.ts (1)
  • mapToPersonAttributes (144-149)
admin-ui/plugins/user-management/helper/userWebhookHelpers.ts (1)
  • triggerUserWebhook (15-28)
admin-ui/plugins/user-management/types/ComponentTypes.ts (1)
  • FormValueEntry (117-122)
admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js (1)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/user-management/helper/userWebhookHelpers.ts (1)
admin-ui/plugins/user-management/types/UserApiTypes.ts (1)
  • CustomUser (5-5)
admin-ui/plugins/user-management/components/PasswordChangeModal.tsx (5)
admin-ui/plugins/user-management/types/UserFormTypes.ts (1)
  • PasswordChangeModalProps (23-31)
admin-ui/plugins/user-management/types/UserApiTypes.ts (1)
  • CustomUser (5-5)
admin-ui/plugins/user-management/helper/userWebhookHelpers.ts (1)
  • triggerUserWebhook (15-28)
admin-ui/plugins/user-management/helper/userAuditHelpers.ts (2)
  • getErrorMessage (253-270)
  • logPasswordChange (205-236)
admin-ui/plugins/user-management/helper/validations.ts (1)
  • passwordChangeValidationSchema (68-82)
admin-ui/plugins/user-management/components/UserAddPage.tsx (6)
admin-ui/app/helpers/navigation.ts (1)
  • useAppNavigation (66-95)
admin-ui/plugins/user-management/types/UserApiTypes.ts (2)
  • PersonAttribute (6-6)
  • CustomUser (5-5)
admin-ui/plugins/user-management/utils/userFormUtils.ts (1)
  • mapToPersonAttributes (144-149)
admin-ui/plugins/user-management/helper/userWebhookHelpers.ts (1)
  • triggerUserWebhook (15-28)
admin-ui/plugins/user-management/types/ComponentTypes.ts (1)
  • FormValueEntry (117-122)
admin-ui/plugins/user-management/common/Constants.ts (1)
  • BIRTHDATE_ATTR (6-6)
admin-ui/app/routes/Apps/Gluu/GluuTabs.tsx (1)
admin-ui/app/customColors.ts (1)
  • customColors (4-25)
🪛 Biome (2.1.2)
admin-ui/plugins/user-management/helper/validations.ts

[error] 46-46: Do not add then to an object.

(lint/suspicious/noThenProperty)

🔇 Additional comments (23)
admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js (1)

25-25: LGTM! Browser-history-aware navigation correctly implemented.

The navigation changes properly address the previous review feedback. The navigateBack implementation will use browser history when available (navigate(-1)) and only fall back to the dashboard when history is unavailable, which is appropriate behavior for a general configuration page.

Also applies to: 29-29, 138-140

admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx (1)

332-337: Back button enablement via showBack looks correct

Exposing the Back button through showBack={true} cleanly aligns this page with the shared footer behavior and does not affect submit, loading, or permission handling. Please just double‑check that the GluuFormFooter’s configured back navigation/fallback for this page matches the current UX requirement (dashboard vs any Cedarling-specific listing context), since this component itself doesn’t specify a custom route.

admin-ui/plugins/services/Components/Configuration/LdapListPage.js (3)

4-4: LGTM! Navigation refactor aligns with PR objectives.

The migration to centralized useAppNavigation and ROUTES constants standardizes navigation across the admin UI, consistent with the PR's goal of uniformity.

Also applies to: 46-46


101-108: LGTM! Guard added and past dependency issue resolved.

The configId guard on line 103 prevents navigation errors, and the dependency array now correctly references navigateToRoute instead of the previously undefined navigate.


115-117: LGTM!

The navigation logic and dependency array are correct.

admin-ui/app/routes/Apps/Profile/ProfilePage.tsx (1)

17-17: LGTM! Centralized navigation pattern adopted correctly.

The refactoring to use useAppNavigation() and ROUTES.USER_EDIT() aligns with the PR's goal of standardizing navigation across the admin UI. The dependency optimization from the previous review has been successfully implemented—removing the redundant profileDetails?.inum from the dependency array while keeping profileDetails to ensure the latest profile data is passed in the navigation state.

Also applies to: 27-27, 70-75

admin-ui/app/routes/Apps/Gluu/GluuTabs.tsx (5)

16-35: Good use of React.memo for TabPanel.

The memoization is appropriate here since TabPanel is a pure presentational component. Setting displayName is a good practice for React DevTools debugging.


44-58: Type system and initialization logic look correct.

The previous review concern about index misalignment has been addressed. initTabValue now correctly operates on the full tabNames array using the isNavigationTab guard, ensuring indices align with the actual tabs array.


70-76: Lazy initialization and memoized getter are well implemented.

The lazy initializer in useState avoids unnecessary computation on re-renders. The getTabLabel callback correctly has an empty dependency array since isNavigationTab is a stable module-level function.


78-90: handleChange correctly handles mixed tab types.

The implementation properly uses tabNames[newValue] directly and checks isNavigationTab before navigating. This ensures indices remain aligned regardless of whether tabs are plain strings or navigation tabs.


92-112: Memoized styling is correctly implemented.

The empty dependency array is appropriate since customColors is a stable module-level import. The styling will be computed once and reused across renders.

admin-ui/plugins/user-management/helper/userWebhookHelpers.ts (1)

1-28: LGTM! Type improvements enhance type safety.

The changes properly introduce the CustomUser type for stronger typing of webhook payloads. The intersection cast on lines 21-22 correctly satisfies both the specific CustomUser type and the broader record union in the payload interface.

admin-ui/plugins/user-management/helper/userAuditHelpers.ts (3)

61-63: LGTM! Compact JSON format is cleaner.

The inline JSON string is valid and more readable than escaped multi-line format.


73-75: LGTM! Type assertion ensures correct array typing.

The as typeof payload.customAttributes assertion correctly preserves the array type after the map operation.


238-251: LGTM! Exporting ErrorResponse enables reuse.

Making this interface public allows other modules to properly type error handling.

admin-ui/plugins/user-management/types/ComponentTypes.ts (1)

116-122: LGTM! Flexible union type for form values.

FormValueEntry properly models the various shapes form values can take (strings, arrays, null/undefined, and select-like objects with value/label properties). This enables type-safe handling of diverse form inputs.

admin-ui/plugins/user-management/components/UserEditPage.tsx (3)

35-39: LGTM! Dependency array correctly updated.

The useEffect now properly depends on userDetails (not just userDetails?.inum), ensuring the redirect triggers whenever userDetails changes.


117-129: LGTM! Proper FormValueEntry handling for multi-valued attributes.

The code correctly handles the various shapes of FormValueEntry:

  • Strings are trimmed directly
  • Objects (like select options) extract value or attribute-named property
  • Empty values are filtered out

45-48: LGTM! Proper memoization of person attributes.

Using useMemo to derive personAttributes from attributesData?.entries prevents unnecessary recomputation and aligns with the centralized mapToPersonAttributes utility.

admin-ui/plugins/user-management/components/PasswordChangeModal.tsx (1)

149-159: LGTM! Proper form reset handling on modal close.

Using a ref for resetForm avoids stale closure issues, and the effect correctly resets form state when the modal closes.

admin-ui/plugins/user-management/utils/userFormUtils.ts (1)

136-142: The type-unsafe cast creates a contract violation—objects validated only for name are cast as complete PersonAttribute objects.

The isPersonAttribute predicate only validates that name is a non-empty string, but mapToPersonAttributes at line 148 casts the filtered results as PersonAttribute[] without verifying other required fields (displayName, description, etc.). The double cast (entries as unknown[]).filter(isPersonAttribute) as PersonAttribute[] bypasses TypeScript's type checker.

While downstream code uses optional chaining (e.g., data.displayName?.toLowerCase()) and React safely renders undefined values, this masks a fundamental type safety violation: incomplete objects are being represented as complete PersonAttribute instances.

Recommendation: Either restore validation of all required fields in isPersonAttribute, or adjust the return type to Partial<PersonAttribute>[] to accurately reflect what the predicate guarantees. The current implementation violates the type contract and is fragile against future changes that remove the defensive ?. operators downstream.

admin-ui/plugins/user-management/components/UserAddPage.tsx (1)

28-28: User creation flow, webhook triggering, and redirect look correct

Using useAppNavigation with navigateToRoute(ROUTES.USER_MANAGEMENT) after a successful create, plus triggerUserWebhook(data) on success, keeps users in the user‑management context and emits the webhook with the persisted server payload. This aligns with the newer navigation requirement and webhook helper typing.

Based on learnings, this matches the “fallback to the listing page instead of dashboard” rule for user management.

Also applies to: 41-47

admin-ui/plugins/user-management/components/UserForm.tsx (1)

81-92: Back button behavior matches the new centralized navigation requirement

Using useAppNavigation and wiring handleNavigateBack as navigateBack(ROUTES.USER_MANAGEMENT) ensures:

  • History‑back when available.
  • Fallback to the user‑management listing when there’s no history.

Plumbing this through GluuFormFooter (showBack, onBack) matches the newer “return to listing screen, not dashboard” rule for this module and keeps behavior consistent across create/edit flows.

Based on learnings, this is the desired pattern for user‑management forms.

Also applies to: 151-154, 423-434

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. The cancel button not working for added custom fields
    https://www.loom.com/share/708f40c93f20463bb727fe247600f4cf

  2. All the added custom fields are multiple item fields

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

Caution

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

⚠️ Outside diff range comments (1)
admin-ui/app/routes/Apps/Gluu/GluuRemovableInputRow.tsx (1)

107-122: PropTypes are redundant with TypeScript interface.

Since the component now has a strongly-typed GluuRemovableInputRowProps interface, the PropTypes block is redundant and can be removed to reduce maintenance burden.

-GluuRemovableInputRow.propTypes = {
-  label: PropTypes.string,
-  name: PropTypes.string,
-  type: PropTypes.string,
-  value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
-  formik: PropTypes.object,
-  required: PropTypes.bool,
-  lsize: PropTypes.number,
-  rsize: PropTypes.number,
-  handler: PropTypes.func,
-  doc_category: PropTypes.string,
-  isDirect: PropTypes.bool,
-  isBoolean: PropTypes.bool,
-  modifiedFields: PropTypes.object,
-  setModifiedFields: PropTypes.func,
-}

Also remove the unused import:

-import PropTypes from 'prop-types'
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 570889f and a68fb38.

📒 Files selected for processing (5)
  • admin-ui/app/routes/Apps/Gluu/GluuRemovableInputRow.tsx (6 hunks)
  • admin-ui/app/routes/Apps/Gluu/GluuRemovableSelectRow.tsx (4 hunks)
  • admin-ui/app/routes/Apps/Gluu/GluuRemovableTypeAhead.tsx (3 hunks)
  • admin-ui/plugins/user-management/components/AvailableClaimsPanel.tsx (4 hunks)
  • admin-ui/plugins/user-management/components/UserForm.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.
📚 Learning: 2025-11-06T08:23:20.948Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.

Applied to files:

  • admin-ui/plugins/user-management/components/UserForm.tsx
📚 Learning: 2025-11-05T19:57:35.143Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2415
File: admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx:148-153
Timestamp: 2025-11-05T19:57:35.143Z
Learning: In the SSA Add page (admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx), the Back button should fall back to '/auth-server/config/ssa' when browser history is unavailable, not '/home/dashboard', as this keeps users in the SSA management context.

Applied to files:

  • admin-ui/plugins/user-management/components/UserForm.tsx
📚 Learning: 2025-11-03T08:47:33.943Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.

Applied to files:

  • admin-ui/plugins/user-management/components/UserForm.tsx
🧬 Code graph analysis (4)
admin-ui/plugins/user-management/components/AvailableClaimsPanel.tsx (3)
admin-ui/plugins/user-management/types/UserFormTypes.ts (1)
  • AvailableClaimsPanelProps (33-40)
admin-ui/plugins/user-management/types/UserApiTypes.ts (1)
  • PersonAttribute (6-6)
admin-ui/plugins/auth-server/components/Configuration/ConfigPage.js (1)
  • dispatch (35-35)
admin-ui/app/routes/Apps/Gluu/GluuRemovableTypeAhead.tsx (1)
admin-ui/plugins/admin/__tests__/components/CustomScripts/CustomScriptDetailPage.test.js (1)
  • name (18-18)
admin-ui/app/routes/Apps/Gluu/GluuRemovableInputRow.tsx (1)
admin-ui/app/layout/components/types.ts (1)
  • InputProps (221-226)
admin-ui/app/routes/Apps/Gluu/GluuRemovableSelectRow.tsx (1)
admin-ui/plugins/admin/__tests__/components/CustomScripts/CustomScriptDetailPage.test.js (1)
  • name (18-18)
🪛 Biome (2.1.2)
admin-ui/app/routes/Apps/Gluu/GluuRemovableTypeAhead.tsx

[error] 98-101: Static Elements should not be interactive.

To add interactivity such as a mouse or key event listener to a static element, give the element an appropriate role value.

(lint/a11y/noStaticElementInteractions)


[error] 98-101: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

admin-ui/app/routes/Apps/Gluu/GluuRemovableSelectRow.tsx

[error] 79-82: Static Elements should not be interactive.

To add interactivity such as a mouse or key event listener to a static element, give the element an appropriate role value.

(lint/a11y/noStaticElementInteractions)


[error] 79-82: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

🔇 Additional comments (9)
admin-ui/plugins/user-management/components/AvailableClaimsPanel.tsx (1)

118-118: Good addition of explicit return null.

Explicitly returning null for filtered-out items improves code clarity and prevents React warnings about missing return values in map callbacks.

admin-ui/plugins/user-management/components/UserForm.tsx (4)

226-257: Effect may miss element if ref is null on first render.

The effect runs once ([] deps) and reads formContentRef.current. If the ref element is conditionally rendered or not yet mounted when the effect runs, element will be null and the observer won't attach. Subsequent renders won't re-run the effect.

Since the <div ref={formContentRef}> is always rendered within the form, this should work in practice. If you encounter height tracking issues, consider adding a callback ref or running the effect when the ref changes.


147-149: Navigation fallback correctly targets user management listing.

The navigateBack(ROUTES.USER_MANAGEMENT) implementation aligns with the updated requirement to keep users in context rather than redirecting to the dashboard. Based on learnings.


465-476: Form footer correctly implements the specified button behaviors.

The implementation properly enforces:

  • Cancel disabled until a change is made (!formik.dirty)
  • Apply disabled when form is clean or invalid (!formik.dirty || !formik.isValid)
  • Back always enabled with proper navigation

This aligns well with the PR objectives.


88-91: Loading state now properly wired from Redux.

The previous concern about hardcoded loading = false has been addressed. The loading state is now correctly sourced from attributesReducerRoot.loading and passed to both <GluuLoader blocking={loading}> and <GluuFormFooter isLoading={loading}>.

Also applies to: 260-260

admin-ui/app/routes/Apps/Gluu/GluuRemovableSelectRow.tsx (1)

71-72: Options rendering is clear and correctly keyed.

Using item.cca2 as both the value and key is appropriate here and should produce stable option identities.

admin-ui/app/routes/Apps/Gluu/GluuRemovableTypeAhead.tsx (3)

7-12: LGTM! Type definitions improve type safety.

The introduction of internal type aliases and explicit FormikProps import strengthens type checking and eliminates the previous reliance on any types.


14-30: LGTM! Props interface properly typed.

The refined prop types replace loose any annotations with specific types, improving type safety and IDE support.


49-50: LGTM! Proper controlled component pattern.

The selectedValue derivation with fallback chain correctly implements controlled component behavior, preventing undefined values while maintaining type safety.

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a68fb38 and 2b13186.

📒 Files selected for processing (2)
  • admin-ui/app/routes/Apps/Gluu/GluuRemovableTypeAhead.tsx (3 hunks)
  • admin-ui/plugins/user-management/components/UserForm.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.
📚 Learning: 2025-11-06T08:23:20.948Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.

Applied to files:

  • admin-ui/plugins/user-management/components/UserForm.tsx
📚 Learning: 2025-11-05T19:57:35.143Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2415
File: admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx:148-153
Timestamp: 2025-11-05T19:57:35.143Z
Learning: In the SSA Add page (admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx), the Back button should fall back to '/auth-server/config/ssa' when browser history is unavailable, not '/home/dashboard', as this keeps users in the SSA management context.

Applied to files:

  • admin-ui/plugins/user-management/components/UserForm.tsx
📚 Learning: 2025-11-03T08:47:33.943Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.

Applied to files:

  • admin-ui/plugins/user-management/components/UserForm.tsx
🧬 Code graph analysis (1)
admin-ui/app/routes/Apps/Gluu/GluuRemovableTypeAhead.tsx (1)
admin-ui/plugins/admin/__tests__/components/CustomScripts/CustomScriptDetailPage.test.js (1)
  • name (18-18)
🪛 Biome (2.1.2)
admin-ui/app/routes/Apps/Gluu/GluuRemovableTypeAhead.tsx

[error] 119-122: Static Elements should not be interactive.

To add interactivity such as a mouse or key event listener to a static element, give the element an appropriate role value.

(lint/a11y/noStaticElementInteractions)


[error] 119-122: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

🔇 Additional comments (8)
admin-ui/app/routes/Apps/Gluu/GluuRemovableTypeAhead.tsx (3)

7-39: LGTM: Excellent type safety improvements.

The migration from any types to strict TypeScript types (FormikProps, specific option types, properly typed state setters) significantly improves type safety and maintainability.


83-109: LGTM: Well-implemented controlled component pattern.

The selectedValue initialization correctly prioritizes Formik state over the value prop. The onChange handler properly maintains both Formik state (full objects) and modifiedFields (extracted strings) for change tracking.


41-64: Helper function correctly extracts mapping logic with intentional field precedence.

The extractValueFromOption function successfully addresses the previous review suggestion to extract mapping logic. The implementation is sound and the field precedence (role → label → fieldName) is intentional:

  • When handling role objects, role is prioritized for semantic correctness
  • When handling other data, the function falls back to the field matching the component's name parameter
  • In actual usage (UserClaimEntry.tsx), role objects and user data are passed in separate scenarios, so the precedence works correctly

The precedence logic is deliberate but relies on consistent usage patterns. If the component's usage evolves to mix different object types, this precedence could produce unexpected results. Document the precedence assumption or add logic to handle mixed option types if component usage expands in the future.

admin-ui/plugins/user-management/components/UserForm.tsx (5)

88-91: Loading state now properly wired from Redux.

The component correctly consumes loading from attributesReducerRoot, enabling the GluuLoader and GluuFormFooter to reflect actual loading state. This addresses the previous concern about hardcoded loading = false.


152-154: Navigation fallback correctly targets user management context.

The handleNavigateBack implementation using navigateBack(ROUTES.USER_MANAGEMENT) correctly keeps users within the user management workflow when browser history is unavailable, aligning with the updated requirement. Based on learnings.


186-202: Initialization guard prevents infinite loops.

The use of initializedRef with a compound key (${userKey}-${attrsKey}) is a good pattern to prevent the effect from re-running unnecessarily when dependencies change but the logical state hasn't.


231-262: Well-structured ResizeObserver with graceful fallback.

The effect correctly implements feature detection for ResizeObserver, falls back to window.resize listener when unavailable, and properly cleans up both in the return function. The empty dependency array is appropriate since the ref is accessed synchronously after render.


470-481: Button states correctly implement PR requirements.

The GluuFormFooter configuration properly implements the standardized button behavior:

  • Back: Always enabled via showBack={true} with no disable prop
  • Cancel: Disabled until form changes (disableCancel={!formik.dirty})
  • Apply: Enabled only when form is dirty AND valid (disableApply={!formik.dirty || !formik.isValid})

This aligns with the PR objectives for preventing accidental state loss and providing consistent UX.

Comment on lines +119 to 124
<div
style={applicationstyle.removableInputRow as React.CSSProperties}
onClick={() => handler()}
>
<i className={'fa fa-fw fa-close'} style={{ color: customColors.accentRed }}></i>
</div>
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

Critical accessibility issue: replace div with semantic button.

This accessibility violation was flagged in the previous review but remains unresolved. The clickable div prevents keyboard-only users from removing items and is not announced by screen readers as an interactive element.

Apply this diff to fix the accessibility issue:

-        <div
+        <button
+          type="button"
           style={applicationstyle.removableInputRow as React.CSSProperties}
           onClick={() => handler()}
+          aria-label={`Remove ${label}`}
         >
           <i className={'fa fa-fw fa-close'} style={{ color: customColors.accentRed }}></i>
-        </div>
+        </button>

Ensure applicationstyle.removableInputRow includes button reset styles (remove default border/background/padding) to maintain the current visual appearance.

📝 Committable suggestion

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

Suggested change
<div
style={applicationstyle.removableInputRow as React.CSSProperties}
onClick={() => handler()}
>
<i className={'fa fa-fw fa-close'} style={{ color: customColors.accentRed }}></i>
</div>
<button
type="button"
style={applicationstyle.removableInputRow as React.CSSProperties}
onClick={() => handler()}
aria-label={`Remove ${label}`}
>
<i className={'fa fa-fw fa-close'} style={{ color: customColors.accentRed }}></i>
</button>
🧰 Tools
🪛 Biome (2.1.2)

[error] 119-122: Static Elements should not be interactive.

To add interactivity such as a mouse or key event listener to a static element, give the element an appropriate role value.

(lint/a11y/noStaticElementInteractions)


[error] 119-122: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

🤖 Prompt for AI Agents
In admin-ui/app/routes/Apps/Gluu/GluuRemovableTypeAhead.tsx around lines 119 to
124, replace the clickable <div> with a semantic <button type="button">, keep
the existing onClick handler, and add an accessible label (aria-label or title)
for screen readers; ensure the button uses applicationstyle.removableInputRow
cast to React.CSSProperties and that applicationstyle.removableInputRow includes
button reset styles (no border, background, padding, outline handled) so the
visual appearance remains unchanged while making it keyboard-focusable and
announced as interactive.

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b13186 and 6c2a9ef.

📒 Files selected for processing (5)
  • admin-ui/plugins/user-management/components/UserAddPage.tsx (5 hunks)
  • admin-ui/plugins/user-management/components/UserEditPage.tsx (6 hunks)
  • admin-ui/plugins/user-management/components/UserForm.tsx (2 hunks)
  • admin-ui/plugins/user-management/helper/userAuditHelpers.ts (3 hunks)
  • admin-ui/plugins/user-management/types/ComponentTypes.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.
📚 Learning: 2025-11-06T08:23:20.948Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.

Applied to files:

  • admin-ui/plugins/user-management/components/UserEditPage.tsx
  • admin-ui/plugins/user-management/components/UserAddPage.tsx
  • admin-ui/plugins/user-management/components/UserForm.tsx
📚 Learning: 2025-11-05T19:57:35.143Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2415
File: admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx:148-153
Timestamp: 2025-11-05T19:57:35.143Z
Learning: In the SSA Add page (admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx), the Back button should fall back to '/auth-server/config/ssa' when browser history is unavailable, not '/home/dashboard', as this keeps users in the SSA management context.

Applied to files:

  • admin-ui/plugins/user-management/components/UserAddPage.tsx
  • admin-ui/plugins/user-management/components/UserForm.tsx
📚 Learning: 2025-11-03T08:47:33.943Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.

Applied to files:

  • admin-ui/plugins/user-management/components/UserForm.tsx
🧬 Code graph analysis (1)
admin-ui/plugins/user-management/components/UserEditPage.tsx (5)
admin-ui/app/helpers/navigation.ts (1)
  • useAppNavigation (66-95)
admin-ui/plugins/user-management/utils/userFormUtils.ts (1)
  • mapToPersonAttributes (144-149)
admin-ui/plugins/user-management/helper/userWebhookHelpers.ts (1)
  • triggerUserWebhook (15-28)
admin-ui/plugins/user-management/helper/userAuditHelpers.ts (1)
  • getErrorMessage (265-291)
admin-ui/plugins/user-management/types/ComponentTypes.ts (1)
  • FormValueEntry (118-123)
🔇 Additional comments (21)
admin-ui/plugins/user-management/helper/userAuditHelpers.ts (3)

74-74: LGTM!

The type assertion correctly preserves the original type after mapping, addressing TypeScript's type widening behavior.


238-263: LGTM!

The exported ErrorResponse interface with additional fields and the pickFirstString utility improve error handling flexibility. The utility correctly handles edge cases including undefined, empty, and whitespace-only strings.


265-290: LGTM!

The refactored getErrorMessage with status-based prioritization is a good improvement. Prioritizing description for 4xx client errors surfaces actionable messages to users, while the comprehensive fallback chain handles various API response structures gracefully.

admin-ui/plugins/user-management/types/ComponentTypes.ts (2)

22-22: LGTM!

The isSubmitting prop addition is correctly typed as optional and aligns with the form submission state management in UserForm, UserAddPage, and UserEditPage.


117-123: LGTM!

The FormValueEntry type union comprehensively covers the various form value shapes (primitives, arrays, nullish values, and select-style objects with value/label). This provides proper type safety for the multi-valued attribute handling in the user forms.

admin-ui/plugins/user-management/components/UserEditPage.tsx (4)

1-3: LGTM!

The import changes properly bring in useMemo for memoization and the centralized navigation utilities (useAppNavigation, ROUTES).


35-39: LGTM!

The dependency array now correctly includes userDetails instead of just userDetails?.inum, ensuring the effect re-runs whenever the entire object reference changes. This addresses the previous review feedback.


45-48: LGTM!

Using mapToPersonAttributes with useMemo for attribute transformation is cleaner than the previous inline casting and ensures the derived data is properly memoized.


187-192: LGTM!

The loader correctly blocks on both loadingAttributes and isSubmitting, preventing user interaction during data fetching or form submission. Passing isSubmitting to UserForm enables proper button state management.

admin-ui/plugins/user-management/components/UserAddPage.tsx (4)

35-38: LGTM!

The use of mapToPersonAttributes with useMemo properly addresses the previous type casting concerns. This provides cleaner type transformation compared to the earlier as unknown as PersonAttribute[] approach.


64-78: LGTM!

The toStringValue function correctly handles all FormValueEntry variants including the object-like { value, label } pattern. The logic properly extracts string values from various input shapes.


80-102: LGTM!

The normalizeValues function now properly accepts FormValueEntry | FormValueEntry[] | null | undefined, addressing the previous review feedback about type alignment. The null/undefined guards at lines 89-91 and 95 ensure robust handling.


142-144: LGTM!

The loader correctly combines loadingAttributes and isSubmitting states, and UserForm receives the isSubmitting prop for proper button state management.

admin-ui/plugins/user-management/components/UserForm.tsx (8)

75-77: LGTM!

The component signature correctly incorporates isSubmitting with a default value of false, and the navigation hook integration is properly structured.


88-91: Loading state is now properly wired to Redux.

The loading state is correctly derived from state.attributesReducerRoot.loading, addressing the previous concern about the hardcoded false value. This ensures the loader reflects the actual attributes fetching state.


155-157: Back button fallback correctly targets user management.

The navigateBack(ROUTES.USER_MANAGEMENT) fallback keeps users in the user management context when browser history is unavailable, which aligns with the updated requirement. Based on learnings.


159-171: LGTM!

The handleCancel implementation properly resets form values, clears modified fields tracking, and re-initializes the claims state. This ensures the form returns to its original state without navigation, matching the PR objectives.


177-186: LGTM!

The submitForm function correctly guards against double submission with isSubmitting check, closes the modal, and delegates to onSubmitData with the current form values and modified fields.


270-273: LGTM!

The blockingLoader correctly combines Redux loading state with the isSubmitting prop, ensuring the UI is blocked during both attribute fetching and form submission.


478-490: LGTM!

The GluuFormFooter integration correctly implements the PR objectives:

  • Back: always enabled unless submitting
  • Cancel: disabled when submitting or form is clean
  • Apply: disabled when submitting, form is clean, or form is invalid

This aligns with the documented Cancel/Back/Apply button behavior.


504-504: LGTM!

Wrapping with React.memo is appropriate for this component to prevent unnecessary re-renders when parent components update but props remain unchanged.

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

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/user-management/components/UserEditPage.tsx (2)

80-142: Align single‑valued attributes to handle object‑shaped FormValueEntry values consistently with multi‑valued logic

The code inconsistency is confirmed. FormValueEntry type explicitly allows { value?: string; label?: string; [key: string]: string | undefined } (verified in admin-ui/plugins/user-management/types/ComponentTypes.ts), yet the single‑valued branch in createCustomAttributes (lines 80–142) ignores object entries while the multi‑valued branch handles them.

Current UI components (GluuSelectRow, GluuRemovableSelectRow) only emit string values, so this is not a present functional bug. However, the type definition permits objects, making this a defensible hardening: extend the single‑valued path to extract value or [attributeName] from objects (lines 95–99), matching the multi‑valued logic (lines 117–124), so both branches handle the same input shapes.


148-181: Remove post-save navigation to align with "save in place" UX objective

The onSuccess handler redirects to ROUTES.USER_MANAGEMENT after mutation completes, which contradicts the PR objective of saving changes without leaving the page. Apply should update the user in place and remain on the edit screen; use the separate Back button for navigation to listing.

Additionally, verify that the extra fields in submittableValues (modifiedFields, performedOn, action_message, and conditional customObjectClasses) match your backend API contract—these are cast as CustomUser without explicit type safety, which could mask payload mismatches.

♻️ Duplicate comments (1)
admin-ui/plugins/user-management/components/UserForm.tsx (1)

34-73: Duplicate setupCustomAttributes logic; consider reusing shared helper

This file defines a local setupCustomAttributes that hydrates selectedClaims from userDetails.customAttributes. Per the provided snippets, a very similar setupCustomAttributes already exists in ../utils/userFormUtils with overlapping responsibilities.

Maintaining two versions of this logic risks subtle divergence (e.g., usedClaims set, how options are attached, merge vs replace semantics). Since this function is already pure and used from multiple places (useEffect initialization and Cancel handler), consider:

  • removing the local implementation, and
  • importing and using the shared helper from ../utils/userFormUtils (or consolidating into a single exported helper).

This keeps the attribute‑to‑claims mapping consistent across Add/Edit flows and simplifies future changes.

Also applies to: 159-171, 192-209

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c2a9ef and c86976c.

📒 Files selected for processing (2)
  • admin-ui/plugins/user-management/components/UserEditPage.tsx (6 hunks)
  • admin-ui/plugins/user-management/components/UserForm.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.
📚 Learning: 2025-11-06T08:23:20.948Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.

Applied to files:

  • admin-ui/plugins/user-management/components/UserEditPage.tsx
  • admin-ui/plugins/user-management/components/UserForm.tsx
📚 Learning: 2025-11-07T12:55:26.241Z
Learnt from: kdhttps
Repo: GluuFederation/flex PR: 2378
File: admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx:93-104
Timestamp: 2025-11-07T12:55:26.241Z
Learning: In the Cedarling configuration feature (admin-ui/plugins/admin/components/Cedarling/CedarlingConfigPage.tsx), the sync role to scopes mappings operation depends on the `auiPolicyStoreUrl`. The backend fetches content from this URL and syncs roles based on the response. Therefore, the audit log for the sync operation should include the `auiPolicyStoreUrl` in its payload to provide proper audit context.

Applied to files:

  • admin-ui/plugins/user-management/components/UserEditPage.tsx
📚 Learning: 2025-11-05T19:57:35.143Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2415
File: admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx:148-153
Timestamp: 2025-11-05T19:57:35.143Z
Learning: In the SSA Add page (admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx), the Back button should fall back to '/auth-server/config/ssa' when browser history is unavailable, not '/home/dashboard', as this keeps users in the SSA management context.

Applied to files:

  • admin-ui/plugins/user-management/components/UserForm.tsx
📚 Learning: 2025-11-03T08:47:33.943Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.

Applied to files:

  • admin-ui/plugins/user-management/components/UserForm.tsx
🧬 Code graph analysis (2)
admin-ui/plugins/user-management/components/UserEditPage.tsx (5)
admin-ui/app/helpers/navigation.ts (1)
  • useAppNavigation (66-95)
admin-ui/plugins/user-management/types/UserApiTypes.ts (2)
  • CustomUser (5-5)
  • PersonAttribute (6-6)
admin-ui/plugins/user-management/utils/userFormUtils.ts (1)
  • mapToPersonAttributes (144-149)
admin-ui/plugins/user-management/helper/userWebhookHelpers.ts (1)
  • triggerUserWebhook (15-28)
admin-ui/plugins/user-management/types/ComponentTypes.ts (1)
  • FormValueEntry (118-123)
admin-ui/plugins/user-management/components/UserForm.tsx (6)
admin-ui/plugins/user-management/utils/userFormUtils.ts (2)
  • setupCustomAttributes (102-134)
  • initializeCustomAttributes (66-100)
admin-ui/plugins/user-management/types/UserApiTypes.ts (2)
  • CustomUser (5-5)
  • PersonAttribute (6-6)
admin-ui/plugins/user-management/types/ComponentTypes.ts (2)
  • UserFormProps (15-23)
  • FormOperation (43-47)
admin-ui/app/helpers/navigation.ts (2)
  • useAppNavigation (66-95)
  • ROUTES (97-97)
admin-ui/plugins/user-management/types/CommonTypes.ts (1)
  • ThemeContext (13-17)
admin-ui/plugins/user-management/helper/validations.ts (2)
  • initializeCustomAttributes (176-208)
  • getUserValidationSchema (8-66)
🔇 Additional comments (3)
admin-ui/plugins/user-management/components/UserEditPage.tsx (1)

187-193: Loader integration correctly blocks form during attribute load and submit

Wrapping UserForm in <GluuLoader blocking={loadingAttributes || isSubmitting}> ensures the edit form doesn’t render or remain interactive while attributes are loading or while an update is in progress. This addresses prior concerns about partially initialized forms and aligns well with the inner blockingLoader in UserForm.

admin-ui/plugins/user-management/components/UserForm.tsx (2)

270-276: Inner loader now correctly reflects attribute loading and submit state

const blockingLoader = loading || isSubmitting wired into <GluuLoader blocking={blockingLoader}> ensures the form is blocked both while attributes are loading from the reducer and while a submit is in progress. This resolves the earlier hard‑coded const loading = false behavior and makes the inner loader behavior consistent with parent‑level loaders.


223-235: No action required — Gluu rows update Formik before invoking handleChange.

GluuInputRow and GluuSelectRow call formik.handleChange(event) before calling the optional handleChange; UserClaimEntry delegates to GluuRemovableInputRow/GluuRemovableSelectRow/GluuRemovableTypeAhead which use formik.setFieldValue/formik.handleChange internally. The UserForm.handleChange that only records modifiedFields is safe as-is.

@sonarqubecloud
Copy link

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

♻️ Duplicate comments (2)
admin-ui/plugins/user-management/components/UserForm.tsx (2)

34-73: Implementation is correct.

The helper properly hydrates custom claims while excluding standard fields via the usedClaims Set. Placing this pure function outside the component prevents unnecessary recreations.

A previous review suggested extracting this to ../helper/validations.ts for consistency with other validation helpers.


398-435: Password fields correctly conditional on new user creation.

The password and confirm password fields are appropriately rendered only when !userDetails (new user flow), while existing users access password changes via the modal. This separation is clean.

A previous review noted the showError condition includes !!formik.values.userPassword for earlier feedback display.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c86976c and a1f18c7.

📒 Files selected for processing (1)
  • admin-ui/plugins/user-management/components/UserForm.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.
📚 Learning: 2025-11-06T08:23:20.948Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2418
File: admin-ui/plugins/user-management/components/UserForm.tsx:290-297
Timestamp: 2025-11-06T08:23:20.948Z
Learning: In the UserForm component (admin-ui/plugins/user-management/components/UserForm.tsx), the Back button should fall back to '/user/usersmanagement' when browser history is unavailable, not '/home/dashboard', as this keeps users in the user management context. This aligns with the new requirement that users should be redirected to the respective listing screen of the component rather than the dashboard.

Applied to files:

  • admin-ui/plugins/user-management/components/UserForm.tsx
📚 Learning: 2025-11-05T19:57:35.143Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2415
File: admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx:148-153
Timestamp: 2025-11-05T19:57:35.143Z
Learning: In the SSA Add page (admin-ui/plugins/auth-server/components/Ssa/SsaAddPage.tsx), the Back button should fall back to '/auth-server/config/ssa' when browser history is unavailable, not '/home/dashboard', as this keeps users in the SSA management context.

Applied to files:

  • admin-ui/plugins/user-management/components/UserForm.tsx
📚 Learning: 2025-11-03T08:47:33.943Z
Learnt from: faisalsiddique4400
Repo: GluuFederation/flex PR: 2404
File: admin-ui/app/routes/Apps/Gluu/Gluuformfooter.tsx:70-77
Timestamp: 2025-11-03T08:47:33.943Z
Learning: In the admin-ui forms (Gluuformfooter component), the Back button should always navigate to '/home/dashboard' rather than using history-based navigation (navigate(-1)), as clarified by faisalsiddique4400 in PR #2404.

Applied to files:

  • admin-ui/plugins/user-management/components/UserForm.tsx
🔇 Additional comments (9)
admin-ui/plugins/user-management/components/UserForm.tsx (9)

1-33: Imports are well-organized and appropriate for the refactored component.

The separation of React hooks, third-party libraries, UI components, context/Redux, API/services, and types follows good organization practices. The navigation abstraction via useAppNavigation and ROUTES improves maintainability.


134-158: Guards properly address the Enter-key bypass vulnerability.

The handleApply callback now correctly guards against invalid, pristine, or empty submissions with comprehensive checks for isSubmitting, formik.dirty, formik.isValid, and modifiedFields length. This aligns with the GluuFormFooter disable conditions and prevents bypassing via Enter key.


160-162: Navigation fallback correctly targets user management listing.

Based on learnings, the fallback to ROUTES.USER_MANAGEMENT is the intended behavior, keeping users in context rather than redirecting to the dashboard.


197-213: Initialization guard pattern is appropriate.

Using a ref to track the initialization key (${userKey}-${attrsKey}) effectively prevents infinite re-runs when enableReinitialize is true. This is a valid pattern for coordinating external state hydration with Formik's reinitialization.


242-273: ResizeObserver implementation is well-structured.

The effect correctly:

  • Feature-detects ResizeObserver availability
  • Falls back to window resize listener
  • Properly cleans up observers/listeners on unmount
  • Uses functional state update to avoid unnecessary re-renders

275-278: Loading state properly wired to Redux.

The blockingLoader now correctly combines Redux loading state with the isSubmitting prop, addressing the earlier concern about the hardcoded false value. This ensures the loader displays during both attribute fetching and form submission.


483-494: GluuFormFooter correctly implements the PR requirements.

The footer configuration aligns with the stated behavior:

  • Back: Always enabled (no disableBack prop) — navigates appropriately
  • Cancel: Disabled until form is dirty (disableCancel={isSubmitting || !formik.dirty}) — resets without navigating
  • Apply: Disabled until form has valid unsaved changes (disableApply={isSubmitting || !formik.dirty || !formik.isValid}) — saves without leaving page

The applyButtonType="button" prevents the Apply button from acting as a submit button, avoiding double-triggering with the Form.onSubmit handler.


508-508: Good use of React.memo for performance optimization.

Wrapping the component with React.memo helps prevent unnecessary re-renders when parent components update but props haven't changed.


228-240: Review comment is incorrect—GluuInputRow properly calls formik.handleChange in all cases.

The verification shows that GluuInputRow calls formik.handleChange(event) unconditionally in both branches of its onChange handler (lines 54 and 57 in admin-ui/app/routes/Apps/Gluu/GluuInputRow.tsx). The custom handleChange prop is only invoked as a supplementary callback when provided. Therefore, formik.dirty will be correctly updated, and the form state management works as expected. No action is required.

Likely an incorrect or invalid review comment.

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.

4 participants