feat: [code-101]: added dotted lines to conversation page (#354)

This commit is contained in:
Calvin Lee 2023-02-24 10:02:24 -07:00 committed by GitHub
parent c1591a2c6a
commit f54c23055c
7 changed files with 198 additions and 94 deletions

View File

@ -1,5 +1,6 @@
.thread {
margin-bottom: var(--spacing-medium) !important;
margin-bottom: var(--spacing-medium);
--layout-spacing: var(--spacing-2) !important;
.content {
padding-left: 25px;
@ -21,3 +22,62 @@
}
}
}
.titleContent {
padding-left: 25px;
position: relative;
> ::before {
position: absolute;
top: 34px;
left: 15px;
content: '';
width: 1px;
height: 28px;
border: 1px dashed var(--grey-200);
opacity: 0.7;
z-index: 2;
}
}
.inCommentBox {
padding-left: 25px;
position: relative;
> ::after {
position: absolute;
bottom: -12px;
left: 15px;
content: '';
width: 1px;
height: 22px;
border: 1px dashed var(--grey-200);
opacity: 0.7;
z-index: 2;
}
}
.threadLessSpace {
margin-bottom: var(--spacing-small) !important;
--layout-spacing: var(--spacing-2) !important;
.content {
padding-left: 25px;
position: relative;
--layout-spacing: var(--spacing-2) !important;
> ::before {
position: absolute;
top: -8px;
left: 7px;
content: '';
width: 1px;
height: calc(100% + 18px);
border: 1px dashed var(--grey-200);
opacity: 0.7;
}
&.hideGutter > ::before {
display: none;
}
}
}

View File

@ -4,5 +4,8 @@ declare const styles: {
readonly thread: string
readonly content: string
readonly hideGutter: string
readonly titleContent: string
readonly inCommentBox: string
readonly threadLessSpace: string
}
export default styles

View File

