Skip to content

Commit

Permalink
Merge branch 'code-comment-new-api' of _OKE5H2PQKOUfzFFDuD4FA/default…
Browse files Browse the repository at this point in the history
…/CODE/gitness (#40)
  • Loading branch information
tan-nhu authored and Harness committed Apr 24, 2023
2 parents 9c995d8 + 0ff7bfa commit 3455405
Show file tree
Hide file tree
Showing 12 changed files with 162 additions and 174 deletions.
81 changes: 45 additions & 36 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,43 +43,52 @@ const App: React.FC<AppProps> = React.memo(function App({
languageLoader(lang).then(setStrings)
}, [lang, setStrings])

// TODO: Workaround to disable editor dark mode (https://github.com/uiwjs/react-markdown-editor#support-dark-modenight-mode)
document.documentElement.setAttribute('data-color-mode', 'light')
const Wrapper: React.FC = useCallback(
props => {
return strings ? (
<Container className={css.main}>
<StringsContextProvider initialStrings={strings}>
<AppErrorBoundary>
<RestfulProvider
base={standalone ? '/' : getConfig('code')}
requestOptions={getRequestOptions}
queryParams={queryParams}
queryParamStringifyOptions={{ skipNulls: true }}
onResponse={response => {
if (!response.ok && response.status === 401) {
on401()
}
}}>
<AppContextProvider
value={{
standalone,
space,
routes,
lang,
on401,
hooks,
currentUser: defaultCurrentUser,
currentUserProfileURL
}}>
<TooltipContextProvider initialTooltipDictionary={tooltipDictionary}>
<ModalProvider>{props.children ? props.children : <RouteDestinations />}</ModalProvider>
</TooltipContextProvider>
</AppContextProvider>
</RestfulProvider>
</AppErrorBoundary>
</StringsContextProvider>
</Container>
) : null
},
[strings] // eslint-disable-line react-hooks/exhaustive-deps
)

useEffect(() => {
AppWrapper = Wrapper
}, [Wrapper])

return strings ? (
<Container className={css.main}>
<StringsContextProvider initialStrings={strings}>
<AppErrorBoundary>
<RestfulProvider
base={standalone ? '/' : getConfig('code')}
requestOptions={getRequestOptions}
queryParams={queryParams}
queryParamStringifyOptions={{ skipNulls: true }}
onResponse={response => {
if (!response.ok && response.status === 401) {
on401()
}
}}>
<AppContextProvider
value={{
standalone,
space,
routes,
lang,
on401,
hooks,
currentUser: defaultCurrentUser,
currentUserProfileURL
}}>
<TooltipContextProvider initialTooltipDictionary={tooltipDictionary}>
<ModalProvider>{children ? children : <RouteDestinations />}</ModalProvider>
</TooltipContextProvider>
</AppContextProvider>
</RestfulProvider>
</AppErrorBoundary>
</StringsContextProvider>
</Container>
) : null
return <Wrapper>{children}</Wrapper>
})

