Skip to content

Commit

Permalink
#16521: fix issue in userProfilePage for roles. teams and displayName (
Browse files Browse the repository at this point in the history
…#16527)

* fix update on roles and backlink them in user profile page

* fix teams, displayName and profile pic issue

* sonar fix

* fix cypress issue

* minor changes
  • Loading branch information
Ashish8689 committed Jun 6, 2024
1 parent 8c2a556 commit 98945cb
Show file tree
Hide file tree
Showing 18 changed files with 545 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,9 @@ export const editTeams = (teamName: string) => {
cy.get('[data-testid="inline-save-btn"]').click({ timeout: 10000 });
verifyResponseStatusCode('@updateTeams', 200);

cy.get('.ant-collapse-expand-icon > .anticon > svg').click();
cy.get('.page-layout-v1-vertical-scroll').scrollTo(0, 0);
cy.get(`[data-testid="${teamName}"]`).should('be.visible');
cy.get(`[data-testid="${teamName}-link"]`)
.scrollIntoView()
.should('be.visible');
};

export const handleUserUpdateDetails = (
Expand Down Expand Up @@ -284,8 +284,7 @@ export const handleAdminUpdateDetails = (
editDisplayName(editedUserName);

// edit teams
cy.get('.ant-collapse-expand-icon > .anticon > svg').scrollIntoView();
cy.get('.ant-collapse-expand-icon > .anticon > svg').click();
cy.get('.ant-collapse-expand-icon > .anticon > svg').scrollIntoView().click();
editTeams(teamName);

// edit description
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,8 @@ const Users = ({ userData, queryFilters, updateUserDetails }: Props) => {
<Chip
showNoDataPlaceholder
data={userData.personas ?? []}
icon={<PersonaIcon height={14} />}
entityType={EntityType.PERSONA}
icon={<PersonaIcon height={20} />}
noDataPlaceholder={t('message.no-persona-assigned')}
/>
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,17 @@ const UserProfileDetails = ({
setIsDisplayNameEdit(false);
}, [userData.displayName, displayName, updateUserDetails]);

const handleCloseEditDisplayName = useCallback(() => {
setDisplayName(userData.displayName);
setIsDisplayNameEdit(false);
}, [userData.displayName]);

const displayNameRenderComponent = useMemo(
() =>
isDisplayNameEdit && hasEditPermission ? (
isDisplayNameEdit ? (
<InlineEdit
isLoading={isLoading}
onCancel={() => setIsDisplayNameEdit(false)}
onCancel={handleCloseEditDisplayName}
onSave={handleDisplayNameSave}>
<Input
className="w-full"
Expand Down Expand Up @@ -173,6 +178,7 @@ const UserProfileDetails = ({
getEntityName,
onDisplayNameChange,
handleDisplayNameSave,
handleCloseEditDisplayName,
]
);

Expand Down Expand Up @@ -286,6 +292,7 @@ const UserProfileDetails = ({
<Chip
showNoDataPlaceholder
data={defaultPersona ? [defaultPersona] : []}
entityType={EntityType.PERSONA}
noDataPlaceholder={NO_DATA_PLACEHOLDER}
/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,16 @@ jest.mock('../UserProfileImage/UserProfileImage.component', () => {
});

jest.mock('../../../../common/InlineEdit/InlineEdit.component', () => {
return jest.fn().mockImplementation(({ onSave, children }) => (
return jest.fn().mockImplementation(({ onSave, onCancel, children }) => (
<div data-testid="inline-edit">
<span>InlineEdit</span>
{children}
<button data-testid="display-name-save-button" onClick={onSave}>
DisplayNameButton
</button>
<button data-testid="display-name-cancel-button" onClick={onCancel}>
DisplayNameCancelButton
</button>
</div>
));
});
Expand Down Expand Up @@ -224,6 +227,28 @@ describe('Test User Profile Details Component', () => {
expect(screen.getByText('InlineEdit')).toBeInTheDocument();
});

it('should not render changed displayName in input if not saved', async () => {
render(<UserProfileDetails {...mockPropsData} />, {
wrapper: MemoryRouter,
});

fireEvent.click(screen.getByTestId('edit-displayName'));

act(() => {
fireEvent.change(screen.getByTestId('displayName'), {
target: { value: 'data-test' },
});
});

act(() => {
fireEvent.click(screen.getByTestId('display-name-cancel-button'));
});

fireEvent.click(screen.getByTestId('edit-displayName'));

expect(screen.getByTestId('displayName')).toHaveValue('');
});

it('should call updateUserDetails on click of DisplayNameButton', async () => {
render(<UserProfileDetails {...mockPropsData} />, {
wrapper: MemoryRouter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import { Image } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import { getEntityName } from '../../../../../utils/EntityUtils';
import {
getImageWithResolutionAndFallback,
ImageQuality,
Expand Down Expand Up @@ -50,7 +51,7 @@ const UserProfileImage = ({ userData }: UserProfileImageProps) => {
/>
) : (
<ProfilePicture
displayName={userData?.displayName ?? userData.name}
displayName={getEntityName(userData)}
height="54"
name={userData?.name ?? ''}
width="54"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ jest.mock('../../../../common/ProfilePicture/ProfilePicture', () => {
return jest.fn().mockReturnValue(<p>ProfilePicture</p>);
});

jest.mock('../../../../../utils/EntityUtils', () => ({
getEntityName: jest.fn().mockReturnValue('getEntityName'),
}));

describe('Test User User Profile Image Component', () => {
it('should render user profile image component', async () => {
render(<UserProfileImage {...mockPropsData} />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Card, Typography } from 'antd';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ReactComponent as UserIcons } from '../../../../../assets/svg/user.svg';
import { EntityType } from '../../../../../enums/entity.enum';
import Chip from '../../../../common/Chip/Chip.component';
import { UserProfileInheritedRolesProps } from './UserProfileInheritedRoles.interface';

Expand All @@ -37,6 +38,7 @@ const UserProfileInheritedRoles = ({
}>
<Chip
data={inheritedRoles ?? []}
entityType={EntityType.ROLE}
icon={<UserIcons height={20} />}
noDataPlaceholder={t('message.no-inherited-roles-found')}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import { Card, Select, Space, Tooltip, Typography } from 'antd';
import { AxiosError } from 'axios';
import { isEmpty, toLower } from 'lodash';
import React, { useEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ReactComponent as EditIcon } from '../../../../../assets/svg/edit-new.svg';
import { ReactComponent as UserIcons } from '../../../../../assets/svg/user.svg';
Expand All @@ -24,6 +24,7 @@ import {
PAGE_SIZE_LARGE,
TERM_ADMIN,
} from '../../../../../constants/constants';
import { EntityType } from '../../../../../enums/entity.enum';
import { Role } from '../../../../../generated/entity/teams/role';
import { useAuth } from '../../../../../hooks/authHooks';
import { getRoles } from '../../../../../rest/rolesAPIV1';
Expand Down Expand Up @@ -87,6 +88,15 @@ const UserProfileRoles = ({
}
};

const setUserRoles = useCallback(() => {
const defaultUserRoles = [
...(userRoles?.map((role) => role.id) ?? []),
...(isUserAdmin ? [toLower(TERM_ADMIN)] : []),
];

setSelectedRoles(defaultUserRoles);
}, [userRoles, isUserAdmin]);

const handleRolesSave = async () => {
setIsLoading(true);
// filter out the roles , and exclude the admin one
Expand Down Expand Up @@ -122,6 +132,7 @@ const UserProfileRoles = ({
: []),
...(userRoles ?? []),
]}
entityType={EntityType.ROLE}
icon={<UserIcons height={20} />}
noDataPlaceholder={t('message.no-roles-assigned')}
showNoDataPlaceholder={!isUserAdmin}
Expand All @@ -130,14 +141,14 @@ const UserProfileRoles = ({
[userRoles, isUserAdmin]
);

useEffect(() => {
const defaultUserRoles = [
...(userRoles?.map((role) => role.id) ?? []),
...(isUserAdmin ? [toLower(TERM_ADMIN)] : []),
];
const handleCloseEditRole = useCallback(() => {
setIsRolesEdit(false);
setUserRoles();
}, [setUserRoles]);

setSelectedRoles(defaultUserRoles);
}, [isUserAdmin, userRoles]);
useEffect(() => {
setUserRoles();
}, [setUserRoles]);

useEffect(() => {
if (isRolesEdit && isEmpty(roles)) {
Expand Down Expand Up @@ -176,7 +187,7 @@ const UserProfileRoles = ({
<InlineEdit
direction="vertical"
isLoading={isLoading}
onCancel={() => setIsRolesEdit(false)}
onCancel={handleCloseEditRole}
onSave={handleRolesSave}>
<Select
allowClear
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,18 @@
* limitations under the License.
*/

import { act, fireEvent, render, screen } from '@testing-library/react';
import {
act,
findByRole,
fireEvent,
render,
screen,
waitForElement,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { useAuth } from '../../../../../hooks/authHooks';
import { MOCK_USER_ROLE } from '../../../../../mocks/User.mock';
import { getRoles } from '../../../../../rest/rolesAPIV1';
import { mockUserRole } from '../../mocks/User.mocks';
import UserProfileRoles from './UserProfileRoles.component';
Expand All @@ -29,12 +38,16 @@ jest.mock('../../../../../hooks/authHooks', () => ({
}));

jest.mock('../../../../common/InlineEdit/InlineEdit.component', () => {
return jest.fn().mockImplementation(({ onSave }) => (
return jest.fn().mockImplementation(({ children, onCancel, onSave }) => (
<div data-testid="inline-edit">
<span>InlineEdit</span>
{children}
<button data-testid="save" onClick={onSave}>
save
</button>
<button data-testid="cancel" onClick={onCancel}>
cancel
</button>
</div>
));
});
Expand Down Expand Up @@ -147,4 +160,52 @@ describe('Test User Profile Roles Component', () => {

expect(screen.getByText('InlineEdit')).toBeInTheDocument();
});

it('should maintain initial state if edit is close without save', async () => {
(useAuth as jest.Mock).mockImplementation(() => ({
isAdminUser: true,
}));

render(
<UserProfileRoles
{...mockPropsData}
userRoles={MOCK_USER_ROLE.slice(0, 2)}
/>
);

fireEvent.click(screen.getByTestId('edit-roles-button'));

const selectInput = await findByRole(
screen.getByTestId('select-user-roles'),
'combobox'
);

await act(async () => {
userEvent.click(selectInput);
});

// wait for list to render, checked with item having in the list
await waitForElement(() => screen.findByText('admin'));

await act(async () => {
userEvent.click(screen.getByText('admin'));
});

fireEvent.click(screen.getByTestId('cancel'));

fireEvent.click(screen.getByTestId('edit-roles-button'));

await act(async () => {
userEvent.click(selectInput);
});

expect(
screen.getByText('37a00e0b-383c-4451-b63f-0bad4c745abc')
).toBeInTheDocument();
expect(
screen.getByText('afc5583c-e268-4f6c-a638-a876d04ebaa1')
).toBeInTheDocument();

expect(screen.queryByText('admin')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
*/

import { Card, Space, Tooltip, Typography } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ReactComponent as EditIcon } from '../../../../../assets/svg/edit-new.svg';
import { ReactComponent as IconTeamsGrey } from '../../../../../assets/svg/teams-grey.svg';
import {
DE_ACTIVE_COLOR,
ICON_DIMENSION,
} from '../../../../../constants/constants';
import { EntityType } from '../../../../../enums/entity.enum';
import { EntityReference } from '../../../../../generated/entity/type';
import { useAuth } from '../../../../../hooks/authHooks';
import { getNonDeletedTeams } from '../../../../../utils/CommonUtils';
Expand Down Expand Up @@ -55,17 +56,27 @@ const UserProfileTeams = ({
() => (
<Chip
data={getNonDeletedTeams(teams ?? [])}
entityType={EntityType.TEAM}
icon={<IconTeamsGrey height={20} />}
noDataPlaceholder={t('message.no-team-found')}
/>
),
[teams, getNonDeletedTeams]
);

useEffect(() => {
const setUserTeams = useCallback(() => {
setSelectedTeams(getNonDeletedTeams(teams ?? []));
}, [teams]);

const handleCloseEditTeam = useCallback(() => {
setIsTeamsEdit(false);
setUserTeams();
}, [setUserTeams]);

useEffect(() => {
setUserTeams();
}, [setUserTeams]);

return (
<Card
className="relative card-body-border-none card-padding-y-0"
Expand Down Expand Up @@ -97,7 +108,7 @@ const UserProfileTeams = ({
<InlineEdit
direction="vertical"
isLoading={isLoading}
onCancel={() => setIsTeamsEdit(false)}
onCancel={handleCloseEditTeam}
onSave={handleTeamsSave}>
<TeamsSelectable
filterJoinable
Expand Down
Loading

0 comments on commit 98945cb

Please sign in to comment.