@ -8,6 +8,9 @@ interface ThreadSectionProps {
className?: string
contentClassName?: string
hideGutter?: boolean
onlyTitle?: boolean
inCommentBox?: boolean
lastItem?: boolean
}
export const ThreadSection: React.FC<ThreadSectionProps> = ({
@ -15,11 +18,18 @@ export const ThreadSection: React.FC<ThreadSectionProps> = ({
children,
className,
contentClassName,
hideGutter
hideGutter,
onlyTitle,
inCommentBox = false,
lastItem
}) => {
return (
<Container className={cx(css.thread, className)}>
<Layout.Vertical spacing="medium">
<Container
className={cx(inCommentBox ? css.thread : css.threadLessSpace, className, {
[css.titleContent]: onlyTitle && !inCommentBox && !lastItem,
[css.inCommentBox]: inCommentBox && !lastItem
})}>
<Layout.Vertical spacing={'medium'}>
{title}
<Container className={cx(css.content, contentClassName, hideGutter ? css.hideGutter : '')}>
{children}

View File

@ -52,6 +52,7 @@
.sortContainer {
border-bottom: 1px solid var(--grey-200);
margin-bottom: var(--spacing-small) !important;
}
.sortDropdown {
@ -62,7 +63,8 @@
}
.mergedBox {
padding: var(--spacing-xlarge) 0 !important;
padding-top: var(--spacing-small) !important;
padding-bottom: var(--spacing-small) !important;
}
.mergeContainer {
@ -136,6 +138,9 @@
display: none !important;
}
}
.hideDottedLine {
z-index: 3;
}
.newCommentCreated {
box-shadow: 0px 0px 5px rgb(37 41 192);

View File

@ -18,6 +18,7 @@ declare const styles: {
readonly title: string
readonly fname: string
readonly snapshotContent: string
readonly hideDottedLine: string
readonly newCommentCreated: string
readonly clear: string
readonly refreshIcon: string

View File

@ -40,6 +40,7 @@ import { DescriptionBox } from './DescriptionBox'
import { PullRequestActionsBox } from './PullRequestActionsBox/PullRequestActionsBox'
import PullRequestSideBar from './PullRequestSideBar/PullRequestSideBar'
import css from './Conversation.module.scss'
import { ThreadSection } from 'components/ThreadSection/ThreadSection'
export interface ConversationProps extends Pick<GitInfoProps, 'repoMetadata' | 'pullRequestMetadata'> {
onCommentUpdate: () => void
@ -280,104 +281,129 @@ export const Conversation: React.FC<ConversationProps> = ({
if (isSystemComment(commentItems)) {
return (
<SystemBox
key={threadId}
pullRequestMetadata={pullRequestMetadata}
commentItems={commentItems}
/>
<ThreadSection
key={`thread-${threadId}`}
onlyTitle
lastItem={activityBlocks.length - 1 === index}
title={
<SystemBox
key={`system-${threadId}`}
pullRequestMetadata={pullRequestMetadata}
commentItems={commentItems}
/>
}></ThreadSection>
)
}
return (
<CommentBox
key={threadId}
fluid
className={cx({
[css.newCommentCreated]: commentCreated && index === activityBlocks.length - 1
})}
getString={getString}
commentItems={commentItems}
currentUserName={currentUser.display_name}
handleAction={async (action, value, commentItem) => {
let result = true
let updatedItem: CommentItem<TypesPullReqActivity> | undefined = undefined
const id = (commentItem as CommentItem<TypesPullReqActivity>)?.payload?.id
<ThreadSection
key={`comment-${threadId}`}
onlyTitle={
activityBlocks[index + 1] !== undefined && isSystemComment(activityBlocks[index + 1])
? true
: false
}
inCommentBox={
activityBlocks[index + 1] !== undefined && isSystemComment(activityBlocks[index + 1])
? true
: false
}
title={
<CommentBox
key={threadId}
fluid
className={cx({
[css.hideDottedLine]: true,
[css.newCommentCreated]: commentCreated && index === activityBlocks.length - 1
})}
getString={getString}
commentItems={commentItems}
currentUserName={currentUser.display_name}
handleAction={async (action, value, commentItem) => {
let result = true
let updatedItem: CommentItem<TypesPullReqActivity> | undefined = undefined
const id = (commentItem as CommentItem<TypesPullReqActivity>)?.payload?.id
switch (action) {
case CommentAction.DELETE:
result = false
await confirmAct({
message: getString('deleteCommentConfirm'),
action: async () => {
await deleteComment({}, { pathParams: { id } })
.then(() => {
result = true
switch (action) {
case CommentAction.DELETE:
result = false
await confirmAct({
message: getString('deleteCommentConfirm'),
action: async () => {
await deleteComment({}, { pathParams: { id } })
.then(() => {
result = true
})
.catch(exception => {
result = false
showError(
getErrorMessage(exception),
0,
getString('pr.failedToDeleteComment')
)
})
}
})
break
case CommentAction.REPLY:
await saveComment({ text: value, parent_id: Number(threadId) })
.then(newComment => {
updatedItem = activityToCommentItem(newComment)
})
.catch(exception => {
result = false
showError(getErrorMessage(exception), 0, getString('pr.failedToDeleteComment'))
showError(getErrorMessage(exception), 0, getString('pr.failedToSaveComment'))
})
}
})
break
break
case CommentAction.REPLY:
await saveComment({ text: value, parent_id: Number(threadId) })
.then(newComment => {
updatedItem = activityToCommentItem(newComment)
})
.catch(exception => {
result = false
showError(getErrorMessage(exception), 0, getString('pr.failedToSaveComment'))
})
break
case CommentAction.UPDATE:
await updateComment({ text: value }, { pathParams: { id } })
.then(newComment => {
updatedItem = activityToCommentItem(newComment)
})
.catch(exception => {
result = false
showError(getErrorMessage(exception), 0, getString('pr.failedToSaveComment'))
})
break
}
case CommentAction.UPDATE:
await updateComment({ text: value }, { pathParams: { id } })
.then(newComment => {
updatedItem = activityToCommentItem(newComment)
})
.catch(exception => {
result = false
showError(getErrorMessage(exception), 0, getString('pr.failedToSaveComment'))
})
break
}
if (result) {
onCommentUpdate()
}
if (result) {
onCommentUpdate()
}
return [result, updatedItem]
}}
outlets={{
[CommentBoxOutletPosition.TOP_OF_FIRST_COMMENT]: isCodeComment(commentItems) && (
<CodeCommentHeader commentItems={commentItems} />
),
[CommentBoxOutletPosition.LEFT_OF_OPTIONS_MENU]: (
<Select
className={css.stateSelect}
items={[
{
label: getString('active'),
value: commentState.ACTIVE
},
{
label: getString('pending'),
value: commentState.PENDING
},
{
label: getString('resolved'),
value: commentState.RESOLVED
}
]}
value={state}
// onChange={(newState)=>{
// state= newState
// }}
/>
)
}}
/>
return [result, updatedItem]
}}
outlets={{
[CommentBoxOutletPosition.TOP_OF_FIRST_COMMENT]: isCodeComment(commentItems) && (
<CodeCommentHeader commentItems={commentItems} />
),
[CommentBoxOutletPosition.LEFT_OF_OPTIONS_MENU]: (
<Select
className={css.stateSelect}
items={[
{
label: getString('active'),
value: commentState.ACTIVE
},
{
label: getString('pending'),
value: commentState.PENDING
},
{
label: getString('resolved'),
value: commentState.RESOLVED
}
]}
value={state}
// onChange={(newState)=>{
// state= newState
// }}
/>
)
}}
/>
}></ThreadSection>
)
})}
@ -542,7 +568,6 @@ const SystemBox: React.FC<SystemBoxProps> = ({ pullRequestMetadata, commentItems
margin={{ left: 'small' }}
padding={{ right: 'small' }}
{...generateReviewDecisionIcon((payload?.payload as Unknown)?.decision)}
/>
{/* </Container> */}

View File

@ -5,7 +5,7 @@
margin: -24px -24px 0 !important;
position: sticky;
top: 0;
z-index: 2;
z-index: 4;
&.merged {
border-color: transparent !important;