Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/users and groups UI updated as per new design #4134

Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a47f1eb
user sidebar and assets UI completed
ShubhamThakre Jan 24, 2022
fa3a92f
user groups UI fixes
ShubhamThakre Jan 25, 2022
db9274a
user group changes/fixes completed
ShubhamThakre Jan 25, 2022
a4bd452
UserGroups pagination added/ code refactored
ShubhamThakre Jan 25, 2022
fb72815
UserSidebar View-> groups and editProfile modal UI and functionality …
ShubhamThakre Jan 31, 2022
678f38d
Merge remote-tracking branch 'origin/master' into feature/users-and-g…
ShubhamThakre Feb 1, 2022
8575248
new search component added | avatar color change completed | code cle…
ShubhamThakre Feb 2, 2022
9c8ed83
Groups tab disabled || Groups section no data added, if no groups dat…
ShubhamThakre Feb 7, 2022
42e93de
About section added | Groups scetion height issue fix- as per screen …
ShubhamThakre Feb 7, 2022
355b730
user sidebar- about section and group section css fixes | added scrol…
ShubhamThakre Feb 8, 2022
b36fd4f
User Side bar section css changes | edit profile modal field validati…
ShubhamThakre Feb 9, 2022
fe513ca
Merge remote-tracking branch 'origin/master' into feature/users-and-g…
ShubhamThakre Feb 10, 2022
c9282fe
Merge remote-tracking branch 'origin/master' into feature/users-and-g…
ShubhamThakre Feb 10, 2022
ec5778c
Mutation updated | userSidebar section remaning fields added | Valida…
ShubhamThakre Feb 14, 2022
cb48b3a
modal error validation added on save changes button | bug fixes | cod…
ShubhamThakre Feb 14, 2022
f370fff
PR Comments resolved
ShubhamThakre Feb 15, 2022
696535e
PR changes completed- userSidebar section seprate pending
ShubhamThakre Feb 16, 2022
5ad5adc
PR comments resolved | yarn lint checked
ShubhamThakre Feb 16, 2022
a9f10ed
User Side bar section seperated | code clean up
ShubhamThakre Feb 17, 2022
08e6527
PR commets resolved
ShubhamThakre Feb 17, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions datahub-web-react/src/app/entity/user/UserAssets.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import styled from 'styled-components';
import { EmbeddedListSearch } from '../shared/components/styled/search/EmbeddedListSearch';
import { useEntityData } from '../shared/EntityContext';

const UserAssetsWrapper = styled.div`
height: calc(100vh - 114px);
overflow: auto;
`;
export const UserAssets = () => {
const { urn } = useEntityData();

return (
<UserAssetsWrapper>
<EmbeddedListSearch
fixedFilter={{ field: 'owners', value: urn }}
emptySearchQuery="*"
placeholderText="Filter domain entities..."
/>
</UserAssetsWrapper>
);
};
221 changes: 221 additions & 0 deletions datahub-web-react/src/app/entity/user/UserEditProfileModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import React, { useState } from 'react';
import { message, Button, Input, Modal, Typography, Form } from 'antd';
import { useUpdateCorpUserPropertiesMutation } from '../../../graphql/user.generated';

type Props = {
visible: boolean;
onClose: () => void;
onSave: () => void;
data: {
name: string | undefined;
title: string | undefined;
image: string | undefined;
team: string | undefined;
email: string | undefined;
slack: string | undefined;
phone: string | undefined;
urn: string | undefined;
};
};
/** Regex Validations */
export const validUserName = new RegExp('^[a-zA-Z ]*$');
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved

