From 96429a8e949f42965dc90fa0fb3863a0020882fe Mon Sep 17 00:00:00 2001 From: Afra Hussaindeen Date: Mon, 11 Nov 2024 15:21:28 +0530 Subject: [PATCH 01/11] Add support for claim-wise uniqueness validation --- .../resources/deployment.config.json.j2 | 3 + ...dit-additional-properties-local-claims.tsx | 60 ++++++++++++++++++- .../edit-basic-details-local-claims.tsx | 38 +++++++++++- features/admin.core.v1/configs/app.ts | 2 + features/admin.core.v1/models/config.ts | 4 ++ .../admin.core.v1/store/reducers/config.ts | 1 + modules/core/src/models/claim.ts | 13 ++++ .../i18n/src/models/namespaces/claims-ns.ts | 9 +++ .../src/translations/en-US/portals/claims.ts | 11 +++- 9 files changed, 135 insertions(+), 6 deletions(-) diff --git a/apps/console/java/org.wso2.identity.apps.console.server.feature/resources/deployment.config.json.j2 b/apps/console/java/org.wso2.identity.apps.console.server.feature/resources/deployment.config.json.j2 index f9a2bc76f46..b1f93b81b3c 100644 --- a/apps/console/java/org.wso2.identity.apps.console.server.feature/resources/deployment.config.json.j2 +++ b/apps/console/java/org.wso2.identity.apps.console.server.feature/resources/deployment.config.json.j2 @@ -1798,6 +1798,9 @@ {% if console.ui.is_marketing_consent_banner_enabled is defined %} "isMarketingConsentBannerEnabled": {{ console.ui.is_marketing_consent_banner_enabled }}, {% endif %} + {% if identity_mgt.user_claim_update.uniqueness.enable is defined %} + "isClaimUniquenessValidationEnabled": {{ identity_mgt.user_claim_update.uniqueness.enable }}, + {% endif %} {% if oauth.hash_tokens_and_secrets is defined %} "isClientSecretHashEnabled": {{ oauth.hash_tokens_and_secrets }}, {% endif %} diff --git a/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx b/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx index ca85335199d..21c4b6de1c3 100644 --- a/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx +++ b/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx @@ -17,13 +17,19 @@ */ import { Show } from "@wso2is/access-control"; -import { AppState, FeatureConfigInterface } from "@wso2is/admin.core.v1"; +import { AppState, FeatureConfigInterface, AppConstants, history } from "@wso2is/admin.core.v1"; +import useUIConfig from "@wso2is/admin.core.v1/hooks/use-ui-configs"; import { IdentityAppsError } from "@wso2is/core/errors"; import { hasRequiredScopes } from "@wso2is/core/helpers"; import { AlertLevels, Claim, TestableComponentInterface } from "@wso2is/core/models"; import { addAlert } from "@wso2is/core/store"; import { DynamicField , KeyValue, useTrigger } from "@wso2is/forms"; -import { EmphasizedSegment, PrimaryButton } from "@wso2is/react-components"; +import { + EmphasizedSegment, + Link, + Message, + PrimaryButton +} from "@wso2is/react-components"; import React, { FunctionComponent, ReactElement, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { useDispatch, useSelector } from "react-redux"; @@ -79,9 +85,43 @@ export const EditAdditionalPropertiesLocalClaims: [ featureConfig, allowedScopes ] ); + const RESTRICTED_PROPERTY_KEYS: string[] = [ "isUnique" ]; + + const [ showWarning, setShowWarning ] = useState(false); + + const { UIConfig } = useUIConfig(); + return ( + + + { showWarning && UIConfig?.isClaimUniquenessValidationEnabled && ( + + The 'isUnique' property is deprecated. Please use the   + { + history.push({ + pathname: AppConstants.getPaths() + .get("LOCAL_CLAIMS_EDIT") + .replace(":id", claim.id) + }); + } } + > + Uniqueness Validation Dropdown + +   to configure claim uniqueness. + + ) } + data-componentid={ `${ testId }-restricted-warning` } + /> + ) } + +

{ t("claims:local.additionalProperties.hint") }

