/** * Copyright (c) 2021-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 * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import { getUserNameWithoutDomain } from "@thiva/core/helpers"; import { TestableComponentInterface } from "@thiva/core/models"; import { ContentLoader, Heading, Hint, TransferComponent, TransferList, TransferListItem } from "@thiva/react-components"; import escapeRegExp from "lodash-es/escapeRegExp"; import isEmpty from "lodash-es/isEmpty"; import React, { Dispatch, FormEvent, FunctionComponent, ReactElement, SetStateAction, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { Header, Segment } from "semantic-ui-react"; import { GroupBasics } from "./group-basics"; import { UIConstants, UserBasicInterface, UserListInterface, getUsersList } from "@thiva/admin.core.v1"; import { GroupsMemberInterface } from "@thiva/admin.groups.v1/models"; import { UserManagementUtils } from "@thiva/admin.users.v1/utils"; import { SCIMConfigs } from "../../../configs/scim"; /** * Proptypes for the application consents list component. */ interface AddGroupUserProps extends TestableComponentInterface { triggerSubmit?: boolean; onSubmit?: ({ basic, users }: { basic: any; users: UserBasicInterface[]; }) => void; assignedUsers?: GroupsMemberInterface[]; isEdit: boolean; userStore?: string; initialValues?: { basic: any; users: UserBasicInterface[]; }; onUserFetchRequestFinish?: () => void; } export const AddGroupUsers: FunctionComponent = (props: AddGroupUserProps): ReactElement => { const { triggerSubmit, onSubmit, assignedUsers, initialValues, userStore, onUserFetchRequestFinish, [ "data-testid" ]: testId } = props; const { t } = useTranslation(); const [ usersList, setUsersList ] = useState([]); const [ initialUserList, setInitialUserList ] = useState([]); const [ listItemLimit, setListItemLimit ] = useState(0); const [ userListMetaContent, setUserListMetaContent ] = useState(undefined); const [ listOffset ] = useState(0); const [ isUsersFetchRequestLoading, setIsUsersFetchRequestLoading ] = useState(true); const [ isSelectAllAssignedUsers ] = useState(false); const [ checkedAssignedListItems, setCheckedAssignedListItems ] = useState([]); useEffect(() => { if (isSelectAllAssignedUsers) { setCheckedAssignedListItems(usersList); } else { setCheckedAssignedListItems([]); } }, [ isSelectAllAssignedUsers ]); // Commented when the select all option for users was removed. // Uncomment if select all option is reintroduced. // /** // * Select all assigned users // */ // const selectAllAssignedList = () => { // setIsSelectAllAssignedUsers(!isSelectAllAssignedUsers); // }; const getList = (limit: number, offset: number, filter: string, attribute: string, userStore: string) => { setIsUsersFetchRequestLoading(true); getUsersList(limit, offset, filter, null, userStore) .then((response: UserListInterface) => { // Exclude JIT users. const responseUsers: UserBasicInterface[] = response?.Resources?.filter( (user: UserBasicInterface) => !user[ SCIMConfigs.scim.enterpriseSchema ]?.userSourceId); if (responseUsers) { responseUsers.sort((userObject: UserBasicInterface, comparedUserObject: UserBasicInterface) => userObject.name?.givenName?.localeCompare(comparedUserObject.name?.givenName) ); setUsersList(responseUsers); setInitialUserList(responseUsers); } if (assignedUsers && assignedUsers.length !== 0) { const selectedUserList: UserBasicInterface[] = []; if (responseUsers && responseUsers instanceof Array) { responseUsers.slice().reverse().forEach((user: UserBasicInterface) => { assignedUsers.forEach((assignedUser: GroupsMemberInterface) => { if (user.id === assignedUser.value) { selectedUserList.push(user); responseUsers.splice(responseUsers.indexOf(user), 1); } }); }); selectedUserList.sort( (userObject: UserBasicInterface, comparedUserObject: UserBasicInterface) => userObject.name?.givenName?.localeCompare(comparedUserObject.name?.givenName) ); } } if (initialValues && initialValues.users && initialValues.users instanceof Array) { const selectedUserList: UserBasicInterface[] = []; if (responseUsers && responseUsers instanceof Array) { responseUsers.forEach((user: UserBasicInterface) => { initialValues.users.forEach((assignedUser: UserBasicInterface) => { if (user.id === assignedUser.id) { selectedUserList.push(user); } }); }); selectedUserList.sort( (userObject: UserBasicInterface, comparedUserObject: UserBasicInterface) => userObject.name?.givenName?.localeCompare(comparedUserObject.name?.givenName) ); setUsersList(responseUsers.filter(function (user: UserBasicInterface) { return selectedUserList.indexOf(user) == -1; })); } } }) .finally(() => { setIsUsersFetchRequestLoading(false); onUserFetchRequestFinish(); }); }; useEffect(() => { setListItemLimit(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT); setUserListMetaContent(new Map([ [ "name", "name" ], [ "emails", "emails" ], [ "name", "name" ], [ "userName", "userName" ], [ "id", "" ], [ "profileUrl", "profileUrl" ], [ "meta.lastModified", "meta.lastModified" ], [ "meta.created", "" ] ])); }, []); /** * The following method accepts a Map and returns the values as a string. * * @param attributeMap - IterableIterator * @returns attribute string */ const generateAttributesString = (attributeMap: IterableIterator) => { const attArray: string[] = []; const iterator1: IterableIterator = attributeMap[ Symbol.iterator ](); for (const attribute of iterator1) { if (attribute !== "") { attArray.push(attribute); } } return attArray.toString(); }; useEffect(() => { if (userListMetaContent) { const attributes: string = generateAttributesString(userListMetaContent.values()); getList(listItemLimit, listOffset, null, attributes, userStore); } }, [ listOffset, listItemLimit ]); const handleSearchFieldChange = (e: FormEvent, query: string, list: UserBasicInterface[], stateAction: Dispatch>) => { let isMatch: boolean = false; const filteredRoleList: UserBasicInterface[] = []; if (!isEmpty(query)) { const regExp: RegExp = new RegExp(escapeRegExp(query), "i"); list && list.map((user: UserBasicInterface) => { isMatch = regExp.test(user.userName) || (user.name && regExp.test(user.name.givenName)) || (user.name && regExp.test(user.name.familyName)); if (isMatch) { filteredRoleList.push(user); } }); stateAction(filteredRoleList); return; } stateAction(list); return; }; const handleAssignedItemCheckboxChange = (role: any) => { const checkedGroups: any = [ ...checkedAssignedListItems ]; if (checkedGroups.includes(role)) { checkedGroups.splice(checkedGroups.indexOf(role), 1); setCheckedAssignedListItems(checkedGroups); } else { checkedGroups.push(role); setCheckedAssignedListItems(checkedGroups); } }; const resolveListItemElement = (listItemValue: string) => { return (
{ listItemValue }
); }; return ( <> { onSubmit({ basic: values, users: checkedAssignedListItems }); } } /> { isUsersFetchRequestLoading ? : initialUserList?.length > 0 && ( <> Add Users { t("roles:addRoleWizard.users.assignUserModal.hint") } , { value }: { value: string; }) => { handleSearchFieldChange(e, value, initialUserList, setUsersList); } } data-testid={ `${ testId }-transfer-component` } > { usersList?.map((user: UserBasicInterface, index: number) => { const header: string = getUserNameWithoutDomain(user?.userName); const subHeader: string = UserManagementUtils.resolveUserListSubheader(user); return ( handleAssignedItemCheckboxChange(user) } key={ index } listItem={ { listItemElement: resolveListItemElement(header), listItemValue: header } } listItemId={ user.id } listItemIndex={ index } isItemChecked={ checkedAssignedListItems.includes(user) } showSecondaryActions={ false } showListSubItem={ true } listSubItem={ header !== subHeader && (
{ subHeader }
) } data-testid={ `${ testId }-unselected-transfer-list-item-${ index }` } /> ); } ) }
) } ); };