export default function UserEditProfileModal({ visible, onClose, onSave, data }: Props) {
const [updateCorpUserPropertiesMutation] = useUpdateCorpUserPropertiesMutation();
const [form] = Form.useForm();

const [userName, setUserName] = useState<string | undefined>(data.name);
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
const [userTitle, setUserTitle] = useState<string | undefined>(data.title);
const [userImageURL, setImageURL] = useState<string | undefined>(data.image);
const [userTeam, setUserTeam] = useState<string | undefined>(data.team);
const [userEmail, setUserEmail] = useState<string | undefined>(data.email);
const [userSlack, setUserSlack] = useState<string | undefined>(data.slack);
const [userPhoneNumber, setUserPhoneNumber] = useState<string | undefined>(data.phone);
const [buttonDisabled, setButtonDisabled] = useState(true);
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved

// save changes function
const onCreateGroup = () => {
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
updateCorpUserPropertiesMutation({
variables: {
urn: data?.urn || '',
input: {
displayName: userName,
title: userTitle,
pictureLink: userImageURL,
teams: userTeam?.split(','),
email: userEmail,
slack: userSlack,
phone: userPhoneNumber,
},
},
})
.catch((e) => {
message.destroy();
message.error({ content: `Failed to Save changes!: \n ${e.message || ''}`, duration: 3 });
})
.finally(() => {
message.success({
content: `Changes saved.`,
duration: 3,
});
onSave(); // call the refetch function once save
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
// clear the values from edit profile form
setUserName('');
setUserTitle('');
setImageURL('');
setUserTeam('');
setUserEmail('');
setUserSlack('');
setUserPhoneNumber('');
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
});
onClose();
onSave();
};

// userFieldValidation before submitting the changes.
const userFieldValidations = () => {
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
if (buttonDisabled) return true;
return false;
};

return (
<Modal
title="Edit Profile"
visible={visible}
onCancel={onClose}
footer={
<>
<Button onClick={onClose} type="text">
Cancel
</Button>
<Button onClick={onCreateGroup} disabled={userFieldValidations()}>
Save Changes
</Button>
</>
}
>
<Form
form={form}
initialValues={{ ...data }}
autoComplete="off"
layout="vertical"
onFieldsChange={() => setButtonDisabled(form.getFieldsError().some((field) => field.errors.length > 0))}
>
<Form.Item
name="name"
label={<Typography.Text strong>Name</Typography.Text>}
rules={[
{
required: true,
message: 'Please enter the User name.',
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
},
{ whitespace: true },
{ min: 2, max: 50 },
{
pattern: new RegExp('^[a-zA-Z ]*$'),
message: '',
},
]}
hasFeedback
>
<Input
placeholder="add name"
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
value={userName}
onChange={(event) => setUserName(event.target.value)}
/>
</Form.Item>
<Form.Item
name="title"
label={<Typography.Text strong>Title/Role</Typography.Text>}
rules={[{ whitespace: true }, { min: 2, max: 50 }]}
hasFeedback
>
<Input
placeholder="add title/role"
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
value={userTitle}
onChange={(event) => setUserTitle(event.target.value)}
/>
</Form.Item>
<Form.Item
name="image"
label={<Typography.Text strong>Image URL</Typography.Text>}
rules={[{ whitespace: true }, { type: 'url', message: 'not valid url' }]}
hasFeedback
>
<Input
placeholder="add image URL"
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
value={userImageURL}
onChange={(event) => setImageURL(event.target.value)}
/>
</Form.Item>
<Form.Item
name="team"
label={<Typography.Text strong>Team</Typography.Text>}
rules={[{ whitespace: true }, { min: 2, max: 50 }]}
>
<Input
placeholder="add team name"
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
value={userTeam}
onChange={(event) => setUserTeam(event.target.value)}
/>
</Form.Item>
<Form.Item
name="email"
label={<Typography.Text strong>Email</Typography.Text>}
rules={[
{
required: true,
message: 'Please enter your email',
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
},
{
type: 'email',
message: 'Please enter valid email',
},
{ whitespace: true },
{ min: 2, max: 50 },
]}
hasFeedback
>
<Input
placeholder="add email"
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
value={userEmail}
onChange={(event) => setUserEmail(event.target.value)}
/>
</Form.Item>
<Form.Item
name="slack"
label={<Typography.Text strong>Slack</Typography.Text>}
rules={[{ whitespace: true }, { min: 2, max: 50 }]}
hasFeedback
>
<Input
placeholder="add slack id"
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
value={userSlack}
onChange={(event) => setUserSlack(event.target.value)}
/>
</Form.Item>
<Form.Item
name="phone"
label={<Typography.Text strong>Phone</Typography.Text>}
rules={[
{
pattern: new RegExp('^(?=.*[0-9])[- +()0-9]+$'),
message: 'not valid phone number',
},
{
min: 5,
max: 15,
},
]}
hasFeedback
>
<Input
placeholder="add phone number"
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
value={userPhoneNumber}
onChange={(event) => setUserPhoneNumber(event.target.value)}
/>
</Form.Item>
</Form>
</Modal>
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
);
}
116 changes: 82 additions & 34 deletions datahub-web-react/src/app/entity/user/UserGroups.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,73 @@
import { List, Pagination, Row, Space, Typography } from 'antd';
import { Col, Pagination, Row, Tooltip } from 'antd';
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import styled from 'styled-components';
import { useGetUserGroupsLazyQuery } from '../../../graphql/user.generated';
import { CorpGroup, EntityRelationshipsResult, EntityType } from '../../../types.generated';
import { useEntityRegistry } from '../../useEntityRegistry';
import { PreviewType } from '../Entity';

