[issues-5643] Profile page updated as per new layout. (#5644)

* [issues-5643] Profile page updated as per new layout.

* Css issue fixed.

* minor issue
This commit is contained in:
yug-shah0106 2022-06-27 14:18:34 +05:30 committed by GitHub
parent 8528c51b9c
commit 74d90c401f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 300 additions and 224 deletions

View File

@ -657,37 +657,38 @@ const Explore: React.FC<ExploreProps> = ({
const fetchLeftPanel = () => { const fetchLeftPanel = () => {
return ( return (
<Card <div className="tw-h-full">
className="tw-h-full" <Card
data-testid="data-summary-container" data-testid="data-summary-container"
style={{ ...leftPanelAntCardStyle, marginTop: '16px' }}> style={{ ...leftPanelAntCardStyle, marginTop: '16px' }}>
<Fragment> <Fragment>
<div className="tw-w-64 tw-mr-5 tw-flex-shrink-0"> <div className="tw-w-64 tw-mr-5 tw-flex-shrink-0">
<Button <Button
className={classNames('tw-underline tw-pb-4')} className={classNames('tw-underline tw-pb-4')}
disabled={!getFilterCount(filters)} disabled={!getFilterCount(filters)}
size="custom" size="custom"
theme="primary" theme="primary"
variant="link" variant="link"
onClick={() => resetFilters(true)}> onClick={() => resetFilters(true)}>
Clear All Clear All
</Button> </Button>
</div> </div>
<div className="tw-filter-seperator" /> <div className="tw-filter-seperator" />
{!error && ( {!error && (
<FacetFilter <FacetFilter
aggregations={getAggrWithDefaultValue( aggregations={getAggrWithDefaultValue(
aggregations, aggregations,
visibleFilters visibleFilters
)} )}
filters={getFacetedFilter()} filters={getFacetedFilter()}
showDeletedOnly={showDeleted} showDeletedOnly={showDeleted}
onSelectDeleted={handleShowDeleted} onSelectDeleted={handleShowDeleted}
onSelectHandler={handleSelectedFilter} onSelectHandler={handleSelectedFilter}
/> />
)} )}
</Fragment> </Fragment>
</Card> </Card>
</div>
); );
}; };

View File

@ -12,6 +12,7 @@
*/ */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Card } from 'antd';
import { AxiosError, AxiosResponse } from 'axios'; import { AxiosError, AxiosResponse } from 'axios';
import { isNil, toLower } from 'lodash'; import { isNil, toLower } from 'lodash';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
@ -50,7 +51,7 @@ import Description from '../common/description/Description';
import ProfilePicture from '../common/ProfilePicture/ProfilePicture'; import ProfilePicture from '../common/ProfilePicture/ProfilePicture';
import { reactSingleSelectCustomStyle } from '../common/react-select-component/reactSelectCustomStyle'; import { reactSingleSelectCustomStyle } from '../common/react-select-component/reactSelectCustomStyle';
import TabsPane from '../common/TabsPane/TabsPane'; import TabsPane from '../common/TabsPane/TabsPane';
import PageLayout from '../containers/PageLayout'; import PageLayout, { leftPanelAntCardStyle } from '../containers/PageLayout';
import Loader from '../Loader/Loader'; import Loader from '../Loader/Loader';
import { Option, Props } from './Users.interface'; import { Option, Props } from './Users.interface';
const tabs = [ const tabs = [
@ -213,9 +214,9 @@ const Users = ({
const getDisplayNameComponent = () => { const getDisplayNameComponent = () => {
if (isAdminUser || isLoggedinUser || isAuthDisabled) { if (isAdminUser || isLoggedinUser || isAuthDisabled) {
return ( return (
<div className="tw-mt-4 tw-w-full"> <div className="tw-mt-4 tw-w-full tw-flex tw-items-center tw-justify-between tw-px-3">
{isDisplayNameEdit ? ( {isDisplayNameEdit ? (
<div className="tw-flex tw-items-center tw-gap-1"> <div className="tw-flex tw-items-center tw-gap-1 ">
<input <input
className="tw-form-inputs tw-form-inputs-padding tw-py-0.5 tw-w-64" className="tw-form-inputs tw-form-inputs-padding tw-py-0.5 tw-w-64"
data-testid="displayName" data-testid="displayName"
@ -279,7 +280,7 @@ const Users = ({
const getDescriptionComponent = () => { const getDescriptionComponent = () => {
if (isAdminUser || isLoggedinUser || isAuthDisabled) { if (isAdminUser || isLoggedinUser || isAuthDisabled) {
return ( return (
<div className="tw--ml-5"> <div className="tw--ml-5 tw-flex tw-items-center tw-justify-between tw-px-3">
<Description <Description
description={userData.description || ''} description={userData.description || ''}
entityName={getEntityName(userData as unknown as EntityReference)} entityName={getEntityName(userData as unknown as EntityReference)}
@ -321,84 +322,102 @@ const Users = ({
if (!isAdminUser && !isAuthDisabled) { if (!isAdminUser && !isAuthDisabled) {
return ( return (
<Fragment> <Card
<div className="tw-flex"> className="ant-card-feed tw-relative"
<h6 className="tw-heading tw-mb-3">Teams</h6> key="inherited-roles-card"
</div> style={{
<div className="tw-pb-4 tw-mb-4 tw-border-b">{teamsElement}</div> ...leftPanelAntCardStyle,
</Fragment> marginTop: '20px',
}}
title={
<div className="tw-flex tw-items-center tw-justify-between">
<h6 className="tw-heading tw-mb-0">Teams</h6>
</div>
}>
<div>{teamsElement}</div>
</Card>
); );
} else { } else {
return ( return (
<Fragment> <Card
<div className="tw-flex"> className="ant-card-feed tw-relative"
<h6 className="tw-heading tw-mb-3">Teams</h6> key="inherited-roles-card"
{!isTeamsEdit && ( style={{
<button ...leftPanelAntCardStyle,
className="tw-ml-2 focus:tw-outline-none tw-self-baseline" marginTop: '20px',
data-testid="edit-teams" }}
onClick={() => setIsTeamsEdit(true)}> title={
<SVGIcons <div className="tw-flex tw-items-center tw-justify-between">
alt="edit" <h6 className="tw-heading tw-mb-0">Teams</h6>
icon="icon-edit" {!isTeamsEdit && (
title="Edit" <button
width="16px" className="tw-ml-2 focus:tw-outline-none tw-self-baseline"
/> data-testid="edit-teams"
</button> onClick={() => setIsTeamsEdit(true)}>
)} <SVGIcons
</div> alt="edit"
<div className="tw-pb-4 tw-mb-4 tw-border-b"> icon="icon-edit"
{isTeamsEdit ? ( title="Edit"
<Fragment> width="16px"
<Select />
isClearable </button>
isMulti )}
aria-label="Select teams" </div>
className="tw-ml-1" }>
isSearchable={false} <Fragment>
options={teams?.map((team) => ({ <div>
label: getEntityName(team as unknown as EntityReference), {isTeamsEdit ? (
value: team.id, <Fragment>
}))} <Select
placeholder="Teams..." isClearable
styles={reactSingleSelectCustomStyle} isMulti
value={selectedTeams} aria-label="Select teams"
onChange={handleOnTeamsChange} className="tw-ml-1"
/> isSearchable={false}
<div options={teams?.map((team) => ({
className="tw-flex tw-justify-end tw-mt-2" label: getEntityName(team as unknown as EntityReference),
data-testid="buttons"> value: team.id,
<Button }))}
className="tw-px-1 tw-py-1 tw-rounded tw-text-sm tw-mr-1" placeholder="Teams..."
data-testid="cancel-teams" styles={reactSingleSelectCustomStyle}
size="custom" value={selectedTeams}
theme="primary" onChange={handleOnTeamsChange}
variant="contained" />
onMouseDown={() => setIsTeamsEdit(false)}> <div
<FontAwesomeIcon className="tw-flex tw-justify-end tw-mt-2"
className="tw-w-3.5 tw-h-3.5" data-testid="buttons">
icon="times" <Button
/> className="tw-px-1 tw-py-1 tw-rounded tw-text-sm tw-mr-1"
</Button> data-testid="cancel-teams"
<Button size="custom"
className="tw-px-1 tw-py-1 tw-rounded tw-text-sm" theme="primary"
data-testid="save-teams" variant="contained"
size="custom" onMouseDown={() => setIsTeamsEdit(false)}>
theme="primary" <FontAwesomeIcon
variant="contained" className="tw-w-3.5 tw-h-3.5"
onClick={handleTeamsChange}> icon="times"
<FontAwesomeIcon />
className="tw-w-3.5 tw-h-3.5" </Button>
icon="check" <Button
/> className="tw-px-1 tw-py-1 tw-rounded tw-text-sm"
</Button> data-testid="save-teams"
</div> size="custom"
</Fragment> theme="primary"
) : ( variant="contained"
teamsElement onClick={handleTeamsChange}>
)} <FontAwesomeIcon
</div> className="tw-w-3.5 tw-h-3.5"
</Fragment> icon="check"
/>
</Button>
</div>
</Fragment>
) : (
teamsElement
)}
</div>
</Fragment>
</Card>
); );
} }
}; };
@ -434,82 +453,102 @@ const Users = ({
if (!isAdminUser && !isAuthDisabled) { if (!isAdminUser && !isAuthDisabled) {
return ( return (
<Fragment> <Card
<div className="tw-flex"> className="ant-card-feed tw-relative"
<h6 className="tw-heading tw-mb-3">Roles</h6> key="inherited-roles-card"
style={{
...leftPanelAntCardStyle,
marginTop: '20px',
}}
title={
<div className="tw-flex tw-items-center tw-justify-between">
<h6 className="tw-heading tw-mb-0">Roles</h6>
</div>
}>
<div className="tw-flex tw-items-center tw-justify-between">
{rolesElement}
</div> </div>
<div className="tw-pb-4 tw-mb-4 tw-border-b">{rolesElement}</div> </Card>
</Fragment>
); );
} else { } else {
return ( return (
<Fragment> <Card
<div className="tw-flex"> className="ant-card-feed tw-relative"
<h6 className="tw-heading tw-mb-3">Roles</h6> key="inherited-roles-card"
{!isRolesEdit && ( style={{
<button ...leftPanelAntCardStyle,
className="tw-ml-2 focus:tw-outline-none tw-self-baseline" marginTop: '20px',
data-testid="edit-roles" }}
onClick={() => setIsRolesEdit(true)}> title={
<SVGIcons <div className="tw-flex tw-items-center tw-justify-between">
alt="edit" <h6 className="tw-heading tw-mb-0">Roles</h6>
icon="icon-edit" {!isRolesEdit && (
title="Edit" <button
width="16px" className="tw-ml-2 focus:tw-outline-none tw-self-baseline"
/> data-testid="edit-roles"
</button> onClick={() => setIsRolesEdit(true)}>
)} <SVGIcons
</div> alt="edit"
<div className="tw-pb-4 tw-mb-4 tw-border-b"> icon="icon-edit"
{isRolesEdit ? ( title="Edit"
<Fragment> width="16px"
<Select />
isClearable </button>
isMulti )}
aria-label="Select roles" </div>
className="tw-ml-1" }>
id="select-role" <Fragment>
isSearchable={false} <div className="tw-flex tw-items-center tw-justify-between">
options={userRolesOption} {isRolesEdit ? (
placeholder="Roles..." <Fragment>
styles={reactSingleSelectCustomStyle} <Select
value={selectedRoles} isClearable
onChange={handleOnRolesChange} isMulti
/> aria-label="Select roles"
<div className="tw-ml-1"
className="tw-flex tw-justify-end tw-mt-2" id="select-role"
data-testid="buttons"> isSearchable={false}
<Button options={userRolesOption}
className="tw-px-1 tw-py-1 tw-rounded tw-text-sm tw-mr-1" placeholder="Roles..."
data-testid="cancel-roles" styles={reactSingleSelectCustomStyle}
size="custom" value={selectedRoles}
theme="primary" onChange={handleOnRolesChange}
variant="contained" />
onMouseDown={() => setIsRolesEdit(false)}> <div
<FontAwesomeIcon className="tw-flex tw-justify-end tw-mt-2"
className="tw-w-3.5 tw-h-3.5" data-testid="buttons">
icon="times" <Button
/> className="tw-px-1 tw-py-1 tw-rounded tw-text-sm tw-mr-1"
</Button> data-testid="cancel-roles"
<Button size="custom"
className="tw-px-1 tw-py-1 tw-rounded tw-text-sm" theme="primary"
data-testid="save-roles" variant="contained"
size="custom" onMouseDown={() => setIsRolesEdit(false)}>
theme="primary" <FontAwesomeIcon
variant="contained" className="tw-w-3.5 tw-h-3.5"
onClick={handleRolesChange}> icon="times"
<FontAwesomeIcon />
className="tw-w-3.5 tw-h-3.5" </Button>
icon="check" <Button
/> className="tw-px-1 tw-py-1 tw-rounded tw-text-sm"
</Button> data-testid="save-roles"
</div> size="custom"
</Fragment> theme="primary"
) : ( variant="contained"
rolesElement onClick={handleRolesChange}>
)} <FontAwesomeIcon
</div> className="tw-w-3.5 tw-h-3.5"
</Fragment> icon="check"
/>
</Button>
</div>
</Fragment>
) : (
rolesElement
)}
</div>
</Fragment>
</Card>
); );
} }
}; };
@ -517,21 +556,33 @@ const Users = ({
const getInheritedRolesComponent = () => { const getInheritedRolesComponent = () => {
if (userData.inheritedRoles?.length) { if (userData.inheritedRoles?.length) {
return ( return (
<Fragment> <Card
<div className="tw-flex"> className="ant-card-feed tw-relative"
<h6 className="tw-heading tw-mb-3" data-testid="inherited-roles"> key="inherited-roles-card"
Inherited Roles style={{
</h6> ...leftPanelAntCardStyle,
</div> marginTop: '20px',
<div className="tw-pb-4 tw-mb-4 tw-border-b"> }}
{userData.inheritedRoles?.map((inheritedRole, i) => ( title={
<div className="tw-mb-2 tw-flex tw-items-center tw-gap-2" key={i}> <div className="tw-flex">
<SVGIcons alt="icon" className="tw-w-4" icon={Icons.USERS} /> <h6 className="tw-heading tw-mb-0" data-testid="inherited-roles">
<span>{getEntityName(inheritedRole)}</span> Inherited Roles
</div> </h6>
))} </div>
</div> }>
</Fragment> <Fragment>
<div className="tw-flex tw-justify-between tw-flex-col">
{userData.inheritedRoles?.map((inheritedRole, i) => (
<div
className="tw-mb-2 tw-flex tw-items-center tw-gap-2"
key={i}>
<SVGIcons alt="icon" className="tw-w-4" icon={Icons.USERS} />
<span>{getEntityName(inheritedRole)}</span>
</div>
))}
</div>
</Fragment>
</Card>
); );
} else { } else {
return null; return null;
@ -540,30 +591,41 @@ const Users = ({
const fetchLeftPanel = () => { const fetchLeftPanel = () => {
return ( return (
<div className="tw-pt-4" data-testid="left-panel"> <div className="user-profile-antd-card" data-testid="left-panel">
<div className="tw-pb-4 tw-mb-4 tw-border-b tw-flex tw-flex-col"> <Card
{userData.profile?.images?.image ? ( className="ant-card-feed tw-relative"
<div className="tw-h-28 tw-w-28"> key="inherited-roles-card"
<img style={{
alt="profile" ...leftPanelAntCardStyle,
className="tw-w-full" marginTop: '12px',
referrerPolicy="no-referrer" }}>
src={userData.profile?.images?.image} <div className="tw-flex tw-flex-col">
{userData.profile?.images?.image ? (
<div>
<img
alt="profile"
className="tw-w-full"
height="150px"
referrerPolicy="no-referrer"
src={userData.profile?.images?.image}
width="300px"
/>
</div>
) : (
<ProfilePicture
displayName={userData?.displayName || userData.name}
height="150"
id={userData?.id || ''}
name={userData?.name || ''}
textClass="tw-text-5xl"
width="300"
/> />
</div> )}
) : ( {getDisplayNameComponent()}
<ProfilePicture <p className="tw-mt-2 tw-mx-3">{userData.email}</p>
displayName={userData?.displayName || userData.name} {getDescriptionComponent()}
id={userData?.id || ''} </div>
name={userData?.name || ''} </Card>
textClass="tw-text-5xl"
width="112"
/>
)}
{getDisplayNameComponent()}
<p className="tw-mt-2">{userData.email}</p>
{getDescriptionComponent()}
</div>
{getTeamsComponent()} {getTeamsComponent()}
{getRolesComponent()} {getRolesComponent()}
{getInheritedRolesComponent()} {getInheritedRolesComponent()}

View File

@ -17,7 +17,7 @@ export const cardStyle = {
active: 'tw-border-primary', active: 'tw-border-primary',
selected: 'tw-border-primary', selected: 'tw-border-primary',
header: { header: {
base: 'tw-flex tw-px-5 tw-py-3 tw-cursor-pointer tw-justify-between tw-items-center', base: 'tw-flex tw-px-5 tw-py-3 tw-cursor-pointer tw-justify-between tw-items-center tw-rounded-t-md',
default: '', default: '',
active: 'tw-bg-primary-lite tw-border-b tw-border-primary', active: 'tw-bg-primary-lite tw-border-b tw-border-primary',
selected: 'tw-bg-primary tw-text-white', selected: 'tw-bg-primary tw-text-white',

View File

@ -29,6 +29,7 @@ interface Props extends UserData {
type?: ImageShape; type?: ImageShape;
textClass?: string; textClass?: string;
className?: string; className?: string;
height?: string;
} }
const ProfilePicture = ({ const ProfilePicture = ({
@ -39,6 +40,7 @@ const ProfilePicture = ({
textClass = '', textClass = '',
type = 'square', type = 'square',
width = '36', width = '36',
height,
}: Props) => { }: Props) => {
const profilePic = useMemo(() => { const profilePic = useMemo(() => {
return getUserProfilePic(id, name); return getUserProfilePic(id, name);
@ -52,6 +54,7 @@ const ProfilePicture = ({
return ( return (
<Avatar <Avatar
className={className} className={className}
height={height}
name={getEntityName({ name, displayName } as EntityReference)} name={getEntityName({ name, displayName } as EntityReference)}
textClass={textClass} textClass={textClass}
type={type} type={type}
@ -64,7 +67,10 @@ const ProfilePicture = ({
return isPicLoading ? ( return isPicLoading ? (
<div <div
className="tw-inline-block tw-relative" className="tw-inline-block tw-relative"
style={{ height: `${width}px`, width: `${width}px` }}> style={{
height: `${height || width}px`,
width: `${width}px`,
}}>
{getAvatarByName()} {getAvatarByName()}
<div <div
className="tw-absolute tw-inset-0 tw-opacity-60 tw-bg-grey-backdrop tw-rounded" className="tw-absolute tw-inset-0 tw-opacity-60 tw-bg-grey-backdrop tw-rounded"
@ -85,7 +91,7 @@ const ProfilePicture = ({
return profilePic ? ( return profilePic ? (
<div <div
className={classNames('profile-image', type)} className={classNames('profile-image', type)}
style={{ height: `${width}px`, width: `${width}px` }}> style={{ height: `${height || width}px`, width: `${width}px` }}>
<img <img
alt="user" alt="user"
data-testid="profile-image" data-testid="profile-image"

View File

@ -22,12 +22,14 @@ const Avatar = ({
textClass = '', textClass = '',
className = '', className = '',
type = 'square', type = 'square',
height,
}: { }: {
name: string; name: string;
width?: string; width?: string;
textClass?: string; textClass?: string;
className?: string; className?: string;
type?: ImageShape; type?: ImageShape;
height?: string;
}) => { }) => {
const { color, character } = getRandomColor(name); const { color, character } = getRandomColor(name);
@ -39,7 +41,7 @@ const Avatar = ({
)} )}
data-testid="avatar" data-testid="avatar"
style={{ style={{
height: `${width}px`, height: `${height || width}px`,
width: `${width}px`, width: `${width}px`,
borderRadius: type === 'circle' ? '50%' : '4px', borderRadius: type === 'circle' ? '50%' : '4px',
background: color, background: color,

View File

@ -1298,6 +1298,11 @@ div.ant-typography-ellipsis-custom {
margin-bottom: 0px; margin-bottom: 0px;
} }
.user-profile-antd-card .ant-card-body:first-child {
padding: 0px;
overflow: hidden;
}
.ant-input:hover, .ant-input:hover,
.ant-input:focus { .ant-input:focus {
border-color: #7147e8; border-color: #7147e8;