@@ -101,13 +141,27 @@ export const EditAdditionalPropertiesLocalClaims: ) } requiredField={ true } update={ (data: KeyValue[]) => { + const hasRestrictedKey: boolean = data.some( + (item: KeyValue) => item.key === RESTRICTED_PROPERTY_KEYS[0] + ); + + setShowWarning(hasRestrictedKey); + + const filteredData: KeyValue[] = data.filter( + (item: KeyValue) => item.key !== RESTRICTED_PROPERTY_KEYS[0] + ); + + if (hasRestrictedKey) { + return; + } + const claimData: Claim = { ...claim }; delete claimData.id; delete claimData.dialectURI; const submitData: Claim = { ...claimData, - properties: [ ...data ] + properties: [ ...filteredData ] }; setIsSubmitting(true); diff --git a/features/admin.claims.v1/components/edit/local-claim/edit-basic-details-local-claims.tsx b/features/admin.claims.v1/components/edit/local-claim/edit-basic-details-local-claims.tsx index 73ef6aabcdf..38dedb5294e 100644 --- a/features/admin.claims.v1/components/edit/local-claim/edit-basic-details-local-claims.tsx +++ b/features/admin.claims.v1/components/edit/local-claim/edit-basic-details-local-claims.tsx @@ -18,6 +18,7 @@ import { Show } from "@wso2is/access-control"; import { AppConstants, AppState, FeatureConfigInterface, history } from "@wso2is/admin.core.v1"; +import useUIConfig from "@wso2is/admin.core.v1/hooks/use-ui-configs"; import { attributeConfig } from "@wso2is/admin.extensions.v1"; import { SCIMConfigs } from "@wso2is/admin.extensions.v1/configs/scim"; import { @@ -38,7 +39,8 @@ import { Claim, ExternalClaim, ProfileSchemaInterface, - TestableComponentInterface + TestableComponentInterface, + UniquenessScope } from "@wso2is/core/models"; import { addAlert, setProfileSchemaRequestLoadingStatus, setSCIMSchemas } from "@wso2is/core/store"; import { Field, Form } from "@wso2is/form"; @@ -135,6 +137,8 @@ export const EditBasicDetailsLocalClaims: FunctionComponent ) } + { + claim && !READONLY_CLAIM_CONFIGS.includes(claim?.claimURI) + && !hideSpecialClaims && mappingChecked + && UIConfig?.isClaimUniquenessValidationEnabled && ( + + ) + } { !READONLY_CLAIM_CONFIGS.includes(claim?.claimURI) && mappingChecked ? ( !hideSpecialClaims && diff --git a/features/admin.core.v1/configs/app.ts b/features/admin.core.v1/configs/app.ts index 592452d6d53..8c3149dc279 100644 --- a/features/admin.core.v1/configs/app.ts +++ b/features/admin.core.v1/configs/app.ts @@ -320,6 +320,8 @@ export class Config { hiddenUserStores: window[ "AppUtils" ]?.getConfig()?.ui?.hiddenUserStores, i18nConfigs: window[ "AppUtils" ]?.getConfig()?.ui?.i18nConfigs, identityProviderTemplates: window[ "AppUtils" ]?.getConfig()?.ui?.identityProviderTemplates, + isClaimUniquenessValidationEnabled: + window[ "AppUtils" ]?.getConfig()?.ui?.isClaimUniquenessValidationEnabled ?? false, isClientSecretHashEnabled: window[ "AppUtils" ]?.getConfig()?.ui?.isClientSecretHashEnabled, isCookieConsentBannerEnabled: window[ "AppUtils" ]?.getConfig()?.ui?.isCookieConsentBannerEnabled, isCustomClaimMappingEnabled: window[ "AppUtils" ]?.getConfig()?.ui?.isCustomClaimMappingEnabled, diff --git a/features/admin.core.v1/models/config.ts b/features/admin.core.v1/models/config.ts index 2dc521e3f45..2a3a823aec8 100644 --- a/features/admin.core.v1/models/config.ts +++ b/features/admin.core.v1/models/config.ts @@ -360,6 +360,10 @@ export interface UIConfigInterface extends CommonUIConfigInterface Date: Sun, 24 Nov 2024 11:40:11 +0530 Subject: [PATCH 02/11] Fix review comments --- .../edit-additional-properties-local-claims.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx b/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx index 21c4b6de1c3..a6dddb284ad 100644 --- a/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx +++ b/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx @@ -66,6 +66,10 @@ export const EditAdditionalPropertiesLocalClaims: const [ isSubmitting, setIsSubmitting ] = useState(false); + const RESTRICTED_PROPERTY_KEYS: string[] = [ "isUnique" ]; + + const [ showWarning, setShowWarning ] = useState(false); + const [ submit, setSubmit ] = useTrigger(); const dispatch: Dispatch = useDispatch(); @@ -85,10 +89,6 @@ export const EditAdditionalPropertiesLocalClaims: [ featureConfig, allowedScopes ] ); - const RESTRICTED_PROPERTY_KEYS: string[] = [ "isUnique" ]; - - const [ showWarning, setShowWarning ] = useState(false); - const { UIConfig } = useUIConfig(); return ( @@ -147,10 +147,6 @@ export const EditAdditionalPropertiesLocalClaims: setShowWarning(hasRestrictedKey); - const filteredData: KeyValue[] = data.filter( - (item: KeyValue) => item.key !== RESTRICTED_PROPERTY_KEYS[0] - ); - if (hasRestrictedKey) { return; } @@ -161,7 +157,7 @@ export const EditAdditionalPropertiesLocalClaims: delete claimData.dialectURI; const submitData: Claim = { ...claimData, - properties: [ ...filteredData ] + properties: [ ...data ] }; setIsSubmitting(true); From ebc30b2ca2d243ca75fdfaf12e984ecc8d7f84c1 Mon Sep 17 00:00:00 2001 From: Afra Hussaindeen Date: Mon, 25 Nov 2024 21:25:58 +0530 Subject: [PATCH 03/11] Improve alternative login identifier --- .../src/extensions/i18n/models/extensions.ts | 7 + .../i18n/resources/en-US/extensions.ts | 13 ++ .../alternative-login-identifier-page.tsx | 156 ++++++++++++++---- .../edit-basic-details-local-claims.tsx | 2 +- .../constants/claim-management-constants.ts | 5 + 5 files changed, 152 insertions(+), 31 deletions(-) diff --git a/apps/console/src/extensions/i18n/models/extensions.ts b/apps/console/src/extensions/i18n/models/extensions.ts index e4837bf4337..91695db50cd 100755 --- a/apps/console/src/extensions/i18n/models/extensions.ts +++ b/apps/console/src/extensions/i18n/models/extensions.ts @@ -2737,6 +2737,13 @@ export interface Extensions { }; claimUpdateNotification: { error: NotificationItem; + success: NotificationItem; + }; + claimUpdateConfirmation: { + header: string; + message: string; + content: string; + assertionHint: string; }; }; pageTitle: string; diff --git a/apps/console/src/extensions/i18n/resources/en-US/extensions.ts b/apps/console/src/extensions/i18n/resources/en-US/extensions.ts index f983b2e517c..be3fe1bad34 100755 --- a/apps/console/src/extensions/i18n/resources/en-US/extensions.ts +++ b/apps/console/src/extensions/i18n/resources/en-US/extensions.ts @@ -3037,7 +3037,20 @@ export const extensions: Extensions = { error: { description: "Error updating the attribute as an unique attribute. Please try again.", message: "Error updating claim" + }, + success: { + description: "Successfully updated the {{claimName}} uniqueness validation scope to across user stores.", + message: "Update successful" } + }, + claimUpdateConfirmation: { + header: "Before you proceed", + message: "Uniqueness validation for the selected attribute(s) will be applied across user stores.", + content: "Alternate log-in identifiers work only if the attribute(s) values are unique across " + + "the organization. This setting will ensure that the required uniqueness of attribute(s) is " + + "guaranteed for new users created through the system. However, it doesn't guarantee the same " + + "for existing users' attribute(s).", + assertionHint: "I understand and wish to proceed" } }, pageTitle: "Account Login", diff --git a/features/admin.alternative-login-identifier.v1/pages/alternative-login-identifier-page.tsx b/features/admin.alternative-login-identifier.v1/pages/alternative-login-identifier-page.tsx index b17558e19bc..dc6d2b70078 100644 --- a/features/admin.alternative-login-identifier.v1/pages/alternative-login-identifier-page.tsx +++ b/features/admin.alternative-login-identifier.v1/pages/alternative-login-identifier-page.tsx @@ -37,10 +37,10 @@ import { import { getUsernameConfiguration } from "@wso2is/admin.users.v1/utils/user-management-utils"; import { useValidationConfigData } from "@wso2is/admin.validation.v1/api"; import { IdentityAppsError } from "@wso2is/core/errors"; -import { AlertLevels, Claim, ClaimsGetParams, IdentifiableComponentInterface, Property } from "@wso2is/core/models"; +import { AlertLevels, Claim, ClaimsGetParams, IdentifiableComponentInterface, Property, UniquenessScope } from "@wso2is/core/models"; import { addAlert } from "@wso2is/core/store"; import { Field, Form } from "@wso2is/form"; -import { ContentLoader, EmphasizedSegment, Message, PageLayout } from "@wso2is/react-components"; +import { ConfirmationModal, ContentLoader, EmphasizedSegment, Message, PageLayout } from "@wso2is/react-components"; import { AxiosError } from "axios"; import isEmpty from "lodash-es/isEmpty"; import React, { FunctionComponent, ReactElement, useEffect, useState } from "react"; @@ -88,6 +88,8 @@ const AlternativeLoginIdentifierInterface: FunctionComponent(false); + const [ showConfirmationModal, setShowConfirmationModal ] = useState(false); + const [ pendingFormValues, setPendingFormValues ] = useState(null); const { data: validationData @@ -319,7 +321,9 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { - updateClaims(checkedClaims); + if (checkedClaims.length > 0) { + updateClaims(checkedClaims); + } handleUpdateSuccess(); loadConnectorDetails(); }) @@ -332,27 +336,26 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { - let isClaimUpdate: boolean = false; - let updatedClaimProperties: Property[] = [ ...claim.properties ]; - const isUniqueIndex: number = claim?.properties?.findIndex((property: Property) => property.key === "isUnique"); - - if (checkedClaims?.includes(claim.claimURI)) { - if (isUniqueIndex !== -1 && claim.properties[isUniqueIndex].value === "false") { - isClaimUpdate = true; - updatedClaimProperties[isUniqueIndex].value = "true"; - } else if (isUniqueIndex === -1) { - isClaimUpdate = true; - updatedClaimProperties.push({ key: "isUnique", value: "true" }); - } - } else if (isUniqueIndex !== -1) { - isClaimUpdate = true; - updatedClaimProperties = updatedClaimProperties.filter((property: Property) => - property.key !== "isUnique"); - } - - return { isClaimUpdate, updatedClaimProperties }; + /** + * Updates the uniqueness scope of a claim if it's selected and needs to be updated to ACROSS_USERSTORES. + * Does not modify claims that are not selected. + */ + const updateClaimUniquenessScope = (claim: Claim, checkedClaims: string[]) => { + const isSelected = checkedClaims?.includes(claim.claimURI); + + // Only update if selected and either uniquenessScope is undefined or not ACROSS_USERSTORES + const needsUpdate = isSelected && + (!claim.uniquenessScope || claim.uniquenessScope !== UniquenessScope.ACROSS_USERSTORES); + + return { + isClaimUpdate: needsUpdate, + updatedClaim: needsUpdate + ? { + ...claim, + uniquenessScope: UniquenessScope.ACROSS_USERSTORES + } + : claim + }; }; // Define a function to update and dispatch alerts @@ -365,6 +368,18 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { + dispatch(addAlert({ + description: t( + "extensions:manage.accountLogin.alternativeLoginIdentifierPage." + + "claimUpdateNotification.success.description", + { claimName: claim.displayName } + ), + level: AlertLevels.SUCCESS, + message: t( + "extensions:manage.accountLogin.alternativeLoginIdentifierPage." + + "claimUpdateNotification.success.message" + ) + })); getClaims(); }) .catch((error: IdentityAppsError) => { @@ -380,10 +395,12 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { for (const claim of availableClaims) { - const { isClaimUpdate, updatedClaimProperties } = updateClaimProperties(claim, checkedClaims); - const updatedClaim: Claim = { ...claim, properties: updatedClaimProperties }; + const { isClaimUpdate, updatedClaim } = updateClaimUniquenessScope(claim, checkedClaims); if (isClaimUpdate) { updateClaimAndAlert(updatedClaim); @@ -392,10 +409,9 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { - + const getProcessedCheckedClaims = (values: AlternativeLoginIdentifierFormInterface): string[] => { const processedFormValues: AlternativeLoginIdentifierFormInterface = { ...values }; let checkedClaims: string[] = availableClaims .filter((claim: Claim) => @@ -407,10 +423,58 @@ const AlternativeLoginIdentifierInterface: FunctionComponent item !== ClaimManagementConstants.EMAIL_CLAIM_URI); } - const updatedConnectorData: any = getUpdatedConfigurations(checkedClaims); + + return checkedClaims; + }; + + /** + * Checks if any claims need uniqueness scope update + */ + const needsUniquenessScopeUpdate = (checkedClaims: string[]): boolean => { + return checkedClaims.some(claimURI => { + const claim = availableClaims.find(c => c.claimURI === claimURI); + return !claim.uniquenessScope || claim.uniquenessScope !== UniquenessScope.ACROSS_USERSTORES; + }); + }; + + /** + * Processes form submission and updates connector and claims + */ + const processFormSubmission = ( + formValues: AlternativeLoginIdentifierFormInterface, + hasUserConsent: boolean = false + ): void => { + const checkedClaims = getProcessedCheckedClaims(formValues); + const updatedConnectorData = getUpdatedConfigurations(checkedClaims); + const requiresUniquenessScopeUpdate = needsUniquenessScopeUpdate(checkedClaims); + + // Show confirmation modal if uniqueness scope update is needed and no consent yet + if (!hasUserConsent && requiresUniquenessScopeUpdate) { + setPendingFormValues(formValues); + setShowConfirmationModal(true); + return; + } updateConnector(updatedConnectorData, checkedClaims); + }; + + /** + * Handles the initial form submission + */ + const handleSubmit = (values: AlternativeLoginIdentifierFormInterface): void => { + processFormSubmission(values, false); + }; + + /** + * Handles the form submission after user consents to uniqueness scope update + */ + const handleConsentedSubmit = (): void => { + if (!pendingFormValues) { + return; + } + processFormSubmission(pendingFormValues, true); + setShowConfirmationModal(false); }; useEffect(() => { @@ -576,6 +640,38 @@ const AlternativeLoginIdentifierInterface: FunctionComponent ) } + { + setShowConfirmationModal(false); + } } + type="warning" + open={ showConfirmationModal } + assertion={ t("common:confirm") } + assertionHint={ t("extensions:manage.accountLogin.alternativeLoginIdentifierPage." + + "claimUpdateConfirmation.assertionHint") } + assertionType="checkbox" + primaryAction={ t("common:confirm") } + secondaryAction={ t("common:cancel") } + onSecondaryActionClick={ (): void => { + setShowConfirmationModal(false); + } } + onPrimaryActionClick={ handleConsentedSubmit } + closeOnDimmerClick={ false } + > + + { t("extensions:manage.accountLogin.alternativeLoginIdentifierPage." + + "claimUpdateConfirmation.header") } + + + { t("extensions:manage.accountLogin.alternativeLoginIdentifierPage." + + "claimUpdateConfirmation.message") } + + + { t("extensions:manage.accountLogin.alternativeLoginIdentifierPage." + + "claimUpdateConfirmation.content") } + + ); }; diff --git a/features/admin.claims.v1/components/edit/local-claim/edit-basic-details-local-claims.tsx b/features/admin.claims.v1/components/edit/local-claim/edit-basic-details-local-claims.tsx index dd25cb6a9e3..9c5afa652c1 100644 --- a/features/admin.claims.v1/components/edit/local-claim/edit-basic-details-local-claims.tsx +++ b/features/admin.claims.v1/components/edit/local-claim/edit-basic-details-local-claims.tsx @@ -574,7 +574,7 @@ export const EditBasicDetailsLocalClaims: FunctionComponent Date: Tue, 26 Nov 2024 11:35:32 +0530 Subject: [PATCH 04/11] Add translation support --- ...dit-additional-properties-local-claims.tsx | 48 ++++++++++++------- .../i18n/src/models/namespaces/claims-ns.ts | 4 ++ .../src/translations/en-US/portals/claims.ts | 5 ++ 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx b/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx index ce4115d71b2..391555147d9 100644 --- a/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx +++ b/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx @@ -30,7 +30,7 @@ import { PrimaryButton } from "@wso2is/react-components"; import React, { FunctionComponent, ReactElement, useMemo, useState } from "react"; -import { useTranslation } from "react-i18next"; +import { Trans, useTranslation } from "react-i18next"; import { useDispatch, useSelector } from "react-redux"; import { Dispatch } from "redux"; import { Grid } from "semantic-ui-react"; @@ -102,26 +102,38 @@ export const EditAdditionalPropertiesLocalClaims: - { showWarning && UIConfig?.isClaimUniquenessValidationEnabled && ( + { showWarning && ( - The 'isUnique' property is deprecated. Please use the   - { - history.push({ - pathname: AppConstants.getPaths() - .get("LOCAL_CLAIMS_EDIT") - .replace(":id", claim.id) - }); - } } - > - Uniqueness Validation Dropdown - -   to configure claim uniqueness. - + + { UIConfig?.isClaimUniquenessValidationEnabled ? ( + <> + The 'isUnique' property is deprecated. Please use the + { + history.push({ + pathname: AppConstants.getPaths() + .get("LOCAL_CLAIMS_EDIT") + .replace(":id", claim.id) + }); + } } + > Uniqueness Validation Dropdown + to configure claim uniqueness. + + ) : ( + "The 'isUnique' property is deprecated." + ) } + ) } data-componentid={ `${ testId }-restricted-warning` } /> diff --git a/modules/i18n/src/models/namespaces/claims-ns.ts b/modules/i18n/src/models/namespaces/claims-ns.ts index 6989ed4517f..617a1f5891c 100644 --- a/modules/i18n/src/models/namespaces/claims-ns.ts +++ b/modules/i18n/src/models/namespaces/claims-ns.ts @@ -439,6 +439,10 @@ export interface ClaimsNS { }; additionalProperties: { hint: string; + isUniqueDeprecationMessage: { + uniquenessDisabled: string; + uniquenessEnabled: string; + }; key: string; value: string; keyRequiredErrorMessage: string; diff --git a/modules/i18n/src/translations/en-US/portals/claims.ts b/modules/i18n/src/translations/en-US/portals/claims.ts index c06a7ab610e..cad5d2f93d6 100644 --- a/modules/i18n/src/translations/en-US/portals/claims.ts +++ b/modules/i18n/src/translations/en-US/portals/claims.ts @@ -394,6 +394,11 @@ export const claims: ClaimsNS = { local: { additionalProperties: { hint: "Use when writing an extension using current attributes", + isUniqueDeprecationMessage: { + uniquenessDisabled: "The 'isUnique' property is deprecated.", + uniquenessEnabled: "The 'isUnique' property is deprecated. Please use the " + + "<1>Uniqueness Validation Dropdown to configure claim uniqueness." + }, key: "Name", keyRequiredErrorMessage: "Enter a name", value: "Value", From 7c8f7f2203171477699f698b6e4dfd00b1a27e27 Mon Sep 17 00:00:00 2001 From: Afra Hussaindeen Date: Tue, 26 Nov 2024 11:53:22 +0530 Subject: [PATCH 05/11] Fix eslint issue --- .../alternative-login-identifier-page.tsx | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/features/admin.alternative-login-identifier.v1/pages/alternative-login-identifier-page.tsx b/features/admin.alternative-login-identifier.v1/pages/alternative-login-identifier-page.tsx index dc6d2b70078..68ef8d62b4f 100644 --- a/features/admin.alternative-login-identifier.v1/pages/alternative-login-identifier-page.tsx +++ b/features/admin.alternative-login-identifier.v1/pages/alternative-login-identifier-page.tsx @@ -37,7 +37,13 @@ import { import { getUsernameConfiguration } from "@wso2is/admin.users.v1/utils/user-management-utils"; import { useValidationConfigData } from "@wso2is/admin.validation.v1/api"; import { IdentityAppsError } from "@wso2is/core/errors"; -import { AlertLevels, Claim, ClaimsGetParams, IdentifiableComponentInterface, Property, UniquenessScope } from "@wso2is/core/models"; +import { + AlertLevels, + Claim, + ClaimsGetParams, + IdentifiableComponentInterface, + UniquenessScope +} from "@wso2is/core/models"; import { addAlert } from "@wso2is/core/store"; import { Field, Form } from "@wso2is/form"; import { ConfirmationModal, ContentLoader, EmphasizedSegment, Message, PageLayout } from "@wso2is/react-components"; @@ -341,15 +347,14 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { - const isSelected = checkedClaims?.includes(claim.claimURI); - - // Only update if selected and either uniquenessScope is undefined or not ACROSS_USERSTORES - const needsUpdate = isSelected && + const isSelected: boolean = checkedClaims?.includes(claim.claimURI); + + const needsUpdate: boolean = isSelected && (!claim.uniquenessScope || claim.uniquenessScope !== UniquenessScope.ACROSS_USERSTORES); return { isClaimUpdate: needsUpdate, - updatedClaim: needsUpdate + updatedClaim: needsUpdate ? { ...claim, uniquenessScope: UniquenessScope.ACROSS_USERSTORES @@ -431,8 +436,9 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { - return checkedClaims.some(claimURI => { - const claim = availableClaims.find(c => c.claimURI === claimURI); + return checkedClaims.some((claimURI: string) => { + const claim: Claim = availableClaims.find((c: Claim) => c.claimURI === claimURI); + return !claim.uniquenessScope || claim.uniquenessScope !== UniquenessScope.ACROSS_USERSTORES; }); }; @@ -441,17 +447,18 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { - const checkedClaims = getProcessedCheckedClaims(formValues); - const updatedConnectorData = getUpdatedConfigurations(checkedClaims); - const requiresUniquenessScopeUpdate = needsUniquenessScopeUpdate(checkedClaims); + const checkedClaims: string[] = getProcessedCheckedClaims(formValues); + const updatedConnectorData: any = getUpdatedConfigurations(checkedClaims); + const requiresUniquenessScopeUpdate: boolean = needsUniquenessScopeUpdate(checkedClaims); // Show confirmation modal if uniqueness scope update is needed and no consent yet if (!hasUserConsent && requiresUniquenessScopeUpdate) { setPendingFormValues(formValues); setShowConfirmationModal(true); + return; } From b48ccc153a3e3711cd7ef35b5e55312fec58b1ec Mon Sep 17 00:00:00 2001 From: Afra Hussaindeen Date: Sat, 30 Nov 2024 10:46:07 +0530 Subject: [PATCH 06/11] Add support for claim property key validation --- .../console/src/public/deployment.config.json | 1 + ...dit-additional-properties-local-claims.tsx | 89 ++++++++----------- .../forms/src/components/dynamic-field.tsx | 25 ++++++ .../src/translations/en-US/portals/claims.ts | 4 +- 4 files changed, 66 insertions(+), 53 deletions(-) diff --git a/apps/console/src/public/deployment.config.json b/apps/console/src/public/deployment.config.json index acd2d775443..831f821ca3f 100644 --- a/apps/console/src/public/deployment.config.json +++ b/apps/console/src/public/deployment.config.json @@ -1234,6 +1234,7 @@ "enabled": true } }, + "isClaimUniquenessValidationEnabled": false, "isClientSecretHashEnabled": false, "isCookieConsentBannerEnabled": true, "isCustomClaimMappingEnabled": true, diff --git a/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx b/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx index 391555147d9..e96213c8d0b 100644 --- a/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx +++ b/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx @@ -26,7 +26,6 @@ import { DynamicField , KeyValue, useTrigger } from "@wso2is/forms"; import { EmphasizedSegment, Link, - Message, PrimaryButton } from "@wso2is/react-components"; import React, { FunctionComponent, ReactElement, useMemo, useState } from "react"; @@ -68,8 +67,6 @@ export const EditAdditionalPropertiesLocalClaims: const RESTRICTED_PROPERTY_KEYS: string[] = [ "isUnique" ]; - const [ showWarning, setShowWarning ] = useState(false); - const [ submit, setSubmit ] = useTrigger(); const dispatch: Dispatch = useDispatch(); @@ -100,46 +97,6 @@ export const EditAdditionalPropertiesLocalClaims: return ( - - - { showWarning && ( - - { UIConfig?.isClaimUniquenessValidationEnabled ? ( - <> - The 'isUnique' property is deprecated. Please use the - { - history.push({ - pathname: AppConstants.getPaths() - .get("LOCAL_CLAIMS_EDIT") - .replace(":id", claim.id) - }); - } } - > Uniqueness Validation Dropdown - to configure claim uniqueness. - - ) : ( - "The 'isUnique' property is deprecated." - ) } - - ) } - data-componentid={ `${ testId }-restricted-warning` } - /> - ) } - -

{ t("claims:local.additionalProperties.hint") }

@@ -158,17 +115,47 @@ export const EditAdditionalPropertiesLocalClaims: "valueRequiredErrorMessage" ) } requiredField={ true } - update={ (data: KeyValue[]) => { - const hasRestrictedKey: boolean = data.some( - (item: KeyValue) => item.key === RESTRICTED_PROPERTY_KEYS[0] - ); - - setShowWarning(hasRestrictedKey); + keyValidation={ (key: string) => { + if (RESTRICTED_PROPERTY_KEYS.includes(key)) { - if (hasRestrictedKey) { - return; + return false; } + return true; + } } + keyValidationWarningMessage={ + UIConfig?.isClaimUniquenessValidationEnabled ? ( + + The 'isUnique' property is deprecated. Please use + { + history.push({ + pathname: AppConstants.getPaths() + .get("LOCAL_CLAIMS_EDIT") + .replace(":id", claim.id) + }); + } } + > Uniqueness Validation + option to configure claim uniqueness. + + ) : ( + + The 'isUnique' property is deprecated. + + ) + } + update={ (data: KeyValue[]) => { const claimData: Claim = { ...claim }; delete claimData.id; diff --git a/modules/forms/src/components/dynamic-field.tsx b/modules/forms/src/components/dynamic-field.tsx index 0363c840bed..4f2b34013dc 100644 --- a/modules/forms/src/components/dynamic-field.tsx +++ b/modules/forms/src/components/dynamic-field.tsx @@ -101,6 +101,15 @@ export interface DynamicFieldPropsInterface extends TestableComponentInterface { * Make the form read only. */ readOnly?: boolean; + /** + * Validation function for the key field + */ + keyValidation?: (key: string) => boolean; + /** + * Warning message to show when key validation fails + * Can be string or JSX content + */ + keyValidationWarningMessage?: string | ReactElement; } /** @@ -128,6 +137,8 @@ export const DynamicField: FunctionComponent = ( requiredField, duplicateKeyErrorMsg, readOnly, + keyValidation, + keyValidationWarningMessage, [ "data-testid" ]: testId } = props; @@ -138,6 +149,7 @@ export const DynamicField: FunctionComponent = ( const [ updateMapIndex, setUpdateMapIndex ] = useState(null); const [ showAddErrorMsg, setAddShowErrorMsg ] = useState(false); const [ showEditErrorMsg, setShowEditErrorMsg ] = useState(false); + const [ showKeyValidationWarningMsg, setShowKeyValidationWarningMsg ] = useState(false); const initRender = useRef(true); @@ -203,9 +215,22 @@ export const DynamicField: FunctionComponent = (
) } + { + showKeyValidationWarningMsg && ( + + { keyValidationWarningMessage } + + ) + } ) => { + if (keyValidation && !keyValidation(values.get("key").toString())) { + setShowKeyValidationWarningMsg(true); + + return; + } + setShowKeyValidationWarningMsg(false); if (!showAddErrorMsg) { const tempFields: Map = new Map(fields); const newIndex: number = tempFields.size > 0 diff --git a/modules/i18n/src/translations/en-US/portals/claims.ts b/modules/i18n/src/translations/en-US/portals/claims.ts index cad5d2f93d6..06f3819a9df 100644 --- a/modules/i18n/src/translations/en-US/portals/claims.ts +++ b/modules/i18n/src/translations/en-US/portals/claims.ts @@ -396,8 +396,8 @@ export const claims: ClaimsNS = { hint: "Use when writing an extension using current attributes", isUniqueDeprecationMessage: { uniquenessDisabled: "The 'isUnique' property is deprecated.", - uniquenessEnabled: "The 'isUnique' property is deprecated. Please use the " + - "<1>Uniqueness Validation Dropdown to configure claim uniqueness." + uniquenessEnabled: "The 'isUnique' property is deprecated. Please use " + + "<1>Uniqueness Validation option to configure claim uniqueness." }, key: "Name", keyRequiredErrorMessage: "Enter a name", From 82f4f65b41563812f27b2d06dcaf49925d17a60d Mon Sep 17 00:00:00 2001 From: Afra Hussaindeen Date: Sun, 1 Dec 2024 12:36:02 +0530 Subject: [PATCH 07/11] Update the uniqueness validation dropdown display condition --- .../edit/local-claim/edit-basic-details-local-claims.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/features/admin.claims.v1/components/edit/local-claim/edit-basic-details-local-claims.tsx b/features/admin.claims.v1/components/edit/local-claim/edit-basic-details-local-claims.tsx index 9c5afa652c1..4571efd44af 100644 --- a/features/admin.claims.v1/components/edit/local-claim/edit-basic-details-local-claims.tsx +++ b/features/admin.claims.v1/components/edit/local-claim/edit-basic-details-local-claims.tsx @@ -570,14 +570,13 @@ export const EditBasicDetailsLocalClaims: FunctionComponent Date: Tue, 3 Dec 2024 08:34:20 +0530 Subject: [PATCH 08/11] Fix review comments --- .../alternative-login-identifier-page.tsx | 36 +++++++++---------- ...dit-additional-properties-local-claims.tsx | 9 ++--- .../edit-basic-details-local-claims.tsx | 6 ++-- .../constants/claim-management-constants.ts | 5 +++ .../forms/src/components/dynamic-field.tsx | 2 +- .../src/translations/en-US/portals/claims.ts | 2 +- 6 files changed, 31 insertions(+), 29 deletions(-) diff --git a/features/admin.alternative-login-identifier.v1/pages/alternative-login-identifier-page.tsx b/features/admin.alternative-login-identifier.v1/pages/alternative-login-identifier-page.tsx index 68ef8d62b4f..a5d0ce3353a 100644 --- a/features/admin.alternative-login-identifier.v1/pages/alternative-login-identifier-page.tsx +++ b/features/admin.alternative-login-identifier.v1/pages/alternative-login-identifier-page.tsx @@ -349,12 +349,12 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { const isSelected: boolean = checkedClaims?.includes(claim.claimURI); - const needsUpdate: boolean = isSelected && - (!claim.uniquenessScope || claim.uniquenessScope !== UniquenessScope.ACROSS_USERSTORES); + const shouldUpdateClaim: boolean = isSelected && + (claim.uniquenessScope !== UniquenessScope.ACROSS_USERSTORES); return { - isClaimUpdate: needsUpdate, - updatedClaim: needsUpdate + isClaimUpdate: shouldUpdateClaim, + updatedClaim: shouldUpdateClaim ? { ...claim, uniquenessScope: UniquenessScope.ACROSS_USERSTORES @@ -363,7 +363,7 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { const claimId: string = claim?.id; @@ -401,7 +401,7 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { for (const claim of availableClaims) { @@ -414,7 +414,7 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { const processedFormValues: AlternativeLoginIdentifierFormInterface = { ...values }; @@ -424,7 +424,7 @@ const AlternativeLoginIdentifierInterface: FunctionComponent claim?.claimURI); - // Remove the email attribute from the allowed attributes list when email username type is enabled + // Remove the email attribute from the allowed attributes list when email username type is enabled. if (!isAlphanumericUsername) { checkedClaims = checkedClaims.filter((item: string) => item !== ClaimManagementConstants.EMAIL_CLAIM_URI); } @@ -433,18 +433,18 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { + const shouldUpdateUniquenessScope = (checkedClaims: string[]): boolean => { return checkedClaims.some((claimURI: string) => { const claim: Claim = availableClaims.find((c: Claim) => c.claimURI === claimURI); - return !claim.uniquenessScope || claim.uniquenessScope !== UniquenessScope.ACROSS_USERSTORES; + return claim.uniquenessScope !== UniquenessScope.ACROSS_USERSTORES; }); }; /** - * Processes form submission and updates connector and claims + * Processes form submission and updates connector and claims. */ const processFormSubmission = ( formValues: AlternativeLoginIdentifierFormInterface, @@ -452,9 +452,9 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { const checkedClaims: string[] = getProcessedCheckedClaims(formValues); const updatedConnectorData: any = getUpdatedConfigurations(checkedClaims); - const requiresUniquenessScopeUpdate: boolean = needsUniquenessScopeUpdate(checkedClaims); + const requiresUniquenessScopeUpdate: boolean = shouldUpdateUniquenessScope(checkedClaims); - // Show confirmation modal if uniqueness scope update is needed and no consent yet + // Show confirmation modal if uniqueness scope update is required and no consent received yet. if (!hasUserConsent && requiresUniquenessScopeUpdate) { setPendingFormValues(formValues); setShowConfirmationModal(true); @@ -466,14 +466,14 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { processFormSubmission(values, false); }; /** - * Handles the form submission after user consents to uniqueness scope update + * Handles the form submission after user consents to uniqueness scope update. */ const handleConsentedSubmit = (): void => { if (!pendingFormValues) { @@ -505,7 +505,7 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { if (validationData) { @@ -648,7 +648,7 @@ const AlternativeLoginIdentifierInterface: FunctionComponent { setShowConfirmationModal(false); } } diff --git a/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx b/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx index e96213c8d0b..aef122cafe6 100644 --- a/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx +++ b/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2020-2024, WSO2 LLC. (https://www.wso2.com). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -65,8 +65,6 @@ export const EditAdditionalPropertiesLocalClaims: const [ isSubmitting, setIsSubmitting ] = useState(false); - const RESTRICTED_PROPERTY_KEYS: string[] = [ "isUnique" ]; - const [ submit, setSubmit ] = useTrigger(); const dispatch: Dispatch = useDispatch(); @@ -116,8 +114,7 @@ export const EditAdditionalPropertiesLocalClaims: ) } requiredField={ true } keyValidation={ (key: string) => { - if (RESTRICTED_PROPERTY_KEYS.includes(key)) { - + if (ClaimManagementConstants.RESTRICTED_PROPERTY_KEYS.includes(key)) { return false; } @@ -142,7 +139,7 @@ export const EditAdditionalPropertiesLocalClaims: }); } } > Uniqueness Validation - option to configure claim uniqueness. + option to configure attribute uniqueness. ) : ( Uniqueness Validation option to configure claim uniqueness." + "<1>Uniqueness Validation option to configure attribute uniqueness." }, key: "Name", keyRequiredErrorMessage: "Enter a name", From 1aa18188755d47574d43ede063ee4c07227e93a3 Mon Sep 17 00:00:00 2001 From: Afra Hussaindeen Date: Tue, 3 Dec 2024 11:47:45 +0530 Subject: [PATCH 09/11] Fix link to the claim edit's general tab --- ...dit-additional-properties-local-claims.tsx | 6 ++-- .../constants/claim-management-constants.ts | 11 ++++++++ .../pages/local-claims-edit.tsx | 28 +++++++++++++------ 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx b/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx index aef122cafe6..064b1b13a1f 100644 --- a/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx +++ b/features/admin.claims.v1/components/edit/local-claim/edit-additional-properties-local-claims.tsx @@ -26,7 +26,8 @@ import { DynamicField , KeyValue, useTrigger } from "@wso2is/forms"; import { EmphasizedSegment, Link, - PrimaryButton + PrimaryButton, + TAB_URL_HASH_FRAGMENT } from "@wso2is/react-components"; import React, { FunctionComponent, ReactElement, useMemo, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; @@ -34,7 +35,7 @@ import { useDispatch, useSelector } from "react-redux"; import { Dispatch } from "redux"; import { Grid } from "semantic-ui-react"; import { updateAClaim } from "../../../api"; -import { ClaimManagementConstants } from "../../../constants"; +import { ClaimManagementConstants, ClaimTabIDs } from "../../../constants"; /** * Prop types for `EditAdditionalPropertiesLocalClaims` component @@ -133,6 +134,7 @@ export const EditAdditionalPropertiesLocalClaims: external={ false } onClick={ () => { history.push({ + hash: `#${TAB_URL_HASH_FRAGMENT}${ClaimTabIDs.GENERAL}`, pathname: AppConstants.getPaths() .get("LOCAL_CLAIMS_EDIT") .replace(":id", claim.id) diff --git a/features/admin.claims.v1/constants/claim-management-constants.ts b/features/admin.claims.v1/constants/claim-management-constants.ts index 848678d2990..1d672d2084c 100644 --- a/features/admin.claims.v1/constants/claim-management-constants.ts +++ b/features/admin.claims.v1/constants/claim-management-constants.ts @@ -229,3 +229,14 @@ export class ClaimManagementConstants { public static readonly REGEX_FIELD_MAX_LENGTH: number = 255; public static readonly REGEX_FIELD_MIN_LENGTH: number = 3; } + +/** + * Unique identifiers for claim edit tabs. + * + * @readonly + */ +export enum ClaimTabIDs { + GENERAL = "general", + ATTRIBUTE_MAPPINGS = "attribute-mappings", + ADDITIONAL_PROPERTIES = "additional-properties" +} diff --git a/features/admin.claims.v1/pages/local-claims-edit.tsx b/features/admin.claims.v1/pages/local-claims-edit.tsx index 2eb7ffdac65..e7e84cd65dc 100644 --- a/features/admin.claims.v1/pages/local-claims-edit.tsx +++ b/features/admin.claims.v1/pages/local-claims-edit.tsx @@ -23,7 +23,7 @@ import { PRIMARY_USERSTORE } from "@wso2is/admin.userstores.v1/constants"; import { UserStoreBasicData } from "@wso2is/admin.userstores.v1/models"; import { AlertLevels, Claim, TestableComponentInterface } from "@wso2is/core/models"; import { addAlert } from "@wso2is/core/store"; -import { AnimatedAvatar, ResourceTab, TabPageLayout } from "@wso2is/react-components"; +import { AnimatedAvatar, ResourceTab, ResourceTabPaneInterface, TabPageLayout } from "@wso2is/react-components"; import { AxiosResponse } from "axios"; import React, { FunctionComponent, ReactElement, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; @@ -37,6 +37,7 @@ import { EditBasicDetailsLocalClaims, EditMappedAttributesLocalClaims } from "../components"; +import { ClaimTabIDs } from "../constants/claim-management-constants"; /** * Props for the Local Claims edit page. @@ -72,6 +73,7 @@ const LocalClaimsEditPage: FunctionComponent = ( const [ claim, setClaim ] = useState(null); const [ isLocalClaimDetailsRequestLoading, setIsLocalClaimDetailsRequestLoading ] = useState(false); const [ userStores, setUserStores ] = useState([]); + const defaultActiveIndex: string = ClaimTabIDs.GENERAL; const dispatch: Dispatch = useDispatch(); @@ -136,11 +138,10 @@ const LocalClaimsEditPage: FunctionComponent = ( /** * Contains the data of the panes. */ - const panes: { - menuItem: string; - render: () => JSX.Element; - }[] = [ + const panes: ResourceTabPaneInterface[] = [ { + componentId: "general", + "data-tabid": ClaimTabIDs.GENERAL, menuItem: t("claims:local.pageLayout.edit.tabs.general"), render: () => ( @@ -153,6 +154,8 @@ const LocalClaimsEditPage: FunctionComponent = ( ) }, { + componentId: "attribute-mappings", + "data-tabid": ClaimTabIDs.ATTRIBUTE_MAPPINGS, menuItem: t("claims:local.pageLayout.edit.tabs.mappedAttributes"), render: () => ( @@ -166,6 +169,8 @@ const LocalClaimsEditPage: FunctionComponent = ( ) }, { + componentId: "additional-properties", + "data-tabid": ClaimTabIDs.ADDITIONAL_PROPERTIES, menuItem: t("claims:local.pageLayout.edit.tabs.additionalProperties"), render: () => ( @@ -182,11 +187,10 @@ const LocalClaimsEditPage: FunctionComponent = ( /** * Contains the data of the basic panes. */ - const basicPanes: { - menuItem: string; - render: () => JSX.Element; - }[] = [ + const basicPanes: ResourceTabPaneInterface[] = [ { + componentId: "general", + "data-tabid": ClaimTabIDs.GENERAL, menuItem: t("claims:local.pageLayout.edit.tabs.general"), render: () => ( @@ -199,6 +203,8 @@ const LocalClaimsEditPage: FunctionComponent = ( ) }, { + componentId: "attribute-mappings", + "data-tabid": ClaimTabIDs.ATTRIBUTE_MAPPINGS, menuItem: t("claims:local.pageLayout.edit.tabs.mappedAttributes"), render: () => ( @@ -260,12 +266,16 @@ const LocalClaimsEditPage: FunctionComponent = ( ) : userStores?.length >= 1 ? ( ) : ( Date: Tue, 3 Dec 2024 12:33:47 +0530 Subject: [PATCH 10/11] =?UTF-8?q?Add=20changeset=20=F0=9F=A6=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/gentle-months-refuse.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changeset/gentle-months-refuse.md diff --git a/.changeset/gentle-months-refuse.md b/.changeset/gentle-months-refuse.md new file mode 100644 index 00000000000..98b7762f8f7 --- /dev/null +++ b/.changeset/gentle-months-refuse.md @@ -0,0 +1,11 @@ +--- +"@wso2is/admin.alternative-login-identifier.v1": patch +"@wso2is/admin.claims.v1": patch +"@wso2is/admin.core.v1": patch +"@wso2is/forms": patch +"@wso2is/console": patch +"@wso2is/core": patch +"@wso2is/i18n": patch +--- + +Add support for claim-wise uniqueness validation From 32fec6a5960c62780009b2d358bae81f319c021c Mon Sep 17 00:00:00 2001 From: Afra Hussaindeen Date: Fri, 6 Dec 2024 09:42:44 +0530 Subject: [PATCH 11/11] Update the modal and alert message content --- .../src/extensions/i18n/resources/en-US/extensions.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/console/src/extensions/i18n/resources/en-US/extensions.ts b/apps/console/src/extensions/i18n/resources/en-US/extensions.ts index be3fe1bad34..cd80956387e 100755 --- a/apps/console/src/extensions/i18n/resources/en-US/extensions.ts +++ b/apps/console/src/extensions/i18n/resources/en-US/extensions.ts @@ -3039,17 +3039,17 @@ export const extensions: Extensions = { message: "Error updating claim" }, success: { - description: "Successfully updated the {{claimName}} uniqueness validation scope to across user stores.", + description: "Successfully updated the {{claimName}} uniqueness validation scope.", message: "Update successful" } }, claimUpdateConfirmation: { header: "Before you proceed", message: "Uniqueness validation for the selected attribute(s) will be applied across user stores.", - content: "Alternate log-in identifiers work only if the attribute(s) values are unique across " + - "the organization. This setting will ensure that the required uniqueness of attribute(s) is " + - "guaranteed for new users created through the system. However, it doesn't guarantee the same " + - "for existing users' attribute(s).", + content: "This setting ensures values of selected attribute(s) remain unique across the " + + "organization for new users, which is required for alternate login identifiers to work. " + + "However, it does not guarantee uniqueness for attribute(s) of existing users that remain " + + "unchanged.", assertionHint: "I understand and wish to proceed" } },