type Props = {
urn: string;
initialRelationships?: EntityRelationshipsResult | null;
pageSize: number;
};

const GroupList = styled(List)`
&&& {
const GroupsViewWrapper = styled.div`
height: calc(100vh - 173px);
overflow-y: auto;

.user-group-pagination {
justify-content: center;
bottom: 24px;
position: absolute;
width: 100%;
border-color: ${(props) => props.theme.styles['border-color-base']};
margin-top: 12px;
margin-bottom: 28px;
padding: 24px 32px;
box-shadow: ${(props) => props.theme.styles['box-shadow']};
left: 50%;
-webkit-transform: translateX(-50%);
-moz-transform: translateX(-50%);
-webkit-transform: translateX(-50%);
-ms-transform: translateX(-50%);
transform: translateX(-50%);
}
& li {
padding-top: 28px;
padding-bottom: 28px;
`;
const GroupItemColumn = styled(Col)`
padding: 10px;
`;
const GroupItem = styled.div`
border: 1px solid #d9d9d9;
padding: 10px;
min-height: 107px;
max-height: 107px;

.title-row {
padding: 9px 11px 9px 11px;
}
& li:not(:last-child) {
border-bottom: 1.5px solid #ededed;
.description-row {
padding: 2px 13px;
}
`;

const GroupsView = styled(Space)`
width: 100%;
margin-bottom: 32px;
padding-top: 28px;
const GroupTitle = styled.span`
font-size: 14px;
line-height: 22px;
font-weight: bold;
color: #262626;
`;
const GroupMember = styled.span`
font-weight: 500;
font-size: 12px;
line-height: 23px;
color: #8c8c8c;
padding-left: 7px;
`;
const GroupDescription = styled.span`
font-weight: 500;
font-size: 12px;
line-height: 20px;
color: #262626;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
height: 43px;
`;

export default function UserGroups({ urn, initialRelationships, pageSize }: Props) {
const [page, setPage] = useState(1);
const entityRegistry = useEntityRegistry();
Expand All @@ -53,19 +85,35 @@ export default function UserGroups({ urn, initialRelationships, pageSize }: Prop
const userGroups = relationships?.relationships?.map((rel) => rel.entity as CorpGroup) || [];

return (
<GroupsView direction="vertical" size="middle">
<Typography.Title level={3}>Group Membership</Typography.Title>
<Row justify="center">
<GroupList
dataSource={userGroups}
split={false}
renderItem={(item, _) => (
<List.Item>
{entityRegistry.renderPreview(EntityType.CorpGroup, PreviewType.PREVIEW, item)}
</List.Item>
)}
bordered
/>
<GroupsViewWrapper>
<Row justify="space-between">
{userGroups &&
userGroups.map((item) => {
return (
<GroupItemColumn xl={8} lg={8} md={12} sm={12} xs={24} key={item.urn}>
<Link to={entityRegistry.getEntityUrl(EntityType.CorpGroup, item.urn)}>
<GroupItem>
<Row className="title-row">
<GroupTitle>{item.info?.displayName || 'NA'}</GroupTitle>
ShubhamThakre marked this conversation as resolved.
Show resolved Hide resolved
<GroupMember>
{item.relationships?.total}
{item.relationships?.total === 1 ? ' member' : ' members'}
</GroupMember>
</Row>
<Row className="description-row">
<GroupDescription>
<Tooltip title={item.info?.description}>
{item.info?.description}
</Tooltip>
</GroupDescription>
</Row>
</GroupItem>
</Link>
</GroupItemColumn>
);
})}
</Row>
<Row className="user-group-pagination">
<Pagination
current={page}
pageSize={pageSize}
Expand All @@ -75,6 +123,6 @@ export default function UserGroups({ urn, initialRelationships, pageSize }: Prop
showSizeChanger={false}
/>
</Row>
</GroupsView>
</GroupsViewWrapper>
);
}
Loading