Skip to content

Commit 90a6c15

Browse files
authored
UI Changes for Comment and add reviewer option (#273)
* Fixed builds section * Tasks section * Theme changes * Review section * Merge conflict fix * Updated changelog * UI chnages * Added changelog
1 parent f44a096 commit 90a6c15

File tree

6 files changed

+302
-235
lines changed

6 files changed

+302
-235
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## What's new in 3.4.24
2+
3+
### Improvements
4+
- In PR details page, made UI Changes to make the comment section and Add Reviewer option cleaner and user friendly
5+
16
## What's new in 3.4.23
27

38
### Improvements
Lines changed: 154 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,86 @@
1-
import { Typography, Tooltip, Button } from '@material-ui/core';
2-
import React, { useCallback, useState } from 'react';
1+
import { Avatar, Grid, TextField, Typography, makeStyles } from '@material-ui/core';
2+
import { Autocomplete } from '@material-ui/lab';
3+
import AddIcon from '@material-ui/icons/Add';
4+
import AwesomeDebouncePromise from 'awesome-debounce-promise';
5+
import React, { useCallback, useContext, useState } from 'react';
6+
import { useAsyncAbortable } from 'react-async-hook';
7+
import useConstant from 'use-constant';
38
import { BitbucketSite, User } from '../../../bitbucket/model';
4-
import DialogUserPicker from './DialogUserPicker';
9+
import { PullRequestDetailsControllerContext } from './pullRequestDetailsController';
10+
11+
const useStyles = makeStyles({
12+
container: {
13+
display: 'flex',
14+
alignItems: 'center',
15+
width: '100%',
16+
position: 'relative',
17+
paddingLeft: 28,
18+
},
19+
addIcon: {
20+
padding: 0,
21+
fontSize: 20,
22+
color: 'var(--vscode-editor-foreground)',
23+
opacity: 0.8,
24+
position: 'absolute',
25+
left: 4,
26+
top: '50%',
27+
transform: 'translateY(-50%)',
28+
display: 'flex',
29+
alignItems: 'center',
30+
justifyContent: 'center',
31+
height: '20px',
32+
width: '20px',
33+
lineHeight: 0,
34+
},
35+
autocompleteRoot: {
36+
flex: 1,
37+
'& .MuiInputBase-root': {
38+
backgroundColor: 'transparent',
39+
color: 'var(--vscode-editor-foreground)',
40+
padding: '0 !important',
41+
minHeight: '24px',
42+
display: 'flex',
43+
alignItems: 'center',
44+
border: '1px solid transparent',
45+
borderRadius: '2px',
46+
'&.Mui-focused': {
47+
border: '1px solid var(--vscode-editor-foreground)',
48+
},
49+
'&:hover': {
50+
border: '1px solid var(--vscode-editor-foreground)',
51+
},
52+
},
53+
'& .MuiOutlinedInput-notchedOutline': {
54+
border: 'none',
55+
},
56+
'& .MuiInputBase-input': {
57+
color: 'var(--vscode-editor-foreground)',
58+
height: '24px',
59+
lineHeight: '24px',
60+
padding: '0 7px !important',
61+
'&::placeholder': {
62+
color: 'var(--vscode-input-placeholderForeground)',
63+
opacity: 0.8,
64+
fontStyle: 'italic',
65+
},
66+
},
67+
'& .MuiAutocomplete-endAdornment': {
68+
display: 'none',
69+
},
70+
'& .MuiFormControl-marginDense': {
71+
margin: '0',
72+
},
73+
},
74+
optionContainer: {
75+
padding: '8px',
76+
},
77+
avatarContainer: {
78+
marginRight: '8px',
79+
},
80+
optionText: {
81+
color: 'var(--vscode-editor-foreground)',
82+
},
83+
});
584

685
type AddReviewersProps = {
786
site: BitbucketSite;
@@ -10,39 +89,85 @@ type AddReviewersProps = {
1089
};
1190

1291
export const AddReviewers: React.FunctionComponent<AddReviewersProps> = ({ site, reviewers, updateReviewers }) => {
13-
const [isOpen, setIsOpen] = useState(false);
92+
const controller = useContext(PullRequestDetailsControllerContext);
93+
const [inputText, setInputText] = useState('');
94+
const classes = useStyles();
95+
96+
const debouncedUserFetcher = useConstant(() =>
97+
AwesomeDebouncePromise(
98+
async (site: BitbucketSite, query: string, abortSignal?: AbortSignal): Promise<User[]> => {
99+
return await controller.fetchUsers(site, query, abortSignal);
100+
},
101+
300,
102+
{ leading: false },
103+
),
104+
);
14105

15-
const handleUpdateReviewers = useCallback(
16-
async (newUser: User) => {
17-
setIsOpen(false);
18-
const updatedReviewers = [...reviewers, newUser];
19-
await updateReviewers(updatedReviewers);
106+
const handleInputChange = useCallback(
107+
(event: React.ChangeEvent, value: string) => {
108+
if (event?.type === 'change') {
109+
setInputText(value);
110+
}
20111
},
21-
[reviewers, updateReviewers],
112+
[setInputText],
22113
);
23114

24-
const handleToggleOpen = useCallback(() => {
25-
setIsOpen(true);
26-
}, [setIsOpen]);
115+
const fetchUsers = useAsyncAbortable(
116+
async (abortSignal) => {
117+
if (inputText.length > 1 && site) {
118+
const results = await debouncedUserFetcher(site, inputText, abortSignal);
119+
return results.filter((user) => !reviewers.some((existing) => existing.accountId === user.accountId));
120+
}
121+
return [];
122+
},
123+
[site, inputText, reviewers],
124+
);
27125

28-
const handleToggleClosed = useCallback(() => {
29-
setIsOpen(false);
30-
}, [setIsOpen]);
126+
const handleUserSelect = useCallback(
127+
async (event: React.ChangeEvent, user: User | null) => {
128+
if (user) {
129+
const updatedReviewers = [...reviewers, user];
130+
await updateReviewers(updatedReviewers);
131+
}
132+
},
133+
[reviewers, updateReviewers],
134+
);
31135

32136
return (
33-
<React.Fragment>
34-
<Tooltip title="Add Reviewers">
35-
<Button color={'primary'} onClick={handleToggleOpen} value={'Add Reviewers'}>
36-
<Typography variant="button">Add Reviewers</Typography>
37-
</Button>
38-
</Tooltip>
39-
<DialogUserPicker
40-
site={site}
41-
users={reviewers}
42-
onChange={handleUpdateReviewers}
43-
hidden={isOpen}
44-
onClose={handleToggleClosed}
137+
<div className={classes.container}>
138+
<AddIcon className={classes.addIcon} />
139+
<Autocomplete
140+
className={classes.autocompleteRoot}
141+
size="small"
142+
options={fetchUsers.result || []}
143+
getOptionLabel={(option) => option?.displayName || ''}
144+
onInputChange={handleInputChange}
145+
onChange={handleUserSelect}
146+
loading={fetchUsers.loading}
147+
renderInput={(params) => (
148+
<TextField
149+
{...params}
150+
variant="outlined"
151+
placeholder="Add reviewer"
152+
InputProps={{
153+
...params.InputProps,
154+
startAdornment: null,
155+
}}
156+
/>
157+
)}
158+
renderOption={(option) => (
159+
<div className={classes.optionContainer}>
160+
<Grid container alignItems="center">
161+
<Grid item className={classes.avatarContainer}>
162+
<Avatar src={option?.avatarUrl} />
163+
</Grid>
164+
<Grid item>
165+
<Typography className={classes.optionText}>{option?.displayName}</Typography>
166+
</Grid>
167+
</Grid>
168+
</div>
169+
)}
45170
/>
46-
</React.Fragment>
171+
</div>
47172
);
48173
};

src/react/atlascode/pullrequest/DialogUserPicker.tsx

Lines changed: 0 additions & 125 deletions
This file was deleted.

0 commit comments

Comments
 (0)