From 00df8aa91d08213df3707327b21084f50ac021ab Mon Sep 17 00:00:00 2001 From: DilshanSenarath <74205483+DilshanSenarath@users.noreply.github.com> Date: Wed, 1 Jan 2025 16:52:32 +0530 Subject: [PATCH 01/10] add the config to modify the primary user store domain name in console app --- .eslintrc.js | 4 +- .../resources/deployment.config.json.j2 | 3 + .../components/all-users-list.tsx | 15 ++-- .../components/guests/edit-guest-user.tsx | 7 +- .../components/guests/guest-users.tsx | 15 ++-- .../guests/onboarded-guest-user-list.tsx | 11 +-- .../pages/administrators.tsx | 7 +- .../components/application-role-groups.tsx | 7 +- .../application-role-invited-user-groups.tsx | 12 ++- .../components/assign-group-wizard.tsx | 16 +++- .../inbound-provisioning-configuration.tsx | 13 +-- .../components/add/add-local-claim.tsx | 8 +- .../components/claims-list.tsx | 16 +++- .../edit-mapped-attributes-local-claims.tsx | 16 ++-- .../wizard/local-claim/mapped-attributes.tsx | 9 ++- .../settings/jit-provisioning-settings.tsx | 12 ++- .../administrators-list.tsx | 9 ++- .../administrators-table.tsx | 11 +-- .../invited-administrators-list.tsx | 9 ++- .../invited-administrators-table.tsx | 7 +- .../components/groups/assign-groups.tsx | 79 +++++++++++-------- features/admin.core.v1/configs/app.ts | 5 +- .../constants/user-store-constants.ts | 13 ++- features/admin.core.v1/models/config.ts | 6 +- .../admin.core.v1/store/reducers/config.ts | 3 +- .../configs/userstores.tsx | 8 +- .../utils/user-store-utils.ts | 10 ++- .../admin.groups.v1/components/group-list.tsx | 13 ++- .../components/wizard/create-group-wizard.tsx | 7 +- .../components/wizard/group-basics.tsx | 12 ++- .../constants/group-constants.ts | 6 +- features/admin.groups.v1/pages/groups.tsx | 7 +- .../organization-role-basics.tsx | 13 +-- .../edit-organization-groups.tsx | 20 ++++- .../edit-organization-role-users.tsx | 9 ++- .../constants/organization-constants.ts | 3 +- .../components/edit-role/edit-role-basic.tsx | 13 ++- .../components/edit-role/edit-role-groups.tsx | 25 ++++-- .../components/edit-role/edit-role-users.tsx | 11 ++- .../components/wizard/role-basics.tsx | 22 ++++-- .../constants/role-constants.ts | 3 +- features/admin.roles.v1/pages/role.tsx | 12 ++- .../components/edit-role/edit-role-users.tsx | 20 +++-- .../constants/role-constants.ts | 3 +- .../components/dropdown/tenant-dropdown.tsx | 6 +- .../components/user-change-password.tsx | 12 +-- .../components/user-groups-edit.tsx | 25 ++++-- .../wizard/bulk-import-user-wizard.tsx | 8 +- .../core/src/constants/userstore-constants.ts | 18 +---- modules/core/src/helpers/profile.ts | 39 +++++---- modules/core/src/utils/string-utils.ts | 13 ++- .../src/components/header/header.tsx | 10 ++- 52 files changed, 421 insertions(+), 240 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index c23d84a7c51..2e5bc3b5d8c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2022-2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2022-2025, 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 @@ -72,7 +72,7 @@ const getLicenseHeaderPattern = () => { const LICENSE_HEADER_DEFAULT_PATTERN = [ "*", { - pattern: " Copyright \\(c\\) \\b(2019|202[0-4])(?:-(202[0-4]))?, WSO2 LLC. \\(https://www.wso2.com\\).$", + pattern: " Copyright \\(c\\) \\b(2019|202[0-5])(?:-(202[0-5]))?, WSO2 LLC. \\(https://www.wso2.com\\).$", template: " * Copyright (c) {{year}}, WSO2 LLC. (https://www.wso2.com)." }, " *", 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 41bcb452280..11fd2b7eeee 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 @@ -1787,6 +1787,9 @@ {% endfor %} {% endif %} ], + {% if user_store.properties.DomainName is defined %} + "primaryUserStoreDomainName": "{{ user_store.properties.DomainName }}", + {% endif %} "hiddenUserStores": [ {% if console.ui.hidden_user_stores is defined %} {% for value in console.ui.hidden_user_stores %} diff --git a/features/admin.administrators.v1/components/all-users-list.tsx b/features/admin.administrators.v1/components/all-users-list.tsx index 2f67b34c24e..14d65a3eece 100644 --- a/features/admin.administrators.v1/components/all-users-list.tsx +++ b/features/admin.administrators.v1/components/all-users-list.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2024-2025, 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 @@ -170,6 +170,8 @@ export const AllUsersList: React.FunctionComponent = (props: const [ loading, setLoading ] = useState(false); const authenticatedUser: string = useSelector((state: AppState) => state?.auth?.username); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); /** * Set tenant admin. @@ -196,7 +198,7 @@ export const AllUsersList: React.FunctionComponent = (props: const allowedScopes: string = useSelector((state: AppState) => state?.auth?.allowedScopes); const handleUserEdit = (user: UserBasicInterface) => { - if (resolveUserstore(user.userName) === userstoresConfig.primaryUserstoreName) { + if (resolveUserstore(user.userName, primaryUserStoreDomainName) === userstoresConfig.primaryUserstoreName) { history.push(AdministratorConstants.getPaths().get("CUSTOMER_USER_EDIT_PATH").replace(":id", user.id)); } else { history.push(AdministratorConstants.getPaths().get("COLLABORATOR_USER_EDIT_PATH").replace(":id", user.id)); @@ -289,7 +291,8 @@ export const AllUsersList: React.FunctionComponent = (props: if (user.userName === tenantAdmin) { return "Owner"; } - if (resolveUserstore(user.userName) === userstoresConfig.primaryUserstoreName) { + if (resolveUserstore(user.userName, primaryUserStoreDomainName) + === userstoresConfig.primaryUserstoreName) { return UserAccountTypes.USER; } else { return administratorConfig.adminRoleName; @@ -599,14 +602,16 @@ export const AllUsersList: React.FunctionComponent = (props: attached negative > - { resolveUserstore(deletingUser.userName) === userstoresConfig.primaryUserstoreName + { resolveUserstore(deletingUser.userName, primaryUserStoreDomainName) + === userstoresConfig.primaryUserstoreName ? t("user:deleteUser.confirmationModal.message") : t("extensions:manage.guest.deleteUser.confirmationModal.message") }
{ alert && alertComponent }
- { resolveUserstore(deletingUser.userName) === userstoresConfig.primaryUserstoreName + { resolveUserstore(deletingUser.userName, primaryUserStoreDomainName) + === userstoresConfig.primaryUserstoreName ? ( deletingUser[SCIMConfigs.scim.enterpriseSchema]?.userSourceId ? t("user:deleteJITUser.confirmationModal.content") diff --git a/features/admin.administrators.v1/components/guests/edit-guest-user.tsx b/features/admin.administrators.v1/components/guests/edit-guest-user.tsx index 45abeb7abb3..f0d833eb591 100644 --- a/features/admin.administrators.v1/components/guests/edit-guest-user.tsx +++ b/features/admin.administrators.v1/components/guests/edit-guest-user.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2024-2025, 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 @@ -26,7 +26,6 @@ import { UserRolesList } from "@wso2is/admin.users.v1/components/user-roles-list import { UserSessions } from "@wso2is/admin.users.v1/components/user-sessions"; import { AdminAccountTypes, UserManagementConstants } from "@wso2is/admin.users.v1/constants/user-management-constants"; import { UserManagementUtils } from "@wso2is/admin.users.v1/utils/user-management-utils"; -import { UserstoreConstants } from "@wso2is/core/constants"; import { hasRequiredScopes, isFeatureEnabled } from "@wso2is/core/helpers"; import { AlertInterface, ProfileInfoInterface, SBACInterface } from "@wso2is/core/models"; import { addAlert } from "@wso2is/core/store"; @@ -95,6 +94,8 @@ export const EditGuestUser: FunctionComponent = ( const [ adminUserType, setAdminUserType ] = useState(AdminAccountTypes.EXTERNAL); const authenticatedUserTenanted: string = useSelector((state: AppState) => state?.auth?.username); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); const authenticatedUser: string = useMemo(() => { const authenticatedUserComponents: string[] = authenticatedUserTenanted.split("@"); @@ -120,7 +121,7 @@ export const EditGuestUser: FunctionComponent = ( const userStore: string = user?.userName?.split("/").length > 1 ? user?.userName?.split("/")[ 0 ] - : UserstoreConstants.PRIMARY_USER_STORE; + : primaryUserStoreDomainName; setReadOnlyUserStore(readOnlyUserStores?.includes(userStore?.toString())); diff --git a/features/admin.administrators.v1/components/guests/guest-users.tsx b/features/admin.administrators.v1/components/guests/guest-users.tsx index 264f708881e..8948dbac25d 100644 --- a/features/admin.administrators.v1/components/guests/guest-users.tsx +++ b/features/admin.administrators.v1/components/guests/guest-users.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2024-2025, 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 @@ -24,7 +24,6 @@ import { UserListInterface } from "@wso2is/admin.core.v1"; import { InvitationStatus, UserInviteInterface } from "@wso2is/admin.users.v1/models"; -import { PRIMARY_USERSTORE } from "@wso2is/admin.userstores.v1/constants/user-store-constants"; import { TestableComponentInterface } from "@wso2is/core/models"; import { DocumentationLink, ListLayout, Message, Text, useDocumentation } from "@wso2is/react-components"; import React, { FunctionComponent, ReactElement, useEffect, useState } from "react"; @@ -97,6 +96,8 @@ const GuestUsersPage: FunctionComponent = ( const [ isInvitationStatusOptionChanged, setIsInvitationStatusOptionChanged ] = useState(false); const featureConfig: FeatureConfigInterface = useSelector((state: AppState) => state.config.ui.features); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); /** * Show the description message for the first time. @@ -191,9 +192,9 @@ const GuestUsersPage: FunctionComponent = ( useEffect(() => { if (invitationStatusOption === InvitationStatus.ACCEPTED) { if (searchQuery == undefined || searchQuery == "") { - getUsersList(listItemLimit, listOffset + 1, null, null, PRIMARY_USERSTORE); + getUsersList(listItemLimit, listOffset + 1, null, null, primaryUserStoreDomainName); } else { - getUsersList(listItemLimit, listOffset + 1, searchQuery, null, PRIMARY_USERSTORE); + getUsersList(listItemLimit, listOffset + 1, searchQuery, null, primaryUserStoreDomainName); } } }, [ listOffset, listItemLimit ]); @@ -271,11 +272,11 @@ const GuestUsersPage: FunctionComponent = ( setSearchQuery(query); if (invitationStatusOption === InvitationStatus.ACCEPTED) { if (query === "userName sw ") { - getUsersList(listItemLimit, listOffset, null, null, PRIMARY_USERSTORE); + getUsersList(listItemLimit, listOffset, null, null, primaryUserStoreDomainName); return; } - getUsersList(listItemLimit, listOffset, query, null, PRIMARY_USERSTORE); + getUsersList(listItemLimit, listOffset, query, null, primaryUserStoreDomainName); } }; @@ -457,7 +458,7 @@ const GuestUsersPage: FunctionComponent = ( readOnlyUserStores={ null } featureConfig={ featureConfig } onUserDelete={ () => - getUsersList(listItemLimit, listOffset, null, null, PRIMARY_USERSTORE) + getUsersList(listItemLimit, listOffset, null, null, primaryUserStoreDomainName) } />) } diff --git a/features/admin.administrators.v1/components/guests/onboarded-guest-user-list.tsx b/features/admin.administrators.v1/components/guests/onboarded-guest-user-list.tsx index e6a96a11f99..133c999525f 100644 --- a/features/admin.administrators.v1/components/guests/onboarded-guest-user-list.tsx +++ b/features/admin.administrators.v1/components/guests/onboarded-guest-user-list.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2024-2025, 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 @@ -42,7 +42,6 @@ import { UserListInterface } from "@wso2is/admin.users.v1/models"; import { UserManagementUtils } from "@wso2is/admin.users.v1/utils"; -import { UserstoreConstants } from "@wso2is/core/constants"; import { IdentityAppsApiException } from "@wso2is/core/exceptions"; import { getUserNameWithoutDomain, isFeatureEnabled } from "@wso2is/core/helpers"; import { @@ -196,6 +195,8 @@ export const OnboardedGuestUsersList: React.FunctionComponent state?.auth?.username); const isPrivilegedUser: boolean = useSelector((state: AppState) => state.auth.isPrivilegedUser); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); const saasFeatureStatus : FeatureStatus = useCheckFeatureStatus(FeatureGateConstants.SAAS_FEATURES_IDENTIFIER); @@ -490,7 +491,7 @@ export const OnboardedGuestUsersList: React.FunctionComponent { const userStore: string = user?.userName?.split("/").length > 1 ? user?.userName?.split("/")[0] - : "PRIMARY"; + : primaryUserStoreDomainName; return ( !hasUserUpdatePermissions @@ -507,7 +508,7 @@ export const OnboardedGuestUsersList: React.FunctionComponent { const userStore: string = user?.userName?.split("/").length > 1 ? user?.userName?.split("/")[0] - : "PRIMARY"; + : primaryUserStoreDomainName; return ( !hasUserUpdatePermissions @@ -527,7 +528,7 @@ export const OnboardedGuestUsersList: React.FunctionComponent { const userStore: string = user?.userName?.split("/").length > 1 ? user?.userName?.split("/")[0] - : UserstoreConstants.PRIMARY_USER_STORE; + : primaryUserStoreDomainName; return !isFeatureEnabled(featureConfig?.users, UserManagementConstants.FEATURE_DICTIONARY.get("USER_DELETE")) diff --git a/features/admin.administrators.v1/pages/administrators.tsx b/features/admin.administrators.v1/pages/administrators.tsx index 1b7c1212de0..dec5e735989 100644 --- a/features/admin.administrators.v1/pages/administrators.tsx +++ b/features/admin.administrators.v1/pages/administrators.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2024-2025, 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 @@ -64,7 +64,6 @@ import { UserManagementUtils } from "@wso2is/admin.users.v1/utils"; import { getUserStores } from "@wso2is/admin.userstores.v1/api"; import { CONSUMER_USERSTORE, - PRIMARY_USERSTORE, UserStoreManagementConstants } from "@wso2is/admin.userstores.v1/constants"; import { IdentityAppsError } from "@wso2is/core/errors"; @@ -161,6 +160,8 @@ const CollaboratorsPage: FunctionComponent = ( const authUserTenants: TenantInfo[] = useSelector((state: AppState) => state?.auth?.tenants); const guestUserFeatureConfig: FeatureAccessConfigInterface = useSelector((state: AppState) => state.config.ui.features.guestUser); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); const hasGuestUserCreatePermissions: boolean = useRequiredScopes( guestUserFeatureConfig?.scopes?.create @@ -251,7 +252,7 @@ const CollaboratorsPage: FunctionComponent = ( : searchQuery ), null, - PRIMARY_USERSTORE, + primaryUserStoreDomainName, excludedAttributes, !administratorConfig.enableAdminInvite || invitationStatusOption === InvitationStatus.ACCEPTED ); diff --git a/features/admin.application-roles.v1/components/application-role-groups.tsx b/features/admin.application-roles.v1/components/application-role-groups.tsx index ba1ed2b3416..129e55863d7 100644 --- a/features/admin.application-roles.v1/components/application-role-groups.tsx +++ b/features/admin.application-roles.v1/components/application-role-groups.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-2025, 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 @@ -68,6 +68,9 @@ const ApplicationRoleGroups = (props: ApplicationRoleGroupsProps): ReactElement const { t } = useTranslation(); const dispatch: Dispatch = useDispatch(); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); + const featureConfig: FeatureConfigInterface = useSelector((state: AppState) => state.config.ui.features); const hasApplicationRolesUpdatePermissions: boolean = useRequiredScopes( @@ -326,7 +329,7 @@ const ApplicationRoleGroups = (props: ApplicationRoleGroupsProps): ReactElement id: "type", key: "type", render: (group: ApplicationRoleGroupInterface): ReactNode => { - const grpName: string = resolveUserstore(group.name); + const grpName: string = resolveUserstore(group.name, primaryUserStoreDomainName); if (grpName === CONSUMER_USERSTORE) { return CONSUMER_USERSTORE; diff --git a/features/admin.application-roles.v1/components/application-role-invited-user-groups.tsx b/features/admin.application-roles.v1/components/application-role-invited-user-groups.tsx index 9b4f843677b..cb81c371b74 100644 --- a/features/admin.application-roles.v1/components/application-role-invited-user-groups.tsx +++ b/features/admin.application-roles.v1/components/application-role-invited-user-groups.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-2025, 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 @@ -15,7 +15,8 @@ * specific language governing permissions and limitations * under the License. */ -import { UIConstants } from "@wso2is/admin.core.v1"; + +import { AppState, UIConstants } from "@wso2is/admin.core.v1"; import { CONSUMER_USERSTORE } from "@wso2is/admin.userstores.v1/constants"; import { IdentityAppsApiException } from "@wso2is/core/exceptions"; import { resolveUserstore } from "@wso2is/core/helpers"; @@ -33,7 +34,7 @@ import { } from "@wso2is/react-components"; import React, { ChangeEvent, ReactElement, ReactNode, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { Dispatch } from "redux"; import { Grid, Header, Icon, Input } from "semantic-ui-react"; import { useApplicationRoleInvitedUserGroups, useDescendantsOfSubOrg } from "../api/application-roles"; @@ -57,6 +58,9 @@ const ApplicationRoleInvitedUserGroups = (props: ApplicationRoleGroupsProps): Re const { t } = useTranslation(); const dispatch: Dispatch = useDispatch(); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); + const [ searchQuery, setSearchQuery ] = useState(""); const [ processedGroupsList, setProcessedGroupsList ] = useState([]); const [ initialGroupsList, setInitialGroupsList ] = useState([]); @@ -268,7 +272,7 @@ const ApplicationRoleInvitedUserGroups = (props: ApplicationRoleGroupsProps): Re id: "type", key: "type", render: (group: ApplicationRoleGroupInterface): ReactNode => { - const grpName: string = resolveUserstore(group.name); + const grpName: string = resolveUserstore(group.name, primaryUserStoreDomainName); if (grpName === CONSUMER_USERSTORE) { return CONSUMER_USERSTORE; diff --git a/features/admin.application-roles.v1/components/assign-group-wizard.tsx b/features/admin.application-roles.v1/components/assign-group-wizard.tsx index 12d6cc9ae1e..17127fe9d9e 100644 --- a/features/admin.application-roles.v1/components/assign-group-wizard.tsx +++ b/features/admin.application-roles.v1/components/assign-group-wizard.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-2025, 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 @@ -16,8 +16,11 @@ * under the License. */ +import { AppState } from "@wso2is/admin.core.v1"; import { getGroupList } from "@wso2is/admin.groups.v1/api"; +import { PRIMARY_USERSTORE } from "@wso2is/admin.userstores.v1/constants"; import { IdentifiableComponentInterface, RolesInterface } from "@wso2is/core/models"; +import { StringUtils } from "@wso2is/core/utils"; import { ContentLoader, Heading, @@ -32,6 +35,7 @@ import escapeRegExp from "lodash-es/escapeRegExp"; import isEmpty from "lodash-es/isEmpty"; import React, { FormEvent, ReactElement, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; +import { useSelector } from "react-redux"; import { Grid, Modal } from "semantic-ui-react"; import { ApplicationRoleGroupInterface, ApplicationRoleGroupsAPIResponseInterface } from "../models/application-roles"; @@ -60,6 +64,9 @@ const AssignGroupWizard = (props: AssignGroupProps): ReactElement => { const { t } = useTranslation(); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); + const [ isLoading, setLoading ] = useState(true); const [ groupList, setGroupsList ] = useState([]); const [ tempGroupList, setTempGroupList ] = useState([]); @@ -205,7 +212,12 @@ const AssignGroupWizard = (props: AssignGroupProps): ReactElement => { if (group.length > 1) { return { labelColor: "teal", labelText: group[0].toString() }; } else { - return { labelColor: "olive", labelText: "Primary" }; + return { + labelColor: "olive", + labelText: StringUtils.isEqualCaseInsensitive(primaryUserStoreDomainName, PRIMARY_USERSTORE) + ? t("console:manage.features.users.userstores.userstoreOptions.primary") + : primaryUserStoreDomainName + }; } }; diff --git a/features/admin.applications.v1/components/settings/provisioning/inbound-provisioning-configuration.tsx b/features/admin.applications.v1/components/settings/provisioning/inbound-provisioning-configuration.tsx index 3a87e0d8f50..1b8b7393387 100644 --- a/features/admin.applications.v1/components/settings/provisioning/inbound-provisioning-configuration.tsx +++ b/features/admin.applications.v1/components/settings/provisioning/inbound-provisioning-configuration.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020-2024, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2020-2025, 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 @@ -17,7 +17,7 @@ */ import { useRequiredScopes } from "@wso2is/access-control"; -import { AuthenticatorAccordion, FeatureConfigInterface } from "@wso2is/admin.core.v1"; +import { AppState, AuthenticatorAccordion, FeatureConfigInterface } from "@wso2is/admin.core.v1"; import { useGetCurrentOrganizationType } from "@wso2is/admin.organizations.v1/hooks/use-get-organization-type"; import { getUserStoreList } from "@wso2is/admin.userstores.v1/api"; import { AlertLevels, SBACInterface, TestableComponentInterface } from "@wso2is/core/models"; @@ -26,7 +26,7 @@ import { Heading } from "@wso2is/react-components"; import { AxiosResponse } from "axios"; import React, { FunctionComponent, MouseEvent, ReactElement, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { Dispatch } from "redux"; import { AccordionTitleProps, Divider, Grid } from "semantic-ui-react"; import { updateApplicationConfigurations } from "../../../api/application"; @@ -86,6 +86,9 @@ export const InboundProvisioningConfigurations: FunctionComponent + state?.config?.ui?.primaryUserStoreDomainName); + const [ userStore, setUserStore ] = useState([]); const [ accordionActiveIndexes, setAccordionActiveIndexes ] = useState(defaultActiveIndexes); @@ -155,8 +158,8 @@ export const InboundProvisioningConfigurations: FunctionComponent { diff --git a/features/admin.claims.v1/components/add/add-local-claim.tsx b/features/admin.claims.v1/components/add/add-local-claim.tsx index 339761f3398..4d3b35fafee 100644 --- a/features/admin.claims.v1/components/add/add-local-claim.tsx +++ b/features/admin.claims.v1/components/add/add-local-claim.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2020-2025, 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 @@ -97,6 +97,8 @@ export const AddLocalClaims: FunctionComponent = ( const skipSCIM: MutableRefObject = useRef(false); const hiddenUserStores: string[] = useSelector((state: AppState) => state.config.ui.hiddenUserStores); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); const [ firstStep, setFirstStep ] = useTrigger(); const [ secondStep, setSecondStep ] = useTrigger(); @@ -328,7 +330,7 @@ export const AddLocalClaims: FunctionComponent = ( tempData.attributeMapping = [ { mappedAttribute: tempData.claimURI.split("/").pop(), - userstore: "PRIMARY" + userstore: primaryUserStoreDomainName } ]; handleSubmit(tempData, customMappings, !!skipSCIM?.current); @@ -351,7 +353,7 @@ export const AddLocalClaims: FunctionComponent = ( if (!attributeConfig.localAttributes.createWizard.showPrimaryUserStore) { tempData.attributeMapping.push({ mappedAttribute: tempData.claimURI.split("/").pop(), - userstore: "PRIMARY" + userstore: primaryUserStoreDomainName }); } diff --git a/features/admin.claims.v1/components/claims-list.tsx b/features/admin.claims.v1/components/claims-list.tsx index 7e4b25ab86e..1ced66ff714 100644 --- a/features/admin.claims.v1/components/claims-list.tsx +++ b/features/admin.claims.v1/components/claims-list.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023-2024, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-2025, 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 @@ -15,6 +15,7 @@ * specific language governing permissions and limitations * under the License. */ + import { Show, useRequiredScopes } from "@wso2is/access-control"; import { AppConstants, @@ -27,6 +28,7 @@ import { import { attributeConfig } from "@wso2is/admin.extensions.v1"; import { getProfileSchemas } from "@wso2is/admin.users.v1/api"; import { getUserStores } from "@wso2is/admin.userstores.v1/api/user-stores"; +import { PRIMARY_USERSTORE } from "@wso2is/admin.userstores.v1/constants"; import { UserStoreListItem } from "@wso2is/admin.userstores.v1/models/user-stores"; import { IdentityAppsApiException } from "@wso2is/core/exceptions"; import { @@ -42,6 +44,7 @@ import { TestableComponentInterface } from "@wso2is/core/models"; import { addAlert, setProfileSchemaRequestLoadingStatus, setSCIMSchemas } from "@wso2is/core/store"; +import { StringUtils } from "@wso2is/core/utils"; import { FormValue, useTrigger } from "@wso2is/forms"; import { AnimatedAvatar, @@ -70,7 +73,7 @@ import React,{ useState } from "react"; import { useTranslation } from "react-i18next"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { ThunkDispatch } from "redux-thunk"; import { Header, Icon, ItemHeader, SemanticICONS } from "semantic-ui-react"; import { EditExternalClaim } from "./edit"; @@ -231,6 +234,9 @@ export const ClaimsList: FunctionComponent = ( const dispatch: ThunkDispatch = useDispatch(); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); + const [ submitExternalClaim, setSubmitExternalClaim ] = useTrigger(); //TODO: [Type Fix] Check the usage of following refs and fix the types. @@ -285,8 +291,10 @@ export const ClaimsList: FunctionComponent = ( }); claim?.attributeMapping?.find((attribute: AttributeMapping) => { - return attribute.userstore === "PRIMARY"; - }) ?? userStoresNotSet.push("Primary"); + return attribute.userstore === primaryUserStoreDomainName; + }) ?? userStoresNotSet.push(StringUtils.isEqualCaseInsensitive(primaryUserStoreDomainName, PRIMARY_USERSTORE) + ? t("console:manage.features.users.userstores.userstoreOptions.primary") + : primaryUserStoreDomainName); return userStoresNotSet; }; diff --git a/features/admin.claims.v1/components/edit/local-claim/edit-mapped-attributes-local-claims.tsx b/features/admin.claims.v1/components/edit/local-claim/edit-mapped-attributes-local-claims.tsx index 7bebb575e62..05be4690eb9 100644 --- a/features/admin.claims.v1/components/edit/local-claim/edit-mapped-attributes-local-claims.tsx +++ b/features/admin.claims.v1/components/edit/local-claim/edit-mapped-attributes-local-claims.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023-2024, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-2025, 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 @@ -23,7 +23,6 @@ import Checkbox from "@oxygen-ui/react/Checkbox"; import Typography from "@oxygen-ui/react/Typography"; import { Show, useRequiredScopes } from "@wso2is/access-control"; import { AppState, FeatureConfigInterface } from "@wso2is/admin.core.v1"; -import { PRIMARY_USERSTORE } from "@wso2is/admin.userstores.v1/constants"; import { UserStoreBasicData } from "@wso2is/admin.userstores.v1/models/user-stores"; import { AlertLevels, AttributeMapping, Claim, IdentifiableComponentInterface, Property } from "@wso2is/core/models"; import { addAlert } from "@wso2is/core/store"; @@ -84,6 +83,8 @@ export const EditMappedAttributesLocalClaims: FunctionComponent state.config.ui.features); const hiddenUserStores: string[] = useSelector((state: AppState) => state?.config?.ui?.hiddenUserStores); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); const isReadOnly: boolean = !useRequiredScopes( featureConfig?.attributeDialects?.scopes?.update @@ -107,11 +108,11 @@ export const EditMappedAttributesLocalClaims: FunctionComponent - attribute.userstore.toLowerCase() === PRIMARY_USERSTORE.toLowerCase() + attribute.userstore.toLowerCase() === primaryUserStoreDomainName.toLowerCase() )?.mappedAttribute; } @@ -155,7 +156,7 @@ export const EditMappedAttributesLocalClaims: FunctionComponent store.toUpperCase()) ?? []) ]; @@ -218,7 +219,8 @@ export const EditMappedAttributesLocalClaims: FunctionComponent { userStores.map((store: UserStoreBasicData, index: number) => { - if (store.enabled || store.id.toUpperCase() === PRIMARY_USERSTORE.toUpperCase()) { + if (store.enabled || store.id.toUpperCase() + === primaryUserStoreDomainName.toUpperCase()) { return ( const [ userStore, setUserStore ] = useState([]); const hiddenUserStores: string[] = useSelector((state: AppState) => state.config.ui.hiddenUserStores); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); const { t } = useTranslation(); @@ -75,8 +78,8 @@ export const MappedAttributes: FunctionComponent userstore.push({ description: "", enabled: true, - id: "PRIMARY", - name: "PRIMARY", + id: primaryUserStoreDomainName, + name: primaryUserStoreDomainName, self: "" }); } diff --git a/features/admin.connections.v1/components/edit/settings/jit-provisioning-settings.tsx b/features/admin.connections.v1/components/edit/settings/jit-provisioning-settings.tsx index 7f2937c543b..6fff686c8c4 100644 --- a/features/admin.connections.v1/components/edit/settings/jit-provisioning-settings.tsx +++ b/features/admin.connections.v1/components/edit/settings/jit-provisioning-settings.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-2025, 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 @@ -17,6 +17,7 @@ */ import { SimpleUserStoreListItemInterface } from "@wso2is/admin.applications.v1/models/application"; +import { AppState } from "@wso2is/admin.core.v1"; import { useGetCurrentOrganizationType } from "@wso2is/admin.organizations.v1/hooks/use-get-organization-type"; import { getUserStoreList } from "@wso2is/admin.userstores.v1/api"; import { AlertLevels, TestableComponentInterface } from "@wso2is/core/models"; @@ -25,7 +26,7 @@ import { EmphasizedSegment } from "@wso2is/react-components"; import { AxiosResponse } from "axios"; import React, { FunctionComponent, ReactElement, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { Dispatch } from "redux"; import { updateJITProvisioningConfigs } from "../../../api/connections"; import { JITProvisioningResponseInterface } from "../../../models/connection"; @@ -80,6 +81,9 @@ export const JITProvisioningSettings: FunctionComponent + state?.config?.ui?.primaryUserStoreDomainName); + const dispatch: Dispatch = useDispatch(); const { isSuperOrganization, isFirstLevelOrganization } = useGetCurrentOrganizationType(); const { t } = useTranslation(); @@ -119,8 +123,8 @@ export const JITProvisioningSettings: FunctionComponent = ( const consoleSettingsFeatureConfig: FeatureAccessConfigInterface = useSelector( (state: AppState) => state.config.ui.features.consoleSettings ); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); const isPrivilegedUsersInConsoleSettingsEnabled: boolean = !consoleSettingsFeatureConfig?.disabledFeatures?.includes( @@ -178,7 +179,7 @@ const AdministratorsList: FunctionComponent = ( useEffect(() => { setSelectedUserStore( isPrivilegedUsersInConsoleSettingsEnabled && selectedAdministratorGroup === "administrators" - ? PRIMARY_USERSTORE + ? primaryUserStoreDomainName : userstoresConfig?.primaryUserstoreName ); },[ isPrivilegedUsersInConsoleSettingsEnabled, selectedAdministratorGroup ]); @@ -428,7 +429,7 @@ const AdministratorsList: FunctionComponent = ( options={ availableUserStores } onChange={ handleSelectedUserStoreChange } value={ selectedUserStore } - defaultValue={ PRIMARY_USERSTORE } + defaultValue={ primaryUserStoreDomainName } /> ); } diff --git a/features/admin.console-settings.v1/components/console-administrators/administrators-list/administrators-table.tsx b/features/admin.console-settings.v1/components/console-administrators/administrators-list/administrators-table.tsx index f3e02bfe594..479512da6bd 100644 --- a/features/admin.console-settings.v1/components/console-administrators/administrators-list/administrators-table.tsx +++ b/features/admin.console-settings.v1/components/console-administrators/administrators-list/administrators-table.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-2025, 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 @@ -31,7 +31,6 @@ import { useServerConfigs } from "@wso2is/admin.server-configurations.v1"; import { UserManagementConstants } from "@wso2is/admin.users.v1/constants"; import { UserListInterface } from "@wso2is/admin.users.v1/models"; import { UserManagementUtils } from "@wso2is/admin.users.v1/utils"; -import { UserstoreConstants } from "@wso2is/core/constants"; import { getUserNameWithoutDomain, hasRequiredScopes, isFeatureEnabled } from "@wso2is/core/helpers"; import { FeatureAccessConfigInterface, @@ -173,6 +172,8 @@ const AdministratorsTable: React.FunctionComponent state?.auth?.providedUsername); const allowedScopes: string = useSelector((state: AppState) => state?.auth?.allowedScopes); const isPrivilegedUser: boolean = useSelector((state: AppState) => state.auth.isPrivilegedUser); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); /** * Resolves data table columns. @@ -338,7 +339,7 @@ const AdministratorsTable: React.FunctionComponent { const userStore: string = user?.userName?.split("/").length > 1 ? user?.userName?.split("/")[0] - : "PRIMARY"; + : primaryUserStoreDomainName; return ( !hasRequiredScopes(featureConfig, featureConfig?.scopes?.update, allowedScopes) @@ -355,7 +356,7 @@ const AdministratorsTable: React.FunctionComponent { const userStore: string = user?.userName?.split("/").length > 1 ? user?.userName?.split("/")[0] - : "PRIMARY"; + : primaryUserStoreDomainName; return ( !hasRequiredScopes(featureConfig, featureConfig?.scopes?.update, allowedScopes) @@ -374,7 +375,7 @@ const AdministratorsTable: React.FunctionComponent { const userStore: string = user?.userName?.split("/").length > 1 ? user?.userName?.split("/")[0] - : UserstoreConstants.PRIMARY_USER_STORE; + : primaryUserStoreDomainName; return !isFeatureEnabled(featureConfig, UserManagementConstants.FEATURE_DICTIONARY.get("USER_DELETE")) diff --git a/features/admin.console-settings.v1/components/console-administrators/invited-administrators/invited-administrators-list.tsx b/features/admin.console-settings.v1/components/console-administrators/invited-administrators/invited-administrators-list.tsx index 61d1ec78598..979be3391a1 100644 --- a/features/admin.console-settings.v1/components/console-administrators/invited-administrators/invited-administrators-list.tsx +++ b/features/admin.console-settings.v1/components/console-administrators/invited-administrators/invited-administrators-list.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023-2024, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-2025, 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 @@ -28,7 +28,6 @@ import { useGetCurrentOrganizationType } from "@wso2is/admin.organizations.v1/ho import { deleteParentOrgInvite } from "@wso2is/admin.users.v1/components/guests/api/invite"; import { UserManagementConstants } from "@wso2is/admin.users.v1/constants"; import { UserInviteInterface } from "@wso2is/admin.users.v1/models"; -import { PRIMARY_USERSTORE } from "@wso2is/admin.userstores.v1/constants"; import { UserStoreDropdownItem } from "@wso2is/admin.userstores.v1/models"; import { AlertLevels, @@ -98,6 +97,8 @@ const InvitedAdministratorsList: React.FunctionComponent state.config.ui.features); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); const [ listOffset, setListOffset ] = useState(0); const [ listItemLimit, setListItemLimit ] = useState(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT); @@ -105,7 +106,7 @@ const InvitedAdministratorsList: React.FunctionComponent(""); const [ showInviteNewAdministratorModal, setShowInviteNewAdministratorModal ] = useState(false); const [ loading, setLoading ] = useState(false); - const [ selectedUserStore, setSelectedUserStore ] = useState(PRIMARY_USERSTORE.toLocaleLowerCase()); + const [ selectedUserStore, setSelectedUserStore ] = useState(primaryUserStoreDomainName); const { invitedAdministrators, @@ -248,7 +249,7 @@ const InvitedAdministratorsList: React.FunctionComponent) : null } topActionPanelExtension={ ( diff --git a/features/admin.console-settings.v1/components/console-administrators/invited-administrators/invited-administrators-table.tsx b/features/admin.console-settings.v1/components/console-administrators/invited-administrators/invited-administrators-table.tsx index 72012da9ea8..276f62f0946 100644 --- a/features/admin.console-settings.v1/components/console-administrators/invited-administrators/invited-administrators-table.tsx +++ b/features/admin.console-settings.v1/components/console-administrators/invited-administrators/invited-administrators-table.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-2025, 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 @@ -26,7 +26,6 @@ import { import { useServerConfigs } from "@wso2is/admin.server-configurations.v1"; import { UserInviteInterface } from "@wso2is/admin.users.v1/components/guests/models/invite"; import { UserManagementConstants } from "@wso2is/admin.users.v1/constants"; -import { UserstoreConstants } from "@wso2is/core/constants"; import { getUserNameWithoutDomain, hasRequiredScopes, isFeatureEnabled } from "@wso2is/core/helpers"; import { FeatureAccessConfigInterface, @@ -161,6 +160,8 @@ const InvitedAdministratorsTable: React.FunctionComponent state?.auth?.username); const allowedScopes: string = useSelector((state: AppState) => state?.auth?.allowedScopes); const isPrivilegedUser: boolean = useSelector((state: AppState) => state.auth.isPrivilegedUser); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); /** * Resolves data table columns. @@ -248,7 +249,7 @@ const InvitedAdministratorsTable: React.FunctionComponent { const userStore: string = user?.username?.split("/").length > 1 ? user?.username?.split("/")[0] - : UserstoreConstants.PRIMARY_USER_STORE; + : primaryUserStoreDomainName; return !isFeatureEnabled(featureConfig, UserManagementConstants.FEATURE_DICTIONARY.get("USER_DELETE")) diff --git a/features/admin.core.v1/components/groups/assign-groups.tsx b/features/admin.core.v1/components/groups/assign-groups.tsx index 418cf1b7ef7..404d22d443d 100644 --- a/features/admin.core.v1/components/groups/assign-groups.tsx +++ b/features/admin.core.v1/components/groups/assign-groups.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. + * Copyright (c) 2020-2025, 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 @@ -16,13 +16,18 @@ * under the License. */ +import { GroupsInterface } from "@wso2is/admin.groups.v1"; +import { PRIMARY_USERSTORE } from "@wso2is/admin.userstores.v1/constants"; import { RolesInterface } from "@wso2is/core/models"; +import { StringUtils } from "@wso2is/core/utils"; import { Forms } from "@wso2is/forms"; import { TransferComponent, TransferList, TransferListItem } from "@wso2is/react-components"; import escapeRegExp from "lodash-es/escapeRegExp"; import isEmpty from "lodash-es/isEmpty"; -import React, { FunctionComponent, ReactElement, useEffect, useState } from "react"; +import React, { FormEvent, FunctionComponent, ReactElement, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; +import { useSelector } from "react-redux"; +import { AppState } from "../../store"; /** * Proptypes for the assign group component. @@ -40,7 +45,7 @@ interface AssignGroupsPropsInterface { /** * Assign Group component. * - * @return {ReactElement} + * @returns ReactElement */ export const AssignGroups: FunctionComponent = ( props: AssignGroupsPropsInterface): ReactElement => { @@ -57,6 +62,9 @@ export const AssignGroups: FunctionComponent = ( const { t } = useTranslation(); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); + const [ checkedUnassignedListItems, setCheckedUnassignedListItems ] = useState([]); const [ checkedAssignedListItems, setCheckedAssignedListItems ] = useState([]); const [ isSelectUnassignedGroupsAllRolesChecked, setIsSelectUnassignedAllGroupsChecked ] = useState(false); @@ -86,14 +94,14 @@ export const AssignGroups: FunctionComponent = ( * @param e - Click event. * @param value - Input value of the field */ - const handleUnselectedListSearch = (e, { value }) => { - let isMatch = false; - const filteredGroupList = []; + const handleUnselectedListSearch = (e: FormEvent, { value }: { value: string }) => { + let isMatch: boolean = false; + const filteredGroupList: GroupsInterface[] = []; if (!isEmpty(value)) { - const re = new RegExp(escapeRegExp(value), "i"); + const re: RegExp = new RegExp(escapeRegExp(value), "i"); - initialValues.groupList && initialValues.groupList.map((group) => { + initialValues.groupList && initialValues.groupList.map((group: GroupsInterface) => { isMatch = re.test(group.displayName); if (isMatch) { filteredGroupList.push(group); @@ -105,14 +113,14 @@ export const AssignGroups: FunctionComponent = ( } }; - const handleSelectedListSearch = (e, { value }) => { - let isMatch = false; - const filteredGroupList = []; + const handleSelectedListSearch = (e: FormEvent, { value }: { value: string }) => { + let isMatch: boolean = false; + const filteredGroupList: GroupsInterface[] = []; if (!isEmpty(value)) { - const re = new RegExp(escapeRegExp(value), "i"); + const re: RegExp = new RegExp(escapeRegExp(value), "i"); - initialValues.tempGroupList && initialValues.tempGroupList.map((group) => { + initialValues.tempGroupList && initialValues.tempGroupList.map((group: GroupsInterface) => { isMatch = re.test(group.displayName); if (isMatch) { filteredGroupList.push(group); @@ -143,10 +151,10 @@ export const AssignGroups: FunctionComponent = ( * roles list to the assigned roles list. */ const addGroups = () => { - const addedGroups = [ ...initialValues?.tempGroupList ]; + const addedGroups: GroupsInterface[] = [ ...initialValues?.tempGroupList ]; if (checkedUnassignedListItems?.length > 0) { - checkedUnassignedListItems.map((group) => { + checkedUnassignedListItems.map((group: GroupsInterface) => { if (!(initialValues?.tempGroupList?.includes(group))) { addedGroups.push(group); } @@ -155,8 +163,9 @@ export const AssignGroups: FunctionComponent = ( handleTempListChange(addedGroups); handleInitialTempListChange(addedGroups); - handleGroupListChange(initialValues?.groupList.filter(x => !addedGroups?.includes(x))); - handleInitialGroupListChange(initialValues?.groupList.filter(x => !addedGroups?.includes(x))); + handleGroupListChange(initialValues?.groupList.filter((x: GroupsInterface) => !addedGroups?.includes(x))); + handleInitialGroupListChange(initialValues?.groupList.filter( + (x: GroupsInterface) => !addedGroups?.includes(x))); setIsSelectUnassignedAllGroupsChecked(false); }; @@ -165,10 +174,10 @@ export const AssignGroups: FunctionComponent = ( * roles list to the initial role list. */ const removeGroups = () => { - const removedGroups = [ ...initialValues?.groupList ]; + const removedGroups: GroupsInterface[] = [ ...initialValues?.groupList ]; if (checkedAssignedListItems?.length > 0) { - checkedAssignedListItems.map((group) => { + checkedAssignedListItems.map((group: GroupsInterface) => { if (!(initialValues?.groupList?.includes(group))) { removedGroups.push(group); } @@ -176,8 +185,9 @@ export const AssignGroups: FunctionComponent = ( } handleGroupListChange(removedGroups); handleInitialGroupListChange(removedGroups); - handleTempListChange(initialValues?.tempGroupList?.filter(x => !removedGroups.includes(x))); - handleInitialTempListChange(initialValues?.tempGroupList?.filter(x => !removedGroups.includes(x))); + handleTempListChange(initialValues?.tempGroupList?.filter((x: GroupsInterface) => !removedGroups.includes(x))); + handleInitialTempListChange(initialValues?.tempGroupList?.filter( + (x: GroupsInterface) => !removedGroups.includes(x))); setCheckedUnassignedListItems([]); setIsSelectAssignedAllGroupsChecked(false); }; @@ -186,8 +196,8 @@ export const AssignGroups: FunctionComponent = ( * The following method handles the onChange event of the * checkbox field of an unassigned item. */ - const handleUnassignedItemCheckboxChange = (group) => { - const checkedGroups = [ ...checkedUnassignedListItems ]; + const handleUnassignedItemCheckboxChange = (group: GroupsInterface) => { + const checkedGroups: GroupsInterface[] = [ ...checkedUnassignedListItems ]; if (checkedGroups?.includes(group)) { checkedGroups.splice(checkedGroups.indexOf(group), 1); @@ -202,8 +212,8 @@ export const AssignGroups: FunctionComponent = ( * The following method handles the onChange event of the * checkbox field of an assigned item. */ - const handleAssignedItemCheckboxChange = (group) => { - const checkedGroups = [ ...checkedAssignedListItems ]; + const handleAssignedItemCheckboxChange = (group: GroupsInterface) => { + const checkedGroups: GroupsInterface[] = [ ...checkedAssignedListItems ]; if (checkedGroups?.includes(group)) { checkedGroups.splice(checkedGroups.indexOf(group), 1); @@ -217,15 +227,20 @@ export const AssignGroups: FunctionComponent = ( /** * The following method handles creating a label for the list item. * - * @param groupName: string + * @param groupName - string */ const createGroupLabel = (groupName: string): any => { - const group = groupName.split("/"); + const group: string[] = groupName.split("/"); if (group.length > 1) { return { labelColor: "teal", labelText: group[0].toString() }; } else { - return { labelColor: "olive", labelText: "Primary" }; + return { + labelColor: "olive", + labelText: StringUtils.isEqualCaseInsensitive(primaryUserStoreDomainName, PRIMARY_USERSTORE) + ? t("console:manage.features.users.userstores.userstoreOptions.primary") + : primaryUserStoreDomainName + }; } }; @@ -261,8 +276,8 @@ export const AssignGroups: FunctionComponent = ( + "emptyPlaceholders.default") } > { - initialValues?.groupList?.map((group, index)=> { - const groupName = group?.displayName?.split("/"); + initialValues?.groupList?.map((group: GroupsInterface, index: number)=> { + const groupName: string[] = group?.displayName?.split("/"); return ( = ( + "emptyPlaceholders.default") } > { - initialValues?.tempGroupList?.map((group, index)=> { - const groupName = group?.displayName?.split("/"); + initialValues?.tempGroupList?.map((group: GroupsInterface, index: number)=> { + const groupName: string[] = group?.displayName?.split("/"); return ( true, primaryUserstoreId: "primary", - primaryUserstoreName: "PRIMARY", + primaryUserstoreName: primaryUserStoreDomainName, shouldShowUserstore: () => { return false; }, diff --git a/features/admin.extensions.v1/utils/user-store-utils.ts b/features/admin.extensions.v1/utils/user-store-utils.ts index 95c995d59cd..6c389b8e461 100644 --- a/features/admin.extensions.v1/utils/user-store-utils.ts +++ b/features/admin.extensions.v1/utils/user-store-utils.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-2025, 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 @@ -19,6 +19,7 @@ import { getAUserStore } from "@wso2is/admin.core.v1/api"; import { SharedUserStoreConstants } from "@wso2is/admin.core.v1/constants"; import { getUserStoreList } from "@wso2is/admin.userstores.v1/api"; +import { PRIMARY_USERSTORE } from "@wso2is/admin.userstores.v1/constants"; import { UserStoreListItem, UserStorePostData, UserStoreProperty } from "@wso2is/admin.userstores.v1/models"; import { AxiosResponse } from "axios"; @@ -27,8 +28,6 @@ import { AxiosResponse } from "axios"; */ export class UserStoreUtils { - private static primaryUserStore:string = "PRIMARY"; - /** * Private constructor to avoid object instantiation from outside * the class. @@ -74,7 +73,10 @@ export class UserStoreUtils { const ids: string[] = await UserStoreUtils.getUserStoreIds(userstores) as string[]; const readOnlyUserStores: string[] = []; - readOnlyUserStores.push(UserStoreUtils.primaryUserStore); + const primaryUserStoreDomainName: string = window[ "AppUtils" ] + ?.getConfig()?.ui?.primaryUserStoreDomainName?.toUpperCase() ?? PRIMARY_USERSTORE; + + readOnlyUserStores.push(primaryUserStoreDomainName); ids.forEach((id: string) => { getAUserStore(id) diff --git a/features/admin.groups.v1/components/group-list.tsx b/features/admin.groups.v1/components/group-list.tsx index e56c3b77a5d..e4fcc6b8096 100644 --- a/features/admin.groups.v1/components/group-list.tsx +++ b/features/admin.groups.v1/components/group-list.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020-2024, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2020-2025, 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 @@ -19,14 +19,17 @@ import { Show, useRequiredScopes } from "@wso2is/access-control"; import { AppConstants, + AppState, FeatureConfigInterface, UIConstants, getEmptyPlaceholderIllustrations, history } from "@wso2is/admin.core.v1"; import { userstoresConfig } from "@wso2is/admin.extensions.v1"; +import { PRIMARY_USERSTORE } from "@wso2is/admin.userstores.v1/constants"; import { isFeatureEnabled } from "@wso2is/core/helpers"; import { LoadableComponentInterface, SBACInterface, TestableComponentInterface } from "@wso2is/core/models"; +import { StringUtils } from "@wso2is/core/utils"; import { AnimatedAvatar, AppAvatar, @@ -41,6 +44,7 @@ import { import moment, { Moment } from "moment"; import React, { ReactElement, ReactNode, SyntheticEvent, useState } from "react"; import { useTranslation } from "react-i18next"; +import { useSelector } from "react-redux"; import { Header, Icon, Label, SemanticICONS } from "semantic-ui-react"; import { GroupConstants } from "../constants"; import { GroupsInterface } from "../models"; @@ -142,6 +146,9 @@ export const GroupList: React.FunctionComponent = (props: GroupL const { t } = useTranslation(); + const primaryUserStoreDomainName: string = useSelector((state: AppState) => + state?.config?.ui?.primaryUserStoreDomainName); + const [ showGroupDeleteConfirmation, setShowDeleteConfirmationModal ] = useState(false); const [ currentDeletedGroup, setCurrentDeletedGroup ] = useState(); @@ -178,7 +185,9 @@ export const GroupList: React.FunctionComponent = (props: GroupL <>