1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

first draft of the comments ui (#2440)

This commit is contained in:
Mateusz Kwasniewski 2022-11-16 11:45:27 +01:00 committed by GitHub
parent 8dac08c5aa
commit 51ad239553
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 165 additions and 4 deletions

View File

@ -0,0 +1,44 @@
import { FC } from 'react';
import { Box, Button, styled, TextField } from '@mui/material';
import { StyledAvatar } from './StyledAvatar';
const AddCommentWrapper = styled(Box)(({ theme }) => ({
display: 'flex',
gap: theme.spacing(2),
marginTop: theme.spacing(2),
marginBottom: theme.spacing(1),
}));
export const AddCommentField: FC<{
imageUrl: string;
commentText: string;
onAddComment: () => void;
onTypeComment: (text: string) => void;
}> = ({ imageUrl, commentText, onTypeComment, onAddComment }) => (
<>
<AddCommentWrapper>
<StyledAvatar src={imageUrl} />
<TextField
variant="outlined"
placeholder="Add your comment here"
fullWidth
multiline
minRows={2}
onChange={e => onTypeComment(e.target.value)}
value={commentText}
/>
</AddCommentWrapper>
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button
variant="outlined"
onClick={onAddComment}
disabled={
commentText.trim().length === 0 ||
commentText.trim().length > 1000
}
>
Comment
</Button>
</Box>
</>
);

View File

@ -0,0 +1,47 @@
import { FC } from 'react';
import Paper from '@mui/material/Paper';
import { Box, styled, Typography } from '@mui/material';
import TimeAgo from 'react-timeago';
import { StyledAvatar } from './StyledAvatar';
import { IChangeRequestComment } from '../../changeRequest.types';
const ChangeRequestCommentWrapper = styled(Box)(({ theme }) => ({
display: 'flex',
gap: theme.spacing(2),
marginTop: theme.spacing(2),
}));
const CommentPaper = styled(Paper)(({ theme }) => ({
width: '100%',
padding: theme.spacing(2),
backgroundColor: theme.palette.tertiary.light,
}));
const CommentHeader = styled(Box)(({ theme }) => ({
display: 'flex',
borderBottom: '1px solid',
borderColor: theme.palette.divider,
paddingBottom: theme.spacing(1),
}));
export const ChangeRequestComment: FC<{ comment: IChangeRequestComment }> = ({
comment,
}) => (
<ChangeRequestCommentWrapper>
<StyledAvatar src={comment.createdBy.imageUrl} />
<CommentPaper variant="outlined">
<CommentHeader>
<Box>
<strong>{comment.createdBy.username}</strong>{' '}
<Typography color="text.secondary" component="span">
commented{' '}
<TimeAgo
minPeriod={60}
date={new Date(comment.createdAt)}
/>
</Typography>
</Box>
</CommentHeader>
<Box sx={{ paddingTop: 2 }}>{comment.text}</Box>
</CommentPaper>
</ChangeRequestCommentWrapper>
);

View File

@ -0,0 +1,7 @@
import { Avatar, styled } from '@mui/material';
export const StyledAvatar = styled(Avatar)(({ theme }) => ({
height: '30px',
width: '30px',
marginTop: theme.spacing(1),
}));

View File

@ -1,5 +1,5 @@
import { Alert, styled } from '@mui/material';
import { FC, useContext } from 'react';
import { Alert, Button, styled, TextField, Typography } from '@mui/material';
import { FC, useContext, useState } from 'react';
import { Box } from '@mui/material';
import { useChangeRequest } from 'hooks/api/getters/useChangeRequest/useChangeRequest';
import { ChangeRequestHeader } from './ChangeRequestHeader/ChangeRequestHeader';
@ -19,6 +19,14 @@ import PermissionButton from 'component/common/PermissionButton/PermissionButton
import { APPLY_CHANGE_REQUEST } from 'component/providers/AccessProvider/permissions';
import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser';
import AccessContext from 'contexts/AccessContext';
import {
StyledAvatar,
StyledCard,
} from './ChangeRequestHeader/ChangeRequestHeader.styles';
import TimeAgo from 'react-timeago';
import { InputProps as StandardInputProps } from '@mui/material/Input/Input';
import { ChangeRequestComment } from './ChangeRequestComments/ChangeRequestComment';
import { AddCommentField } from './ChangeRequestComments/AddCommentField';
const StyledAsideBox = styled(Box)(({ theme }) => ({
width: '30%',
@ -48,13 +56,14 @@ export const ChangeRequestOverview: FC = () => {
const projectId = useRequiredPathParam('projectId');
const { user } = useAuthUser();
const { isAdmin } = useContext(AccessContext);
const [commentText, setCommentText] = useState('');
const id = useRequiredPathParam('id');
const { data: changeRequest, refetchChangeRequest } = useChangeRequest(
projectId,
id
);
const { changeState } = useChangeRequestApi();
const { changeState, addComment } = useChangeRequestApi();
const { setToastData, setToastApiError } = useToast();
if (!changeRequest) {
@ -77,6 +86,21 @@ export const ChangeRequestOverview: FC = () => {
}
};
const onAddComment = async () => {
try {
await addComment(projectId, id, commentText);
setCommentText('');
refetchChangeRequest();
setToastData({
type: 'success',
title: 'Success',
text: 'Comment added',
});
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
}
};
const isSelfReview =
changeRequest?.createdBy.id === user?.id &&
changeRequest.state === 'In review' &&
@ -109,6 +133,18 @@ export const ChangeRequestOverview: FC = () => {
<StyledInnerContainer>
Changes
<ChangeRequest changeRequest={changeRequest} />
{changeRequest.comments?.map(comment => (
<ChangeRequestComment
key={comment.id}
comment={comment}
/>
))}
<AddCommentField
imageUrl={changeRequest?.createdBy?.imageUrl}
commentText={commentText}
onAddComment={onAddComment}
onTypeComment={setCommentText}
/>
<ConditionallyRender
condition={isSelfReview}
show={

View File

@ -68,7 +68,7 @@ const DraftBannerContent: FC<{
const StickyBanner = styled(Box)(({ theme }) => ({
position: 'sticky',
top: -1,
zIndex: 200 /* has to lower than header.zIndex */,
zIndex: 250 /* has to lower than header.zIndex and higher than body.zIndex */,
borderTop: `1px solid ${theme.palette.warning.border}`,
borderBottom: `1px solid ${theme.palette.warning.border}`,
backgroundColor: theme.palette.warning.light,

View File

@ -10,6 +10,7 @@ export interface IChangeRequest {
createdAt: Date;
features: IChangeRequestFeature[];
approvals: IChangeRequestApproval[];
comments: IChangeRequestComment[];
conflict?: string;
}
@ -30,6 +31,13 @@ export interface IChangeRequestApproval {
createdAt: Date;
}
export interface IChangeRequestComment {
text: string;
createdBy: Pick<IUser, 'username' | 'imageUrl'>;
createdAt: Date;
id: string;
}
export interface IChangeRequestBase {
id: number;
action: ChangeRequestAction;

View File

@ -98,12 +98,31 @@ export const useChangeRequestApi = () => {
}
};
const addComment = async (
projectId: string,
changeSetId: string,
text: string
) => {
const path = `/api/admin/projects/${projectId}/change-requests/${changeSetId}/comments`;
const req = createRequest(path, {
method: 'POST',
body: JSON.stringify({ text }),
});
try {
return await makeRequest(req.caller, req.id);
} catch (e) {
throw e;
}
};
return {
addChangeRequest,
changeState,
discardChangeRequestEvent,
updateChangeRequestEnvironmentConfig,
discardDraft,
addComment,
errors,
loading,
};