Skip to content

Conversation

@asra-ameer
Copy link
Contributor

@asra-ameer asra-ameer commented Jan 5, 2026

Purpose

Replaces the text input for allowed attributes with an Autocomplete component that fetches and displays claim URIs and display names. Improves usability by allowing selection from available claims, adds tooltips, and updates state management for selected claims. Also updates form submission logic to handle the new selection method.

WSO2.Identity.Server.Console.-.Multi.Attribute.Login.mp4

Related Issues

wso2/product-is#22655

Related PRs

  • N/A

Checklist

  • e2e cypress tests locally verified. (for internal contributers)
  • Manual test round performed and verified.
  • UX/UI review done on the final implementation.
  • Documentation provided. (Add links if there are any)
  • Relevant backend changes deployed and verified
  • Unit tests provided. (Add links if there are any)
  • Integration tests provided. (Add links if there are any)

Security checks

Developer Checklist (Mandatory)

  • Complete the Developer Checklist in the related product-is issue to track any behavioral change or migration impact.

Summary by CodeRabbit

  • New Features

    • Enhanced multi-attribute login form with an interactive autocomplete for selecting multiple claim URIs.
    • Displays user-friendly claim labels (instead of raw identifiers) and supports chip-style selections with tooltips.
    • Loads available local claims dynamically and shows loading/disabled states during retrieval.
  • UI Improvements

    • Updated styling, helper text, and improved submission handling for selected claims.

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

Replaces the text input for allowed attributes with an Autocomplete component that fetches and displays claim URIs and display names. Improves usability by allowing selection from available claims, adds tooltips, and updates state management for selected claims. Also updates form submission logic to handle the new selection method.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 5, 2026

Walkthrough

Replaces a plain text input for allowed claim attributes with a multi-select Autocomplete that fetches local claims, maps URIs to display names, shows chips with tooltips, and submits joined claim URIs under account.multiattributelogin.handler.allowedattributes.

Changes

Cohort / File(s) Summary
Multi-Attribute Login Form Enhancement
features/admin.server-configurations.v1/forms/multi-attribute-login.tsx
Replaces a text input with a multi-select Autocomplete. Adds local claim fetching (useGetAllLocalClaims usage), builds claimMap and claimURIs, introduces selectedClaims state and handleClaimChange, implements getDisplayName helper, custom chip/tooltip rendering, loading/disabled states, and submits joined claim URIs under account.multiattributelogin.handler.allowedattributes. Minor data-componentid and styling adjustments.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User as User (UI)
    participant Form as MultiAttributeLoginForm
    participant ClaimsAPI as LocalClaimsService
    participant Server as ConfigurationAPI

    Note over Form,ClaimsAPI: On mount / open
    User->>Form: Opens form
    Form->>ClaimsAPI: Fetch local claims (useGetAllLocalClaims)
    ClaimsAPI-->>Form: Return claims list (uris + display names)
    Form->>Form: build claimMap & claimURIs (render options)

    Note over User,Form: User selects claims
    User->>Form: Selects/Deselects claims (Autocomplete)
    Form-->>Form: update selectedClaims (handleClaimChange)

    Note over Form,Server: On submit
    User->>Form: Submit
    Form->>Server: POST updated config (account.multiattributelogin.handler.allowedattributes = joined selectedClaims)
    Server-->>Form: Acknowledge / persist
    Form->>User: Show success / error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped into the fields of claims today,
