mirror of
https://github.com/harness/drone.git
synced 2025-05-09 20:59:13 +08:00
feat: [code-101]: added dotted lines to conversation page (#354)
This commit is contained in:
parent
c1591a2c6a
commit
f54c23055c
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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> */}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
margin: -24px -24px 0 !important;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
z-index: 4;
|
||||
|
||||
&.merged {
|
||||
border-color: transparent !important;
|
||||
|
Loading…
Reference in New Issue
Block a user