mirror of
https://github.com/harness/drone.git
synced 2025-05-04 20:10:44 +08:00
250 lines
9.1 KiB
TypeScript
250 lines
9.1 KiB
TypeScript
import React, { useEffect, useState } from 'react'
|
|
import { Link, useHistory } from 'react-router-dom'
|
|
import {
|
|
Button,
|
|
ButtonVariation,
|
|
Container,
|
|
FlexExpander,
|
|
FontVariation,
|
|
Layout,
|
|
PageBody,
|
|
StringSubstitute,
|
|
Text
|
|
} from '@harness/uicore'
|
|
import { Falsy, Match, Truthy } from 'react-jsx-match'
|
|
import { useGetResourceContent } from 'hooks/useGetResourceContent'
|
|
import { voidFn, getErrorMessage, permissionProps } from 'utils/Utils'
|
|
import { useAppContext } from 'AppContext'
|
|
import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata'
|
|
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
|
|
import { useStrings } from 'framework/strings'
|
|
import type { OpenapiGetContentOutput, TypesRepository } from 'services/code'
|
|
import { MarkdownViewer } from 'components/MarkdownViewer/MarkdownViewer'
|
|
import { CodeIcon, GitInfoProps } from 'utils/GitUtils'
|
|
import { useDisableCodeMainLinks } from 'hooks/useDisableCodeMainLinks'
|
|
import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
|
|
import { Images } from 'images'
|
|
import { RepositoryContent } from './RepositoryContent/RepositoryContent'
|
|
import { RepositoryHeader } from './RepositoryHeader/RepositoryHeader'
|
|
import { ContentHeader } from './RepositoryContent/ContentHeader/ContentHeader'
|
|
import css from './Repository.module.scss'
|
|
import { CopyButton } from 'components/CopyButton/CopyButton'
|
|
import CloneCredentialDialog from 'components/CloneCredentialDialog/CloneCredentialDialog'
|
|
|
|
export default function Repository() {
|
|
const { gitRef, resourcePath, repoMetadata, error, loading, refetch } = useGetRepositoryMetadata()
|
|
const {
|
|
data: resourceContent,
|
|
error: resourceError,
|
|
loading: resourceLoading,
|
|
isRepositoryEmpty
|
|
} = useGetResourceContent({ repoMetadata, gitRef, resourcePath, includeCommit: true })
|
|
const [fileNotExist, setFileNotExist] = useState(false)
|
|
const { getString } = useStrings()
|
|
|
|
useEffect(() => {
|
|
if (resourceError?.status === 404) {
|
|
setFileNotExist(true)
|
|
} else {
|
|
setFileNotExist(false)
|
|
}
|
|
}, [resourceError])
|
|
return (
|
|
<Container className={css.main}>
|
|
<Match expr={fileNotExist}>
|
|
<Truthy>
|
|
<RepositoryHeader repoMetadata={repoMetadata as TypesRepository} />
|
|
<Layout.Vertical>
|
|
<Container className={css.bannerContainer} padding={{ left: 'xlarge' }}>
|
|
<Text font={'small'} padding={{ left: 'large' }}>
|
|
<StringSubstitute
|
|
str={getString('branchDoesNotHaveFile')}
|
|
vars={{
|
|
repoName: repoMetadata?.uid,
|
|
fileName: resourcePath,
|
|
branchName: gitRef
|
|
}}
|
|
/>
|
|
</Text>
|
|
</Container>
|
|
<Container padding={{ left: 'xlarge' }}>
|
|
<ContentHeader
|
|
repoMetadata={repoMetadata as TypesRepository}
|
|
gitRef={gitRef}
|
|
resourcePath={resourcePath}
|
|
resourceContent={resourceContent as OpenapiGetContentOutput}
|
|
/>
|
|
</Container>
|
|
<PageBody
|
|
noData={{
|
|
when: () => fileNotExist === true,
|
|
message: getString('error404Text'),
|
|
image: Images.error404
|
|
}}></PageBody>
|
|
</Layout.Vertical>
|
|
</Truthy>
|
|
<Falsy>
|
|
<PageBody error={getErrorMessage(error || resourceError)} retryOnError={voidFn(refetch)}>
|
|
<LoadingSpinner visible={loading || resourceLoading} withBorder={!!resourceContent && resourceLoading} />
|
|
|
|
{!!repoMetadata && (
|
|
<>
|
|
<RepositoryHeader repoMetadata={repoMetadata} />
|
|
|
|
{!!resourceContent && (
|
|
<RepositoryContent
|
|
repoMetadata={repoMetadata}
|
|
gitRef={gitRef}
|
|
resourcePath={resourcePath}
|
|
resourceContent={resourceContent}
|
|
/>
|
|
)}
|
|
|
|
{isRepositoryEmpty && (
|
|
<EmptyRepositoryInfo
|
|
repoMetadata={repoMetadata}
|
|
resourceContent={resourceContent as OpenapiGetContentOutput}
|
|
/>
|
|
)}
|
|
</>
|
|
)}
|
|
</PageBody>
|
|
</Falsy>
|
|
</Match>
|
|
</Container>
|
|
)
|
|
}
|
|
|
|
const EmptyRepositoryInfo: React.FC<Pick<GitInfoProps, 'repoMetadata' | 'resourceContent'>> = (
|
|
{ repoMetadata },
|
|
resourceContent
|
|
) => {
|
|
const history = useHistory()
|
|
const { routes } = useAppContext()
|
|
const { getString } = useStrings()
|
|
const { currentUserProfileURL } = useAppContext()
|
|
const newFileURL = routes.toCODEFileEdit({
|
|
repoPath: repoMetadata.path as string,
|
|
gitRef: repoMetadata.default_branch as string,
|
|
resourcePath: ''
|
|
})
|
|
const { standalone } = useAppContext()
|
|
const { hooks } = useAppContext()
|
|
const space = useGetSpaceParam()
|
|
const [flag, setFlag] = useState(false)
|
|
|
|
const permPushResult = hooks?.usePermissionTranslate?.(
|
|
{
|
|
resource: {
|
|
resourceType: 'CODE_REPO'
|
|
},
|
|
permissions: ['code_repo_push']
|
|
},
|
|
[space]
|
|
)
|
|
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' }}
|
|
className={css.divContainer}>
|
|
<Text font={{ variation: FontVariation.H5 }}>{getString('emptyRepoHeader')}</Text>
|
|
<Layout.Horizontal padding={{ top: 'large' }}>
|
|
<Button
|
|
variation={ButtonVariation.PRIMARY}
|
|
text={getString('addNewFile')}
|
|
onClick={() => history.push(newFileURL)}
|
|
{...permissionProps(permPushResult, standalone)}></Button>
|
|
|
|
<Container padding={{ left: 'medium', top: 'small' }}>
|
|
<Text className={css.textContainer}>
|
|
<StringSubstitute
|
|
str={getString('emptyRepoInclude')}
|
|
vars={{
|
|
README: <Link to={newFileURL + `?name=README.md`}>README</Link>,
|
|
LICENSE: <Link to={newFileURL + `?name=LICENSE.md`}>LICENSE</Link>,
|
|
GITIGNORE: <Link to={newFileURL + `?name=.gitignore`}>.gitignore</Link>
|
|
}}
|
|
/>
|
|
</Text>
|
|
</Container>
|
|
</Layout.Horizontal>
|
|
</Container>
|
|
<Container
|
|
margin={{ bottom: 'xxlarge' }}
|
|
padding={{ top: 'xxlarge', bottom: 'xxlarge', left: 'xxlarge', right: 'xxlarge' }}
|
|
className={css.divContainer}>
|
|
<Text font={{ variation: FontVariation.H4 }}>{getString('firstTimeTitle')}</Text>
|
|
<Text className={css.text} padding={{ top: 'medium', bottom: 'small' }} font={{ variation: FontVariation.BODY }}>
|
|
{getString('cloneHTTPS')}
|
|
</Text>
|
|
<Layout.Horizontal>
|
|
<Container padding={{ bottom: 'medium' }} width={400} margin={{ right: 'small' }}>
|
|
<Layout.Horizontal className={css.layout}>
|
|
<Text className={css.url}>{repoMetadata.git_url}</Text>
|
|
<FlexExpander />
|
|
<CopyButton
|
|
content={repoMetadata?.git_url as string}
|
|
id={css.cloneCopyButton}
|
|
icon={CodeIcon.Copy}
|
|
iconProps={{ size: 14 }}
|
|
/>
|
|
</Layout.Horizontal>
|
|
</Container>
|
|
<Button
|
|
onClick={() => {
|
|
setFlag(true)
|
|
}}
|
|
variation={ButtonVariation.SECONDARY}>
|
|
{getString('generateCloneCred')}
|
|
</Button>
|
|
</Layout.Horizontal>
|
|
<Text font={{ variation: FontVariation.BODY, size: 'small' }}>
|
|
<StringSubstitute
|
|
str={getString('manageCredText')}
|
|
vars={{
|
|
URL: (
|
|
<a
|
|
onClick={() => {
|
|
history.push(currentUserProfileURL)
|
|
}}>
|
|
here
|
|
</a>
|
|
)
|
|
}}
|
|
/>
|
|
</Text>
|
|
</Container>
|
|
<Container
|
|
margin={{ bottom: 'xxlarge' }}
|
|
padding={{ top: 'xxlarge', bottom: 'xxlarge', left: 'xxlarge', right: 'xxlarge' }}
|
|
className={css.divContainer}>
|
|
<MarkdownViewer
|
|
getString={getString}
|
|
source={getString('repoEmptyMarkdownClonePush').replace(/REPO_NAME/g, repoMetadata.uid || '')}
|
|
/>
|
|
</Container>
|
|
<Container
|
|
margin={{ bottom: 'xxlarge' }}
|
|
padding={{ top: 'xxlarge', bottom: 'xxlarge', left: 'xxlarge', right: 'xxlarge' }}
|
|
className={css.divContainer}>
|
|
<MarkdownViewer
|
|
getString={getString}
|
|
source={getString('repoEmptyMarkdownExisting')
|
|
.replace(/REPO_URL/g, repoMetadata.git_url || '')
|
|
.replace(/REPO_NAME/g, repoMetadata.uid || '')
|
|
.replace(/CREATE_API_TOKEN_URL/g, currentUserProfileURL || '')}
|
|
/>
|
|
</Container>
|
|
<CloneCredentialDialog flag={flag} setFlag={setFlag} />
|
|
</Container>
|
|
)
|
|
}
|