feat: [CODE-298]: Code Comment API integration + Optimize PR polling + implement unchecked status

This commit is contained in:
“tan-nhu” 2023-05-10 02:13:52 -07:00
parent f3eed8ba00
commit 4e18c009bb
17 changed files with 186 additions and 176 deletions

View File

@ -7,8 +7,7 @@ import {
Text,
StringSubstitute,
Button,
PageError,
ButtonSize
PageError
} from '@harness/uicore'
import { Match, Case, Render } from 'react-jsx-match'
import * as Diff2Html from 'diff2html'
@ -47,7 +46,6 @@ interface ChangesProps extends Pick<GitInfoProps, 'repoMetadata'> {
className?: string
onCommentUpdate: () => void
prHasChanged?: boolean
handleRefresh?: () => void
}
export const Changes: React.FC<ChangesProps> = ({
@ -60,8 +58,7 @@ export const Changes: React.FC<ChangesProps> = ({
pullRequestMetadata,
onCommentUpdate,
className,
prHasChanged,
handleRefresh
prHasChanged
}) => {
const { getString } = useStrings()
const [viewStyle, setViewStyle] = useUserPreference(UserPreference.DIFF_VIEW_STYLE, ViewStyle.SIDE_BY_SIDE)
@ -84,8 +81,8 @@ export const Changes: React.FC<ChangesProps> = ({
const {
data: activities,
loading: loadingActivities,
error: errorActivities
// refetch: refetchActivities
error: errorActivities,
refetch: refetchActivities
} = useGet<TypesPullReqActivity[]>({
path: `/api/v1/repos/${repoMetadata.path}/+/pullreq/${pullRequestMetadata?.number}/activities`,
lazy: !pullRequestMetadata?.number
@ -104,6 +101,12 @@ export const Changes: React.FC<ChangesProps> = ({
[diffs]
)
useEffect(() => {
if (prHasChanged) {
refetchActivities()
}
}, [prHasChanged, refetchActivities])
useEffect(() => {
const _raw = rawDiff && typeof rawDiff === 'string' ? rawDiff : ''
@ -115,7 +118,7 @@ export const Changes: React.FC<ChangesProps> = ({
const contentId = `content-${fileId}`
const filePath = diff.isDeleted ? diff.oldName : diff.newName
const fileActivities: TypesPullReqActivity[] | undefined = activities?.filter(
activity => filePath === activity.code_comment_path
activity => filePath === activity.code_comment?.path
)
return {
@ -171,18 +174,6 @@ export const Changes: React.FC<ChangesProps> = ({
}}
/>
</Text>
{!prHasChanged ? null : (
<Button
onClick={handleRefresh}
iconProps={{ className: css.refreshIcon, size: 12 }}
icon="repeat"
text={getString('refresh')}
variation={ButtonVariation.SECONDARY}
size={ButtonSize.SMALL}
padding={{ left: 'small' }}
className={css.repeatBtn}
/>
)}
{/* Show "Scroll to top" button */}
<Render when={isSticky}>

View File

@ -333,7 +333,7 @@ export const DiffViewer: React.FC<DiffViewerProps> = ({
case CommentAction.REPLY: {
const parentComment = diff.fileActivities?.find(
activity => diff.filePath === activity.code_comment_path
activity => diff.filePath === activity.code_comment?.path
)
if (parentComment) {

View File

@ -1,7 +1,6 @@
import type * as Diff2Html from 'diff2html'
// import { Diff2HtmlUI } from 'diff2html/lib-esm/ui/js/diff2html-ui'
import HoganJsUtils from 'diff2html/lib/hoganjs-utils'
// import type { DiffLine } from 'diff2html/lib/types'
import { get } from 'lodash-es'
import type { CommentItem } from 'components/CommentBox/CommentBox'
import type { TypesPullReqActivity } from 'services/code'
import type { DiffFileEntry } from 'utils/types'
@ -208,14 +207,13 @@ export function activitiesToDiffCommentItems(diff: DiffFileEntry): DiffCommentIt
diff.activities
?.filter(replyActivity => replyActivity.parent_id === activity.id)
.map(_activity => activityToCommentItem(_activity)) || []
// TODO: Use backend support when it's ready https://harness.slack.com/archives/C03Q1Q4C9J8/p1682609265294089
const left = activity.payload?.line_start_new || false
const right = get(activity.payload, 'line_start_new', false)
return {
left,
right: !left,
left: !right,
right,
height: 0,
lineNumber: (left ? activity.code_comment_line_old : activity.code_comment_line_new) as number,
lineNumber: (right ? activity.code_comment?.line_new : activity.code_comment?.line_old) as number,
commentItems: [activityToCommentItem(activity)].concat(replyComments)
}
}) || []

View File

@ -192,6 +192,7 @@ export interface StringsMap {
'pr.branchHasNoConflicts': string
'pr.cantBeMerged': string
'pr.cantMerge': string
'pr.checkingToMerge': string
'pr.createDraftPR': string
'pr.descriptionPlaceHolder': string
'pr.diffStatsLabel': string

View File

@ -184,6 +184,7 @@ pr:
reviewChanges: Review changes
mergePR: Merge pull request
branchHasNoConflicts: This branch has no conflicts with the base branch
checkingToMerge: Checking for ability to merge automatically...
prCanBeMerged: Mergeing can be performed automatically.
enterDesc: Enter description here
failedToUpdate: Failed to update Pull Request. Please try again.

View File

@ -5,6 +5,8 @@ import PrRejected from 'images/pull-request-rejected.svg'
import PrDraft from 'images/pull-request-draft.svg'
import EmptyState from 'images/empty-state.svg'
import error404 from 'images/404-error.svg'
import PrUnchecked from 'images/pull-request-unchecked.svg'
export const Images = {
PrOpen,
PrMerged,
@ -12,5 +14,6 @@ export const Images = {
PrRejected,
PrDraft,
error404,
EmptyState
EmptyState,
PrUnchecked
}

View File

@ -0,0 +1 @@
<svg fill="none" viewBox="0 0 24 25" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><filter id="a" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="24" width="24" x="0" y=".5"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feColorMatrix in="SourceAlpha" result="hardAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/><feOffset dy=".5"/><feGaussianBlur stdDeviation="1"/><feColorMatrix type="matrix" values="0 0 0 0 0.376471 0 0 0 0 0.380392 0 0 0 0 0.439216 0 0 0 0.16 0"/><feBlend in2="BackgroundImageFix" mode="normal" result="effect1_dropShadow_3325_360836"/><feColorMatrix in="SourceAlpha" result="hardAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/><feOffset/><feGaussianBlur stdDeviation=".5"/><feColorMatrix type="matrix" values="0 0 0 0 0.156863 0 0 0 0 0.160784 0 0 0 0 0.239216 0 0 0 0.08 0"/><feBlend in2="effect1_dropShadow_3325_360836" mode="normal" result="effect2_dropShadow_3325_360836"/><feBlend in="SourceGraphic" in2="effect2_dropShadow_3325_360836" mode="normal" result="shape"/></filter><clipPath id="b"><path d="m4.5 3.25h16.25v16.25h-16.25z"/></clipPath><clipPath id="c"><path d="m4.875 4.5h15v15h-15z"/></clipPath><g filter="url(#a)"><circle cx="12" cy="12" fill="#fff" r="10"/></g><circle cx="12" cy="12" fill="#ff7020" r="9.375"/><g clip-path="url(#b)"><g clip-path="url(#c)"><path d="m12.3687 5.75c-3.44995 0-6.2437 2.8-6.2437 6.25s2.79375 6.25 6.2437 6.25c3.4563 0 6.2563-2.8 6.2563-6.25s-2.8-6.25-6.2563-6.25zm.0063 11.25c-2.7625 0-5-2.2375-5-5s2.2375-5 5-5 5 2.2375 5 5-2.2375 5-5 5zm.3125-8.125h-.9375v3.75l3.2812 1.9688.4688-.7688-2.8125-1.6688z" fill="#fff"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -1,9 +1,6 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import {
Avatar,
Button,
ButtonSize,
ButtonVariation,
Color,
Container,
FlexExpander,
@ -44,7 +41,6 @@ import css from './Conversation.module.scss'
export interface ConversationProps extends Pick<GitInfoProps, 'repoMetadata' | 'pullRequestMetadata'> {
onCommentUpdate: () => void
prHasChanged?: boolean
handleRefresh?: () => void
}
export enum prSortState {
@ -58,8 +54,7 @@ export const Conversation: React.FC<ConversationProps> = ({
repoMetadata,
pullRequestMetadata,
onCommentUpdate,
prHasChanged,
handleRefresh
prHasChanged
}) => {
const { getString } = useStrings()
const { currentUser } = useAppContext()
@ -76,9 +71,7 @@ export const Conversation: React.FC<ConversationProps> = ({
})
const { showError } = useToaster()
const [newComments, setNewComments] = useState<TypesPullReqActivity[]>([])
const [dateOrderSort, setDateOrderSort] = useState<boolean | 'desc' | 'asc'>(orderSortDate.ASC)
const [prShowState, setPrShowState] = useState<SelectOption>({
label: `Show Everything `,
value: 'showEverything'
@ -178,12 +171,17 @@ export const Conversation: React.FC<ConversationProps> = ({
const [commentCreated, setCommentCreated] = useState(false)
const [dirtyNewComment, setDirtyNewComment] = useState(false)
const [dirtyCurrentComments, setDirtyCurrentComments] = useState(false)
const refreshPR = useCallback(() => {
const onPRStateChanged = useCallback(() => {
onCommentUpdate()
refetchActivities()
}, [onCommentUpdate, refetchActivities])
useEffect(() => {
if (prHasChanged) {
refetchActivities()
}
}, [prHasChanged, refetchActivities])
useAnimateNewCommentBox(commentCreated, setCommentCreated)
return (
@ -193,24 +191,9 @@ export const Conversation: React.FC<ConversationProps> = ({
<PullRequestActionsBox
repoMetadata={repoMetadata}
pullRequestMetadata={pullRequestMetadata}
onPRStateChanged={refreshPR}
onPRStateChanged={onPRStateChanged}
/>
<Container>
<Layout.Horizontal width={`70%`}>
<FlexExpander />
{!prHasChanged ? null : (
<Button
onClick={handleRefresh}
iconProps={{ className: css.refreshIcon, size: 12 }}
icon="repeat"
text={getString('refresh')}
variation={ButtonVariation.SECONDARY}
size={ButtonSize.SMALL}
margin={{ bottom: 'small' }}
/>
)}
</Layout.Horizontal>
<Layout.Horizontal>
<Container width={`70%`}>
<Layout.Vertical spacing="xlarge">
@ -378,7 +361,7 @@ export const Conversation: React.FC<ConversationProps> = ({
}}
outlets={{
[CommentBoxOutletPosition.TOP_OF_FIRST_COMMENT]: isCodeComment(commentItems) && (
<CodeCommentHeader commentItems={commentItems} />
<CodeCommentHeader commentItems={commentItems} threadId={threadId} />
),
[CommentBoxOutletPosition.LEFT_OF_OPTIONS_MENU]: (
<Select
@ -456,20 +439,23 @@ function isCodeComment(commentItems: CommentItem<TypesPullReqActivity>[]) {
interface CodeCommentHeaderProps {
commentItems: CommentItem<TypesPullReqActivity>[]
threadId: number | undefined
}
const CodeCommentHeader: React.FC<CodeCommentHeaderProps> = ({ commentItems }) => {
const CodeCommentHeader: React.FC<CodeCommentHeaderProps> = ({ commentItems, threadId }) => {
const _isCodeComment = isCodeComment(commentItems)
const id = `code-comment-snapshot-${commentItems[0]?.payload?.code_comment_path}`
const id = `code-comment-snapshot-${threadId}`
useEffect(() => {
if (_isCodeComment) {
// Note: Since payload does not have information about the file path, mode, and index, and we
// don't render them anyway in the UI, we just use dummy info for them.
const codeDiffSnapshot = [
`diff --git a/hello-world.md b/hello-world.md`,
`diff --git a/src b/dest`,
`new file mode 100644`,
'index 0000000..0000000',
'--- /dev/null',
'+++ b/hello-world.md',
'--- a/src',
'+++ b/dest',
get(commentItems[0], 'payload.payload.title', ''),
...get(commentItems[0], 'payload.payload.lines', [])
].join('\n')
@ -480,14 +466,14 @@ const CodeCommentHeader: React.FC<CodeCommentHeaderProps> = ({ commentItems }) =
Object.assign({}, DIFF2HTML_CONFIG, { outputFormat: ViewStyle.LINE_BY_LINE })
).draw()
}
}, [id, commentItems, _isCodeComment])
}, [id, commentItems, _isCodeComment, threadId])
return _isCodeComment ? (
<Container className={css.snapshot}>
<Layout.Vertical>
<Container className={css.title}>
<Text inline className={css.fname}>
{commentItems[0].payload?.code_comment_path}
{commentItems[0].payload?.code_comment?.path}
</Text>
</Container>
<Container className={css.snapshotContent} id={id} />
@ -568,13 +554,11 @@ const SystemBox: React.FC<SystemBoxProps> = ({ pullRequestMetadata, commentItems
return (
<Container>
<Layout.Horizontal spacing="small" style={{ alignItems: 'center' }} className={css.mergedBox}>
{/* <Container width={24} height={24} className={css.mergeContainer}> */}
<Icon
margin={{ left: 'small' }}
padding={{ right: 'small' }}
{...generateReviewDecisionIcon((payload?.payload as Unknown)?.decision)}
/>
{/* </Container> */}
<Avatar name={payload?.author?.display_name as string} size="small" hoverCard={false} />
<Text color={Color.GREY_500}>

View File

@ -16,6 +16,10 @@
background-color: var(--red-50) !important;
}
&.unchecked {
background-color: #fcf4e3 !important; // Note: No UICore color variable for this background
}
.layout {
height: var(--bar-height);
padding: 0 var(--spacing-xlarge) !important;
@ -43,6 +47,11 @@
font-size: 13px !important;
line-height: 20px !important;
color: var(--grey-700) !important;
&.unchecked {
color: #c05809 !important; // Note: No UICore color variable for this text
font-weight: 600 !important;
}
}
}
@ -86,7 +95,8 @@
--background-color-active: var(--grey-100) !important;
}
a, button {
a,
button {
--background-color: var(--green-800) !important;
--background-color-hover: var(--green-900) !important;
--background-color-active: var(--green-900) !important;

View File

@ -4,6 +4,7 @@ declare const styles: {
readonly main: string
readonly merged: string
readonly error: string
readonly unchecked: string
readonly layout: string
readonly secondaryButton: string
readonly btn: string

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useMemo, useState } from 'react'
import {
Button,
ButtonVariation,
@ -28,7 +28,8 @@ import { useStrings } from 'framework/strings'
import { CodeIcon, GitInfoProps, PullRequestFilterOption, PullRequestState } from 'utils/GitUtils'
import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
import { useAppContext } from 'AppContext'
import { getErrorMessage, permissionProps } from 'utils/Utils'
import { Images } from 'images'
import { getErrorMessage, MergeCheckStatus, permissionProps } from 'utils/Utils'
import ReviewSplitButton from 'components/Changes/ReviewSplitButton/ReviewSplitButton'
import css from './PullRequestActionsBox.module.scss'
@ -60,7 +61,14 @@ export const PullRequestActionsBox: React.FC<PullRequestActionsBoxProps> = ({
verb: 'POST',
path: `/api/v1/repos/${repoMetadata.path}/+/pullreq/${pullRequestMetadata.number}/state`
})
const mergeable = pullRequestMetadata.merge_check_status === 'mergeable'
const mergeable = useMemo(
() => pullRequestMetadata.merge_check_status === MergeCheckStatus.MERGEABLE,
[pullRequestMetadata]
)
const unchecked = useMemo(
() => pullRequestMetadata.merge_check_status === MergeCheckStatus.UNCHCKED,
[pullRequestMetadata]
)
const isDraft = pullRequestMetadata.is_draft
const mergeOptions: PRMergeOption[] = [
{
@ -104,19 +112,28 @@ export const PullRequestActionsBox: React.FC<PullRequestActionsBoxProps> = ({
return (
<Container
className={cx(css.main, {
[css.error]: mergeable === false
[css.error]: mergeable === false && !unchecked,
[css.unchecked]: unchecked
})}>
<Layout.Vertical spacing="xlarge">
<Container>
<Layout.Horizontal spacing="small" flex={{ alignItems: 'center' }} className={css.layout}>
<Icon
name={isDraft ? CodeIcon.Draft : mergeable === false ? 'warning-sign' : 'tick-circle'}
size={20}
color={isDraft ? Color.ORANGE_900 : mergeable === false ? Color.RED_500 : Color.GREEN_700}
/>
<Text className={css.sub}>
{(unchecked && <img src={Images.PrUnchecked} width={20} height={20} />) || (
<Icon
name={isDraft ? CodeIcon.Draft : mergeable === false ? 'warning-sign' : 'tick-circle'}
size={20}
color={isDraft ? Color.ORANGE_900 : mergeable === false ? Color.RED_500 : Color.GREEN_700}
/>
)}
<Text className={cx(css.sub, { [css.unchecked]: unchecked })}>
{getString(
isDraft ? 'prState.draftHeading' : mergeable === false ? 'pr.cantBeMerged' : 'pr.branchHasNoConflicts'
isDraft
? 'prState.draftHeading'
: unchecked
? 'pr.checkingToMerge'
: mergeable === false
? 'pr.cantBeMerged'
: 'pr.branchHasNoConflicts'
)}
</Text>

View File

@ -23,9 +23,9 @@ import { useAppContext } from 'AppContext'
import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata'
import { useStrings } from 'framework/strings'
import { RepositoryPageHeader } from 'components/RepositoryPageHeader/RepositoryPageHeader'
import { voidFn, getErrorMessage, PR_POLLING_LIMIT } from 'utils/Utils'
import { voidFn, getErrorMessage, MergeCheckStatus } from 'utils/Utils'
import { CodeIcon, GitInfoProps } from 'utils/GitUtils'
import type { TypesPullReq, TypesRepository } from 'services/code'
import type { TypesPullReq, TypesPullReqStats, TypesRepository } from 'services/code'
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
import { PullRequestMetaLine } from './PullRequestMetaLine'
import { Conversation } from './Conversation/Conversation'
@ -34,18 +34,10 @@ import { Changes } from '../../components/Changes/Changes'
import { PullRequestCommits } from './PullRequestCommits/PullRequestCommits'
import css from './PullRequest.module.scss'
enum PullRequestSection {
CONVERSATION = 'conversation',
COMMITS = 'commits',
FILES_CHANGED = 'changes',
CHECKS = 'checks'
}
export default function PullRequest() {
const history = useHistory()
const { getString } = useStrings()
const { routes } = useAppContext()
const [prHasChanged, setPrHasChanged] = useState(false)
const {
repoMetadata,
error,
@ -54,49 +46,59 @@ export default function PullRequest() {
pullRequestId,
pullRequestSection = PullRequestSection.CONVERSATION
} = useGetRepositoryMetadata()
const path = useMemo(
() => `/api/v1/repos/${repoMetadata?.path}/+/pullreq/${pullRequestId}`,
[repoMetadata?.path, pullRequestId]
)
const {
data: prData,
error: prError,
loading: prLoading,
refetch: refetchPullRequest
} = useGet<TypesPullReq>({
path: `/api/v1/repos/${repoMetadata?.path}/+/pullreq/${pullRequestId}`,
path,
lazy: !repoMetadata
})
const {
data: pollPrData,
error: pollPrError,
refetch: refetchPollPullRequest
} = useGet<TypesPullReq>({
path: `/api/v1/repos/${repoMetadata?.path}/+/pullreq/${pullRequestId}`,
lazy: !repoMetadata
})
const [newPrData, setNewPrData] = useState<TypesPullReq>()
const handleRefresh = () => {
refetchPullRequest()
setNewPrData(prData as TypesPullReq)
setPrHasChanged(false)
}
useEffect(() => {
const interval = window.setTimeout(() => {
refetchPollPullRequest()
setNewPrData(pollPrData as TypesPullReq)
}, PR_POLLING_LIMIT)
return () => window.clearTimeout(interval)
}, [pollPrData, refetchPollPullRequest])
useEffect(() => {
if (prData?.stats && newPrData?.stats) {
const prStatsChanged =
prData.stats.commits !== newPrData.stats.commits || prData.stats.files_changed !== newPrData.stats.files_changed
if (prStatsChanged) {
setPrHasChanged(prStatsChanged)
const showSpinner = useMemo(() => {
return loading || (prLoading && !prData)
}, [loading, prLoading, prData])
const [stats, setStats] = useState<TypesPullReqStats>()
const prHasChanged = useMemo(() => {
if (stats && prData?.stats) {
if (
stats.commits !== prData.stats.commits ||
stats.conversations !== prData.stats.conversations ||
stats.files_changed !== prData.stats.files_changed
) {
window.setTimeout(() => setStats(prData.stats), 50)
return true
}
}
}, [newPrData, refetchPollPullRequest, prData?.stats])
return false
}, [prData?.stats, stats])
const mergeable = useMemo(() => prData?.merge_check_status === MergeCheckStatus.MERGEABLE, [prData])
useEffect(
function setStatsIfNotSet() {
if (!stats && prData?.stats) {
setStats(prData.stats)
}
},
[prData?.stats, stats]
)
useEffect(() => {
const fn = () => {
if (repoMetadata) {
refetchPullRequest().then(() => {
interval = window.setTimeout(fn, mergeable ? PR_POLLING_INTERVAL : PR_POLLING_INTERVAL_WHEN_NOT_MERGEABLE)
})
}
}
let interval = window.setTimeout(fn, mergeable ? PR_POLLING_INTERVAL : PR_POLLING_INTERVAL_WHEN_NOT_MERGEABLE)
return () => window.clearTimeout(interval)
}, [repoMetadata, refetchPullRequest, path, mergeable])
const activeTab = useMemo(
() =>
@ -121,8 +123,8 @@ export default function PullRequest() {
]
}
/>
<PageBody error={getErrorMessage(error || prError || pollPrError)} retryOnError={voidFn(refetch)}>
<LoadingSpinner visible={loading || prLoading} withBorder={!!prData && prLoading} />
<PageBody error={getErrorMessage(error || prError)} retryOnError={voidFn(refetch)}>
<LoadingSpinner visible={showSpinner} />
<Render when={repoMetadata && prData}>
<>
@ -157,7 +159,6 @@ export default function PullRequest() {
pullRequestMetadata={prData as TypesPullReq}
onCommentUpdate={voidFn(refetchPullRequest)}
prHasChanged={prHasChanged}
handleRefresh={voidFn(handleRefresh)}
/>
)
},
@ -176,7 +177,7 @@ export default function PullRequest() {
repoMetadata={repoMetadata as TypesRepository}
pullRequestMetadata={prData as TypesPullReq}
prHasChanged={prHasChanged}
handleRefresh={voidFn(handleRefresh)}
handleRefresh={voidFn(refetchPullRequest)}
/>
)
},
@ -201,14 +202,13 @@ export default function PullRequest() {
emptyMessage={getString('noChangesPR')}
onCommentUpdate={voidFn(refetchPullRequest)}
prHasChanged={prHasChanged}
handleRefresh={voidFn(handleRefresh)}
/>
</Container>
)
},
{
id: PullRequestSection.CHECKS,
disabled: true,
disabled: window.location.hostname !== 'localhost', // TODO: Remove when API supports checks
title: (
<TabTitle
icon={CodeIcon.ChecksSuccess}
@ -337,3 +337,13 @@ const TabTitle: React.FC<{ icon: IconName; title: string; count?: number; paddin
</Text>
)
}
enum PullRequestSection {
CONVERSATION = 'conversation',
COMMITS = 'commits',
FILES_CHANGED = 'changes',
CHECKS = 'checks'
}
const PR_POLLING_INTERVAL = 15000
const PR_POLLING_INTERVAL_WHEN_NOT_MERGEABLE = 5000

View File

@ -50,6 +50,7 @@ export default function Repository() {
setFileNotExist(false)
}
}, [resourceError])
return (
<Container className={cx(css.main, !!resourceContent && css.withFileViewer)}>
<Match expr={fileNotExist}>
@ -101,12 +102,7 @@ export default function Repository() {
/>
)}
{isRepositoryEmpty && (
<EmptyRepositoryInfo
repoMetadata={repoMetadata}
resourceContent={resourceContent as OpenapiGetContentOutput}
/>
)}
{isRepositoryEmpty && <EmptyRepositoryInfo repoMetadata={repoMetadata} />}
</>
)}
</PageBody>
@ -116,10 +112,7 @@ export default function Repository() {
)
}
const EmptyRepositoryInfo: React.FC<Pick<GitInfoProps, 'repoMetadata' | 'resourceContent'>> = (
{ repoMetadata },
resourceContent
) => {
const EmptyRepositoryInfo: React.FC<Pick<GitInfoProps, 'repoMetadata'>> = ({ repoMetadata }) => {
const history = useHistory()
const { routes } = useAppContext()
const { getString } = useStrings()
@ -146,12 +139,6 @@ const EmptyRepositoryInfo: React.FC<Pick<GitInfoProps, 'repoMetadata' | 'resourc
useDisableCodeMainLinks(true)
return (
<Container className={css.emptyRepo}>
<ContentHeader
repoMetadata={repoMetadata}
gitRef={repoMetadata.default_branch as string}
resourcePath={''}
resourceContent={resourceContent}
/>
<Container
margin={{ bottom: 'xxlarge' }}
padding={{ top: 'xxlarge', bottom: 'xxlarge', left: 'xxlarge', right: 'xxlarge' }}

View File

@ -18,7 +18,7 @@
}
.readmeContent {
max-width: var(--max-width, calc(100vw - 320px));
max-width: 100%;
padding: var(--spacing-xxlarge) !important;
}
}

View File

@ -353,6 +353,17 @@ export interface RepoSymlinkContent {
target?: string
}
export interface TypesCodeCommentFields {
line_new?: number
line_old?: number
merge_base_sha?: string
outdated?: boolean
path?: string
source_sha?: string
span_new?: number
span_old?: number
}
export interface TypesCommit {
author?: TypesSignature
committer?: TypesSignature
@ -419,13 +430,7 @@ export interface TypesPullReq {
export interface TypesPullReqActivity {
author?: TypesPrincipalInfo
code_comment_line_new?: number | null
code_comment_line_old?: number | null
code_comment_merge_base_sha?: string | null
code_comment_path?: string | null
code_comment_source_sha?: string | null
code_comment_span_new?: number | null
code_comment_span_old?: number | null
code_comment?: TypesCodeCommentFields
created?: number
deleted?: number | null
edited?: number
@ -433,7 +438,6 @@ export interface TypesPullReqActivity {
kind?: EnumPullReqActivityKind
metadata?: { [key: string]: any } | null
order?: number
outdated?: boolean | null
parent_id?: number | null
payload?: {}
pullreq_id?: number

View File

@ -4268,6 +4268,25 @@ components:
target:
type: string
type: object
TypesCodeCommentFields:
properties:
line_new:
type: integer
line_old:
type: integer
merge_base_sha:
type: string
outdated:
type: boolean
path:
type: string
source_sha:
type: string
span_new:
type: integer
span_old:
type: integer
type: object
TypesCommit:
properties:
author:
@ -4386,27 +4405,8 @@ components:
properties:
author:
$ref: '#/components/schemas/TypesPrincipalInfo'
code_comment_line_new:
nullable: true
type: integer
code_comment_line_old:
nullable: true
type: integer
code_comment_merge_base_sha:
nullable: true
type: string
code_comment_path:
nullable: true
type: string
code_comment_source_sha:
nullable: true
type: string
code_comment_span_new:
nullable: true
type: integer
code_comment_span_old:
nullable: true
type: integer
code_comment:
$ref: '#/components/schemas/TypesCodeCommentFields'
created:
type: integer
deleted:
@ -4424,9 +4424,6 @@ components:
type: object
order:
type: integer
outdated:
nullable: true
type: boolean
parent_id:
nullable: true
type: integer

View File

@ -10,9 +10,9 @@ export const DEFAULT_BRANCH_NAME = 'main'
export const REGEX_VALID_REPO_NAME = /^[a-zA-Z_][0-9a-zA-Z-_.$]*$/
export const SUGGESTED_BRANCH_NAMES = [DEFAULT_BRANCH_NAME, 'master']
export const FILE_SEPERATOR = '/'
export const PR_POLLING_LIMIT = 15000
export const INITIAL_ZOOM_LEVEL = 1
export const ZOOM_INC_DEC_LEVEL = 0.1
/** This utility shows a toaster without being bound to any component.
* It's useful to show cross-page/component messages */
export function showToaster(message: string, props?: Partial<IToastProps>): IToaster {
@ -235,3 +235,8 @@ export function waitUntil(condition: () => boolean, callback: () => void, maxCou
export const voidFn = (f: Function) => () => {
f()
}
export enum MergeCheckStatus {
MERGEABLE = 'mergeable',
UNCHCKED = 'unchecked'
}