export let AppWrapper: React.FC = () => <Container />
export default App
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const ReviewSplitButton = (props: ReviewSplitButtonProps) => {
refreshPr?.()
})
.catch(exception => showError(getErrorMessage(exception)))
}, [decisionOption, mutate, showError, showSuccess, getString])
}, [decisionOption, mutate, showError, showSuccess, getString, refreshPr])
return (
<Container className={cx(css.btn, { [css.hide]: shouldHide })}>
<SplitButton
Expand Down
13 changes: 5 additions & 8 deletions web/src/components/CommentBox/CommentBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
import cx from 'classnames'
import ReactTimeago from 'react-timeago'
import { noop } from 'lodash-es'
import type { UseStringsReturn } from 'framework/strings'
import { useStrings } from 'framework/strings'
import { ThreadSection } from 'components/ThreadSection/ThreadSection'
import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator'
import { useAppContext } from 'AppContext'
Expand Down Expand Up @@ -54,7 +54,6 @@ export enum CommentBoxOutletPosition {

interface CommentBoxProps<T> {
className?: string
getString: UseStringsReturn['getString']
onHeightChange?: (height: number) => void
initialContent?: string
width?: string
Expand All @@ -74,7 +73,6 @@ interface CommentBoxProps<T> {

export const CommentBox = <T = unknown,>({
className,
getString,
onHeightChange = noop,
initialContent = '',
width,
Expand All @@ -87,6 +85,7 @@ export const CommentBox = <T = unknown,>({
resetOnSave,
outlets = {}
}: CommentBoxProps<T>) => {
const { getString } = useStrings()
const [comments, setComments] = useState<CommentItem<T>[]>(commentItems)
const [showReplyPlaceHolder, setShowReplyPlaceHolder] = useState(!!comments.length)
const [markdown, setMarkdown] = useState(initialContent)
Expand Down Expand Up @@ -130,7 +129,6 @@ export const CommentBox = <T = unknown,>({
<Layout.Vertical>
<CommentsThread<T>
commentItems={comments}
getString={getString}
onQuote={onQuote}
handleAction={async (action, content, atCommentItem) => {
const [result, updatedItem] = await handleAction(action, content, atCommentItem)
Expand Down Expand Up @@ -211,18 +209,17 @@ export const CommentBox = <T = unknown,>({
)
}

interface CommentsThreadProps<T>
extends Pick<CommentBoxProps<T>, 'commentItems' | 'getString' | 'handleAction' | 'outlets'> {
interface CommentsThreadProps<T> extends Pick<CommentBoxProps<T>, 'commentItems' | 'handleAction' | 'outlets'> {
onQuote: (content: string) => void
}

const CommentsThread = <T = unknown,>({
getString,
onQuote,
commentItems = [],
handleAction,
outlets = {}
}: CommentsThreadProps<T>) => {
const { getString } = useStrings()
const { standalone } = useAppContext()
const [editIndexes, setEditIndexes] = useState<Record<number, boolean>>({})
const resetStateAtIndex = useCallback(
Expand Down Expand Up @@ -350,7 +347,7 @@ const CommentsThread = <T = unknown,>({
<Text className={css.deleted}>{getString('commentDeleted')}</Text>
</Truthy>
<Else>
<MarkdownViewer source={commentItem?.content} getString={getString} />
<MarkdownViewer source={commentItem?.content} />
</Else>
</Match>
</Else>
Expand Down
192 changes: 97 additions & 95 deletions web/src/components/DiffViewer/DiffViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { useAppContext } from 'AppContext'
import type { TypesPullReq, TypesPullReqActivity } from 'services/code'
import { getErrorMessage } from 'utils/Utils'
import { CopyButton } from 'components/CopyButton/CopyButton'
import { AppWrapper } from 'App'
import {
activitiesToDiffCommentItems,
activityToCommentItem,
Expand Down Expand Up @@ -278,121 +279,122 @@ export const DiffViewer: React.FC<DiffViewerProps> = ({
// the above rules as well (i.e useString as a prop instead of importing)
ReactDOM.unmountComponentAtNode(element as HTMLDivElement)
ReactDOM.render(
<CommentBox
commentItems={comment.commentItems}
initialContent={getInitialCommentContentFromSelection(diff)}
getString={getString}
width={isSideBySide ? 'calc(100vw / 2 - 163px)' : undefined} // TODO: Re-calcualte for standalone version
onHeightChange={boxHeight => {
if (comment.height !== boxHeight) {
comment.height = boxHeight
setTimeout(() => setComments([...commentsRef.current]), 0)
}
}}
onCancel={() => {
// Clean up CommentBox rendering and reset states bound to lineInfo
ReactDOM.unmountComponentAtNode(element as HTMLDivElement)
commentRowElement.parentElement?.removeChild(commentRowElement)
lineInfo.oppositeRowElement?.parentElement?.removeChild(
lineInfo.oppositeRowElement?.nextElementSibling as Element
)
delete lineInfo.rowElement.dataset.annotated
setTimeout(() => setComments(commentsRef.current.filter(item => item !== comment)), 0)
}}
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.NEW: {
// lineNumberRange can be used to allow multiple-line selection when commenting in the future
const lineNumberRange = [comment.lineNumber]
const payload: PullRequestCodeCommentPayload = {
type: CommentType.CODE_COMMENT,
version: PR_CODE_COMMENT_PAYLOAD_VERSION,
file_id: diff.fileId,
file_title: diff.fileTitle,
language: diff.language || '',
is_on_left: comment.left,
at_line_number: comment.lineNumber,
line_number_range: lineNumberRange,
range_text_content: getRawTextInRange(diff, lineNumberRange),
diff_html_snapshot: getDiffHTMLSnapshotFromRow(rowElement)
}

await saveComment({ type: CommentType.CODE_COMMENT, text: value, payload })
.then((newComment: TypesPullReqActivity) => {
updatedItem = activityToCommentItem(newComment)
})
.catch(exception => {
result = false
showError(getErrorMessage(exception), 0)
})
break
<AppWrapper>
<CommentBox
commentItems={comment.commentItems}
initialContent={getInitialCommentContentFromSelection(diff)}
width={isSideBySide ? 'calc(100vw / 2 - 163px)' : undefined} // TODO: Re-calcualte for standalone version
onHeightChange={boxHeight => {
if (comment.height !== boxHeight) {
comment.height = boxHeight
setTimeout(() => setComments([...commentsRef.current]), 0)
}

case CommentAction.REPLY: {
const parentComment = diff.fileActivities?.find(
activity => (activity.payload as PullRequestCodeCommentPayload).file_id === diff.fileId
)

if (parentComment) {
await saveComment({
}}
onCancel={() => {
// Clean up CommentBox rendering and reset states bound to lineInfo
ReactDOM.unmountComponentAtNode(element as HTMLDivElement)
commentRowElement.parentElement?.removeChild(commentRowElement)
lineInfo.oppositeRowElement?.parentElement?.removeChild(
lineInfo.oppositeRowElement?.nextElementSibling as Element
)
delete lineInfo.rowElement.dataset.annotated
setTimeout(() => setComments(commentsRef.current.filter(item => item !== comment)), 0)
}}
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.NEW: {
// lineNumberRange can be used to allow multiple-line selection when commenting in the future
const lineNumberRange = [comment.lineNumber]
const payload: PullRequestCodeCommentPayload = {
type: CommentType.CODE_COMMENT,
text: value,
parent_id: Number(parentComment.id as number)
})
.then(newComment => {
version: PR_CODE_COMMENT_PAYLOAD_VERSION,
file_id: diff.fileId,
file_title: diff.fileTitle,
language: diff.language || '',
is_on_left: comment.left,
at_line_number: comment.lineNumber,
line_number_range: lineNumberRange,
range_text_content: getRawTextInRange(diff, lineNumberRange),
diff_html_snapshot: getDiffHTMLSnapshotFromRow(rowElement)
}

await saveComment({ type: CommentType.CODE_COMMENT, text: value, payload })
.then((newComment: TypesPullReqActivity) => {
updatedItem = activityToCommentItem(newComment)
})
.catch(exception => {
result = false
showError(getErrorMessage(exception), 0)
})
break
}
break
}

case CommentAction.DELETE: {
result = false
await confirmAct({
message: getString('deleteCommentConfirm'),
action: async () => {
await deleteComment({}, { pathParams: { id } })
.then(() => {
result = true
case CommentAction.REPLY: {
const parentComment = diff.fileActivities?.find(
activity => (activity.payload as PullRequestCodeCommentPayload).file_id === diff.fileId
)

if (parentComment) {
await saveComment({
type: CommentType.CODE_COMMENT,
text: value,
parent_id: Number(parentComment.id as number)
})
.then(newComment => {
updatedItem = activityToCommentItem(newComment)
})
.catch(exception => {
result = false
showError(getErrorMessage(exception), 0, getString('pr.failedToDeleteComment'))
showError(getErrorMessage(exception), 0)
})
}
})
break
}
break
}

case CommentAction.UPDATE: {
await updateComment({ text: value }, { pathParams: { id } })
.then(newComment => {
updatedItem = activityToCommentItem(newComment)
})
.catch(exception => {
result = false
showError(getErrorMessage(exception), 0)
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
break
}

case CommentAction.UPDATE: {
await updateComment({ text: value }, { pathParams: { id } })
.then(newComment => {
updatedItem = activityToCommentItem(newComment)
})
.catch(exception => {
result = false
showError(getErrorMessage(exception), 0)
})
break
}
}
}

if (result) {
onCommentUpdate()
}
if (result) {
onCommentUpdate()
}

return [result, updatedItem]
}}
/>,
return [result, updatedItem]
}}
/>
</AppWrapper>,
element
)

Expand Down
Loading

0 comments on commit 3455405

Please sign in to comment.