Picking URIs in a bright autocomplete array.
Chips on my back, tooltips to show the way,
I joined them all — then bounced away! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: refactoring the allowed attributes field to use an autocomplete component for claim selection.
Description check ✅ Passed The description covers the purpose, related issues, and some checklist items, but several mandatory checks are uncompleted (e2e tests, documentation, backend verification, unit/integration tests, security checks).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings

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

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Fix all issues with AI Agents 🤖
In @features/admin.server-configurations.v1/forms/multi-attribute-login.tsx:
- Around line 265-276: The Chip inside renderTags is receiving a duplicate key
because getTagProps({ index }) already injects a key; remove the explicit key={
option } from the Chip component (keep the spread {...getTagProps({ index })}
and the Tooltip's key if needed) so only one key prop is present; locate the
renderTags function and edit the Chip JSX to drop key={ option } while
preserving label={getDisplayName(option)} and size="small".
🧹 Nitpick comments (5)
features/admin.server-configurations.v1/forms/multi-attribute-login.tsx (5)

83-99: Consider extracting styles outside the component.

These style objects are recreated on every render. Moving them outside the component as module-level constants would avoid unnecessary object allocations.

Proposed refactor
+const containerStyle: React.CSSProperties = { marginBottom: "1rem" };
+const labelStyle: React.CSSProperties = {
+    display: "block",
+    fontSize: "0.875rem",
+    fontWeight: 500,
+    marginBottom: "0.5rem"
+};
+const spanStyle: React.CSSProperties = {
+    overflow: "hidden",
+    textOverflow: "ellipsis",
+    whiteSpace: "nowrap"
+};
+const helperTextStyle: React.CSSProperties = {
+    color: "rgba(0, 0, 0, 0.6)",
+    fontSize: "0.75rem",
+    marginTop: "0.25rem"
+};
+
 export const MultiAttributeLoginForm: FunctionComponent<MultiAttributeLoginFormPropsInterface> = (
     props: MultiAttributeLoginFormPropsInterface
 ): ReactElement => {
     // ... component code, remove style definitions from inside

107-116: Potential issues with claims fetching configuration.

  1. claimsParams is recreated on every render. If the hook uses object reference equality, this could cause unnecessary re-fetches. Consider memoizing with useMemo or extracting as a constant.

  2. Hard-coded limit: 1000 may be insufficient for deployments with many claims.

  3. The hook's error state isn't destructured or handled. Consider providing user feedback if claim loading fails.

Proposed improvements
+    const claimsParams: ClaimsGetParams = useMemo(() => ({
+        filter: "",
+        limit: 1000,
+        offset: 0,
+        sort: ""
+    }), []);
+
     const {
         data: claimsData,
-        isLoading: isClaimsLoading
+        isLoading: isClaimsLoading,
+        error: claimsError
     } = useGetAllLocalClaims<Claim[]>(claimsParams, isConnectorEnabled);

Then handle claimsError appropriately in the UI (e.g., show an error message).


152-154: Minor formatting issue and consider memoization.

Missing spaces in the type annotation and after ||. Also, since getDisplayName depends on claimMap, consider wrapping it with useCallback to prevent unnecessary re-creations.

Proposed fix
-    const getDisplayName = (uri:string): string => {
-        return claimMap.get(uri) ||uri;
-    };
+    const getDisplayName = useCallback((uri: string): string => {
+        return claimMap.get(uri) || uri;
+    }, [claimMap]);

214-216: Unused event parameter.

The event parameter is required by the Autocomplete onChange signature but isn't used. Consider prefixing with underscore for clarity.

-    const handleClaimChange = (event: React.SyntheticEvent, newValue: string[]): void => {
+    const handleClaimChange = (_event: React.SyntheticEvent, newValue: string[]): void => {

248-255: Hard-coded placeholder strings should use i18n.

The placeholder texts "Loading claims..." and "Select claim URIs" are hard-coded. For consistency with the rest of the codebase, use the t() translation function.

     <TextField
         { ...params }
-        placeholder={ isClaimsLoading ? "Loading claims..." : "Select claim URIs" }
+        placeholder={ isClaimsLoading 
+            ? t("common:loading") 
+            : t("governanceConnectors:form.placeholder.selectClaimURIs") 
+        }
         size="small"
         data-componentid={ `${componentId}-allowed-attribute-list` }
     />

Note: Adjust the translation keys to match your i18n configuration.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb46a19 and 67043f3.

📒 Files selected for processing (1)
  • features/admin.server-configurations.v1/forms/multi-attribute-login.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
features/admin.server-configurations.v1/forms/multi-attribute-login.tsx (1)
modules/core/src/models/claim.ts (2)
  • ClaimsGetParams (123-132)
  • Claim (22-48)
🔇 Additional comments (2)
features/admin.server-configurations.v1/forms/multi-attribute-login.tsx (2)

160-190: LGTM!

The initial values parsing logic correctly extracts and processes the comma-separated allowed attributes into the selectedClaims state.


198-207: LGTM!

The submission logic correctly joins selected claims into a comma-separated string for the expected property key.

Comment on lines +265 to +276
renderTags={ (value: string[], getTagProps: (args: { index: number }) => any) =>
value.map((option: string, index: number) => (
<Tooltip title={ option } key={ option } placement="top">
<Chip
{ ...getTagProps({ index }) }
label={ getDisplayName(option) }
size="small"
key={ option }
/>
</Tooltip>
))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Duplicate key prop on Chip component.

getTagProps({ index }) already provides a key prop. Adding an explicit key={ option } on the Chip causes duplicate key assignment. Remove the explicit key from Chip to avoid potential React warnings.

Proposed fix
     renderTags={ (value: string[], getTagProps: (args: { index: number }) => any) =>
         value.map((option: string, index: number) => (
             <Tooltip title={ option } key={ option } placement="top">
                 <Chip
                     { ...getTagProps({ index }) }
                     label={ getDisplayName(option) }
                     size="small"
-                    key={ option }
                 />
             </Tooltip>
         ))
     }
📝 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
renderTags={ (value: string[], getTagProps: (args: { index: number }) => any) =>
value.map((option: string, index: number) => (
<Tooltip title={ option } key={ option } placement="top">
<Chip
{ ...getTagProps({ index }) }
label={ getDisplayName(option) }
size="small"
key={ option }
/>
</Tooltip>
))
}
renderTags={ (value: string[], getTagProps: (args: { index: number }) => any) =>
value.map((option: string, index: number) => (
<Tooltip title={ option } key={ option } placement="top">
<Chip
{ ...getTagProps({ index }) }
label={ getDisplayName(option) }
size="small"
/>
</Tooltip>
))
}
🤖 Prompt for AI Agents
In @features/admin.server-configurations.v1/forms/multi-attribute-login.tsx
around lines 265-276, The Chip inside renderTags is receiving a duplicate key
because getTagProps({ index }) already injects a key; remove the explicit key={
option } from the Chip component (keep the spread {...getTagProps({ index })}
and the Tooltip's key if needed) so only one key prop is present; locate the
renderTags function and edit the Chip JSX to drop key={ option } while
preserving label={getDisplayName(option)} and size="small".

@codecov
Copy link

codecov bot commented Jan 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 55.88%. Comparing base (98bc214) to head (49784e8).
⚠️ Report is 266 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #9535   +/-   ##
=======================================
  Coverage   55.88%   55.88%           
=======================================
  Files          42       42           
  Lines        1020     1020           
  Branches      254      254           
=======================================
  Hits          570      570           
- Misses        439      450   +11     
+ Partials       11        0   -11     
Flag Coverage Δ
@wso2is/core 55.88% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.
see 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

/**
* Flattens and resolved form initial values and field metadata.
*/

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change

@pavinduLakshan
Copy link
Member

Purpose

Replaces the text input for allowed attributes with an Autocomplete component that fetches and displays claim URIs and display names. Improves usability by allowing selection from available claims, adds tooltips, and updates state management for selected claims. Also updates form submission logic to handle the new selection method.

WSO2.Identity.Server.Console.-.Multi.Attribute.Login.mp4

Related Issues

wso2/product-is#22655

Related PRs

  • N/A

Checklist

  • e2e cypress tests locally verified. (for internal contributers)
  • Manual test round performed and verified.
  • UX/UI review done on the final implementation.
  • Documentation provided. (Add links if there are any)
  • Relevant backend changes deployed and verified
  • Unit tests provided. (Add links if there are any)
  • Integration tests provided. (Add links if there are any)

Security checks

Developer Checklist (Mandatory)

  • Complete the Developer Checklist in the related product-is issue to track any behavioral change or migration impact.

Summary by CodeRabbit

  • New Features

    • Enhanced multi-attribute login configuration form with an interactive autocomplete interface for selecting claim URIs
    • Improved user experience with friendly claim labels displayed instead of raw identifiers
    • Added visual multi-selection support for managing allowed attributes in authentication configuration
    • Streamlined claim discovery through local integration for available options

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

Is there any specific reason to only show email and username attributes in the list of attributes?

@asra-ameer
Copy link
Contributor Author

For a quick local test, I added mock partial claims at the top of the file to check how the UI would display the attributes.
The actual payload structure in the code was not changed. This was only for testing locally.

Comment on lines -104 to +176
[ property.name ]: property.value
[property.name]: property.value
Copy link
Member

Choose a reason for hiding this comment

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

Is this intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no , i accidentally added space

Co-authored-by: Pavindu Lakshan <pavindulakshan@gmail.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
features/admin.server-configurations.v1/forms/multi-attribute-login.tsx (5)

83-99: Consider extracting inline styles to a stylesheet or styled-components.

Defining styles as inline objects works, but for consistency with the codebase and easier theming, consider using CSS modules, styled-components, or the project's existing styling pattern.


107-116: Memoize claimsParams to prevent potential refetch loops.

The claimsParams object is recreated on every render. If useGetAllLocalClaims uses referential equality checks, this could cause unnecessary refetches or infinite loops.

Proposed fix
+    const claimsParams: ClaimsGetParams = useMemo(() => ({
+        filter: "",
+        limit: 1000,
+        offset: 0,
+        sort: ""
+    }), []);
-    const claimsParams: ClaimsGetParams = {
-        filter: "",
-        limit: 1000,
-        offset: 0,
-        sort: ""
-    };

Also add useMemo to the imports on line 25:

-import React, { FunctionComponent, ReactElement, useEffect, useState } from "react";
+import React, { FunctionComponent, ReactElement, useEffect, useMemo, useState } from "react";

128-150: Move pure helper functions outside the component.

getClaimURIs and createClaimMap don't depend on component state or props. Moving them outside the component avoids unnecessary recreation on each render and improves clarity.

Proposed refactor

Move these functions above the component definition:

+const getClaimURIs = (claims: Claim[]): string[] => {
+    if (!claims || claims.length === 0) {
+        return [];
+    }
+    return claims
+        .map((claim: Claim) => claim?.claimURI)
+        .filter((uri: string) => typeof uri === "string" && uri.length > 0);
+};
+
+const createClaimMap = (claims: Claim[]): Map<string, string> => {
+    const map: Map<string, string> = new Map<string, string>();
+    if (!claims || claims.length === 0) {
+        return map;
+    }
+    claims.forEach((claim: Claim) => {
+        if (claim?.claimURI && claim?.displayName) {
+            map.set(claim.claimURI, claim.displayName);
+        }
+    });
+    return map;
+};
+
 export const MultiAttributeLoginForm: FunctionComponent<MultiAttributeLoginFormPropsInterface> = (

Then remove them from inside the component body.


152-154: Minor formatting: missing space after ||.

Proposed fix
-    const getDisplayName = (uri:string): string => {
-        return claimMap.get(uri) ||uri;
+    const getDisplayName = (uri: string): string => {
+        return claimMap.get(uri) || uri;
     };

171-178: Use forEach instead of map for side effects.

.map() is intended for transformations that return values. Since the return value is ignored here and you're only performing side effects (populating resolvedInitialValues and resolvedInitialFormValues), use .forEach() instead.

Proposed fix
-        initialValues.properties.map((property: ConnectorPropertyInterface) => {
-
+        initialValues.properties.forEach((property: ConnectorPropertyInterface) => {
             resolvedInitialValues.set(property.name, property);
             resolvedInitialFormValues = {
                 ...resolvedInitialFormValues,
                 [property.name]: property.value
             };
         });
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67043f3 and 49784e8.

📒 Files selected for processing (1)
  • features/admin.server-configurations.v1/forms/multi-attribute-login.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
features/admin.server-configurations.v1/forms/multi-attribute-login.tsx (1)
modules/core/src/models/claim.ts (2)
  • ClaimsGetParams (123-132)
  • Claim (22-48)
🔇 Additional comments (4)
features/admin.server-configurations.v1/forms/multi-attribute-login.tsx (4)

18-32: Imports look good.

The new imports for MUI components (Autocomplete, Chip, TextField, Tooltip) and the claims-related types/hook are appropriate for the refactored functionality.


198-216: Form submission logic looks correct.

The getUpdatedConfigurations function properly joins selected claims and returns the expected data structure. The handleClaimChange handler is appropriately simple.


253-260: Potential duplicate key in renderOption.

The props argument from MUI's Autocomplete renderOption may already include a key prop. Spreading props after setting an explicit key is correct here, but verify there are no console warnings about duplicate keys.


287-298: Submit button configuration looks correct.

The button properly handles disabled state, loading state, and visibility based on connector and read-only states.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants