mirror of
https://github.com/harness/drone.git
synced 2025-05-21 11:29:52 +08:00
feat: [repo-summar/code-1950] added repoSummary and commit divergence tracker (#2066)
This commit is contained in:
parent
0d72a20450
commit
c035c53e4d
@ -16,9 +16,8 @@
|
||||
|
||||
.latestCommit {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: var(--primary-1) !important;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
padding: var(--spacing-small) var(--spacing-large) var(--spacing-small) var(--spacing-medium) !important;
|
||||
box-shadow: var(--elevation-3);
|
||||
border-top-left-radius: 4px;
|
||||
@ -42,19 +41,39 @@
|
||||
font-size: 13px !important;
|
||||
}
|
||||
|
||||
.commitLink {
|
||||
.link {
|
||||
font-weight: 500 !important;
|
||||
font-size: 13px !important;
|
||||
color: var(--primary-8);
|
||||
color: var(--primary-7);
|
||||
}
|
||||
|
||||
.tag {
|
||||
padding: 3px 6px !important;
|
||||
font-weight: 400 !important;
|
||||
font-size: 12px !important;
|
||||
font-family: var(--font-family-inter) !important;
|
||||
background-color: #c6eefa !important;
|
||||
color: var(--primary-7) !important;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.noWrap {
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
.border {
|
||||
border-bottom: 1px solid #d0f4fe;
|
||||
}
|
||||
|
||||
.time {
|
||||
flex-shrink: inherit;
|
||||
}
|
||||
|
||||
.commitIcon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin: 0px 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.popover {
|
||||
|
@ -16,11 +16,14 @@
|
||||
|
||||
/* eslint-disable */
|
||||
// This is an auto-generated file
|
||||
export declare const commitLink: string
|
||||
export declare const border: string
|
||||
export declare const commitIcon: string
|
||||
export declare const forFile: string
|
||||
export declare const latestCommit: string
|
||||
export declare const link: string
|
||||
export declare const noWrap: string
|
||||
export declare const popover: string
|
||||
export declare const shaBtn: string
|
||||
export declare const standalone: string
|
||||
export declare const tag: string
|
||||
export declare const time: string
|
||||
|
@ -14,58 +14,227 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import { Container, Layout, FlexExpander, Text, Avatar } from '@harnessio/uicore'
|
||||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
import {
|
||||
Container,
|
||||
Layout,
|
||||
FlexExpander,
|
||||
Text,
|
||||
Avatar,
|
||||
Utils,
|
||||
Tag,
|
||||
useIsMounted,
|
||||
StringSubstitute,
|
||||
useToaster
|
||||
} from '@harnessio/uicore'
|
||||
import { Color, FontVariation } from '@harnessio/design-system'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Render } from 'react-jsx-match'
|
||||
import cx from 'classnames'
|
||||
import { defaultTo } from 'lodash-es'
|
||||
import type { TypesCommit } from 'services/code'
|
||||
import { GitCommit } from 'iconoir-react'
|
||||
import { Icon } from '@harnessio/icons'
|
||||
import { useMutate } from 'restful-react'
|
||||
import type {
|
||||
OpenapiCalculateCommitDivergenceRequest,
|
||||
RepoCommitDivergence,
|
||||
TypesCommit,
|
||||
TypesRepository
|
||||
} from 'services/code'
|
||||
import { CommitActions } from 'components/CommitActions/CommitActions'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import { formatBytes } from 'utils/Utils'
|
||||
import type { GitInfoProps } from 'utils/GitUtils'
|
||||
import { formatBytes, getErrorMessage } from 'utils/Utils'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { makeDiffRefs, type GitInfoProps, type RepositorySummaryData, isRefATag } from 'utils/GitUtils'
|
||||
import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator'
|
||||
import { TimePopoverWithLocal } from 'utils/timePopoverLocal/TimePopoverWithLocal'
|
||||
import css from './LatestCommit.module.scss'
|
||||
|
||||
interface LatestCommitProps extends Pick<GitInfoProps, 'repoMetadata'> {
|
||||
interface LatestCommitProps extends Pick<GitInfoProps, 'repoMetadata' | 'gitRef'> {
|
||||
latestCommit?: TypesCommit
|
||||
standaloneStyle?: boolean
|
||||
size?: number
|
||||
repoSummaryData?: RepositorySummaryData | null
|
||||
loadingSummaryData?: boolean
|
||||
}
|
||||
|
||||
export function LatestCommitForFolder({ repoMetadata, latestCommit, standaloneStyle }: LatestCommitProps) {
|
||||
interface DivergenceInfoProps {
|
||||
commitDivergence: RepoCommitDivergence
|
||||
metadata: TypesRepository
|
||||
currentGitRef: string
|
||||
}
|
||||
|
||||
export function LatestCommitForFolder({
|
||||
repoMetadata,
|
||||
latestCommit,
|
||||
standaloneStyle,
|
||||
gitRef,
|
||||
repoSummaryData,
|
||||
loadingSummaryData
|
||||
}: LatestCommitProps) {
|
||||
const { routes } = useAppContext()
|
||||
const { getString } = useStrings()
|
||||
const { showError } = useToaster()
|
||||
const [divergence, setDivergence] = useState<RepoCommitDivergence>({})
|
||||
|
||||
const commitURL = routes.toCODECommit({
|
||||
repoPath: repoMetadata.path as string,
|
||||
commitRef: latestCommit?.sha as string
|
||||
})
|
||||
|
||||
const commitPage = routes.toCODECommits({
|
||||
repoPath: repoMetadata.path as string,
|
||||
commitRef: gitRef as string
|
||||
})
|
||||
|
||||
const compareCommits = (target: string, source: string) =>
|
||||
routes.toCODECompare({
|
||||
repoPath: repoMetadata?.path as string,
|
||||
diffRefs: makeDiffRefs(target as string, source as string)
|
||||
})
|
||||
|
||||
const { mutate: getBranchDivergence, loading: divergenceLoading } = useMutate({
|
||||
verb: 'POST',
|
||||
path: `/api/v1/repos/${repoMetadata.path}/+/commits/calculate-divergence`
|
||||
})
|
||||
|
||||
const branchDivergenceRequestBody: OpenapiCalculateCommitDivergenceRequest = useMemo(() => {
|
||||
return {
|
||||
maxCount: 0,
|
||||
requests: [{ from: gitRef, to: repoMetadata.default_branch }]
|
||||
}
|
||||
}, [repoMetadata, gitRef])
|
||||
|
||||
const isMounted = useIsMounted()
|
||||
|
||||
useEffect(() => {
|
||||
if (isMounted.current && branchDivergenceRequestBody.requests?.length && gitRef !== repoMetadata.default_branch) {
|
||||
setDivergence({})
|
||||
getBranchDivergence(branchDivergenceRequestBody)
|
||||
.then(([response]: RepoCommitDivergence[]) => {
|
||||
if (isMounted.current) {
|
||||
setDivergence(response)
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showError(getErrorMessage(error), 0, 'unableToGetDivergence')
|
||||
})
|
||||
}
|
||||
}, [getBranchDivergence, branchDivergenceRequestBody, isMounted])
|
||||
|
||||
const currentBranchCommitCount =
|
||||
gitRef !== repoMetadata.default_branch &&
|
||||
(repoSummaryData?.default_branch_commit_count ?? 0) + (divergence?.ahead ?? 0) - (divergence?.behind ?? 0)
|
||||
|
||||
const DivergenceInfo: React.FC<DivergenceInfoProps> = ({ commitDivergence, metadata, currentGitRef }) => {
|
||||
if ((commitDivergence?.ahead as number) > 0 && (commitDivergence?.behind as number) > 0) {
|
||||
return (
|
||||
<>
|
||||
<Link to={compareCommits(metadata.default_branch as string, currentGitRef)}>
|
||||
<Text className={css.link} lineClamp={1}>
|
||||
<StringSubstitute str={getString('aheadDivergence')} vars={{ aheadCommits: commitDivergence.ahead }} />
|
||||
</Text>
|
||||
</Link>
|
||||
<Text className={css.link} lineClamp={1}>
|
||||
{getString('and')}
|
||||
</Text>
|
||||
<Link to={compareCommits(currentGitRef, metadata.default_branch as string)}>
|
||||
<Text className={css.link} lineClamp={1}>
|
||||
<StringSubstitute str={getString('behindDivergence')} vars={{ behindCommits: commitDivergence.behind }} />
|
||||
</Text>
|
||||
</Link>
|
||||
</>
|
||||
)
|
||||
}
|
||||
if ((commitDivergence?.ahead as number) > 0) {
|
||||
return (
|
||||
<Link to={compareCommits(metadata.default_branch as string, currentGitRef)}>
|
||||
<Text className={css.link} lineClamp={1}>
|
||||
<StringSubstitute str={getString('aheadDivergence')} vars={{ aheadCommits: commitDivergence.ahead }} />
|
||||
</Text>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
if ((commitDivergence?.behind as number) > 0) {
|
||||
return (
|
||||
<Link to={compareCommits(currentGitRef, metadata.default_branch as string)}>
|
||||
<Text className={css.link} lineClamp={1}>
|
||||
<StringSubstitute str={getString('behindDivergence')} vars={{ behindCommits: commitDivergence.behind }} />
|
||||
</Text>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Text className={css.link} lineClamp={1}>
|
||||
{getString('branchUpToDateWith')}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Render when={latestCommit}>
|
||||
<Container>
|
||||
<Layout.Horizontal spacing="small" className={cx(css.latestCommit, { [css.standalone]: standaloneStyle })}>
|
||||
<Avatar hoverCard={false} size="small" name={latestCommit?.author?.identity?.name || ''} />
|
||||
<Text className={css.noWrap} font={{ variation: FontVariation.SMALL_BOLD }}>
|
||||
{latestCommit?.author?.identity?.name || latestCommit?.author?.identity?.email}
|
||||
</Text>
|
||||
<Link to={commitURL}>
|
||||
<Text className={css.commitLink} lineClamp={1}>
|
||||
{latestCommit?.title}
|
||||
<Layout.Vertical className={cx(css.latestCommit, { [css.standalone]: standaloneStyle })}>
|
||||
<Render when={gitRef !== repoMetadata.default_branch && !loadingSummaryData}>
|
||||
<Layout.Horizontal
|
||||
spacing="small"
|
||||
padding={{ bottom: 'small' }}
|
||||
className={cx(css.border)}
|
||||
flex={{ alignItems: 'center' }}>
|
||||
<GitCommit
|
||||
height={20}
|
||||
width={20}
|
||||
color={Utils.getRealCSSColor(Color.GREY_500)}
|
||||
className={css.commitIcon}
|
||||
/>
|
||||
<Text className={css.noWrap} font={{ variation: FontVariation.SMALL_SEMI }}>
|
||||
<StringSubstitute str={getString('thisRefHas')} vars={{ isTag: isRefATag(gitRef) }} />
|
||||
</Text>
|
||||
<Link to={commitPage}>
|
||||
<Text className={css.link} lineClamp={1}>
|
||||
<StringSubstitute
|
||||
str={getString('branchCommitCount')}
|
||||
vars={{
|
||||
count: currentBranchCommitCount
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
</Link>
|
||||
<FlexExpander />
|
||||
<Render when={!isRefATag(gitRef) && !divergenceLoading}>
|
||||
<>
|
||||
<Layout.Horizontal spacing={'xsmall'}>
|
||||
<DivergenceInfo commitDivergence={divergence} metadata={repoMetadata} currentGitRef={gitRef} />
|
||||
</Layout.Horizontal>
|
||||
<Tag className={css.tag} minimal>
|
||||
<Icon name="code-branch" />
|
||||
{repoMetadata?.default_branch}
|
||||
</Tag>
|
||||
</>
|
||||
</Render>
|
||||
</Layout.Horizontal>
|
||||
</Render>
|
||||
<Layout.Horizontal spacing="small" flex={{ alignItems: 'center' }}>
|
||||
<Avatar hoverCard={false} size="small" name={latestCommit?.author?.identity?.name || ''} />
|
||||
<Text className={css.noWrap} font={{ variation: FontVariation.SMALL_BOLD }}>
|
||||
{latestCommit?.author?.identity?.name || latestCommit?.author?.identity?.email}
|
||||
</Text>
|
||||
</Link>
|
||||
<FlexExpander />
|
||||
<CommitActions sha={latestCommit?.sha as string} href={commitURL} enableCopy />
|
||||
<TimePopoverWithLocal
|
||||
time={defaultTo(latestCommit?.committer?.when as unknown as number, 0)}
|
||||
inline={false}
|
||||
className={css.time}
|
||||
font={{ variation: FontVariation.SMALL }}
|
||||
color={Color.GREY_400}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
<Link to={commitURL}>
|
||||
<Text className={css.link} lineClamp={1}>
|
||||
{latestCommit?.title}
|
||||
</Text>
|
||||
</Link>
|
||||
<FlexExpander />
|
||||
<CommitActions sha={latestCommit?.sha as string} href={commitURL} enableCopy />
|
||||
<TimePopoverWithLocal
|
||||
time={defaultTo(latestCommit?.committer?.when as unknown as number, 0)}
|
||||
inline={false}
|
||||
className={css.time}
|
||||
font={{ variation: FontVariation.SMALL }}
|
||||
color={Color.GREY_400}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
</Layout.Vertical>
|
||||
</Container>
|
||||
</Render>
|
||||
)
|
||||
@ -91,7 +260,7 @@ export function LatestCommitForFile({ repoMetadata, latestCommit, standaloneStyl
|
||||
<PipeSeparator height={9} />
|
||||
|
||||
<Text lineClamp={1} tooltipProps={{ portalClassName: css.popover }}>
|
||||
<Link to={commitURL} className={css.commitLink}>
|
||||
<Link to={commitURL} className={css.link}>
|
||||
{latestCommit?.title}
|
||||
</Link>
|
||||
</Text>
|
||||
|
@ -12,6 +12,7 @@ export interface StringsMap {
|
||||
activeBranches: string
|
||||
add: string
|
||||
addComment: string
|
||||
addDescription: string
|
||||
addGitIgnore: string
|
||||
addLabel: string
|
||||
addLicense: string
|
||||
@ -20,6 +21,7 @@ export interface StringsMap {
|
||||
addReadMe: string
|
||||
addUserToSpace2: string
|
||||
admin: string
|
||||
aheadDivergence: string
|
||||
aiSearch: string
|
||||
aidaGenSummary: string
|
||||
all: string
|
||||
@ -36,6 +38,7 @@ export interface StringsMap {
|
||||
at: string
|
||||
attachText: string
|
||||
basedOn: string
|
||||
behindDivergence: string
|
||||
blame: string
|
||||
blameCommitLine: string
|
||||
blameEmpty: string
|
||||
@ -43,6 +46,7 @@ export interface StringsMap {
|
||||
botAlerts: string
|
||||
bottom: string
|
||||
branch: string
|
||||
branchCommitCount: string
|
||||
branchCreated: string
|
||||
branchDeleted: string
|
||||
branchDivergenceAhead: string
|
||||
@ -123,6 +127,7 @@ export interface StringsMap {
|
||||
branchTagCreation: string
|
||||
branchTagDeletion: string
|
||||
branchUpToDate: string
|
||||
branchUpToDateWith: string
|
||||
branches: string
|
||||
browse: string
|
||||
browseFiles: string
|
||||
@ -281,6 +286,7 @@ export interface StringsMap {
|
||||
enterName: string
|
||||
enterNewBranchName: string
|
||||
enterNewPassword: string
|
||||
enterRepoDescription: string
|
||||
enterRepoName: string
|
||||
enterSecret: string
|
||||
enterTagPlaceholder: string
|
||||
@ -863,6 +869,7 @@ export interface StringsMap {
|
||||
tagger: string
|
||||
tags: string
|
||||
termsOfUse: string
|
||||
thisRefHas: string
|
||||
title: string
|
||||
token: string
|
||||
tooltipRepoEdit: string
|
||||
@ -881,6 +888,7 @@ export interface StringsMap {
|
||||
'triggers.newTrigger': string
|
||||
'triggers.updateSuccess': string
|
||||
turnOnSemanticSearch: string
|
||||
unableToGetDivergence: string
|
||||
unorderedList: string
|
||||
unrsolvedComment: string
|
||||
'unsavedChanges.leave': string
|
||||
|
@ -39,6 +39,8 @@ createARepo: Create a repository
|
||||
createRepo: Create Repository
|
||||
enterRepoName: Enter Repository Name
|
||||
enterDescription: Enter a description (optional)
|
||||
enterRepoDescription: Enter repository description
|
||||
addDescription: Add a description
|
||||
addLicense: Add License
|
||||
none: None
|
||||
create: Create
|
||||
@ -195,6 +197,11 @@ createBranchFromTag: "<strong>Create branch: {{newBranch}}</strong> from tag '{{
|
||||
tagNotFound: 'Tag <strong>{{tag}}</strong> not found.'
|
||||
branchNotFound: 'Branch <strong>{{branch}}</strong> not found.'
|
||||
branchUpToDate: Up to date with {{defaultBranch}}
|
||||
branchUpToDateWith: Branch is up to date with
|
||||
unableToGetDivergence: Unable to get divergence
|
||||
branchCommitCount: '{count} {count|1:commit,commits}'
|
||||
behindDivergence: '{behindCommits} {behindCommits|1:commit,commits} behind '
|
||||
aheadDivergence: '{aheadCommits} {aheadCommits|1:commit,commits} ahead'
|
||||
branchDivergenceBehind: '{behind} {behindCommits|1:commit,commits} behind {defaultBranch}'
|
||||
branchDivergenceAhead: '{ahead} {aheadCommits|1:commit,commits} ahead {defaultBranch}'
|
||||
branchDivergenceAheadBehind: '{ahead} {aheadCommits|1:commit,commits} ahead, {behind} {behindCommits|1:commit,commits} behind {defaultBranch}'
|
||||
@ -583,6 +590,7 @@ token: Token
|
||||
expired: Expired
|
||||
expirationDate: Expiration Date
|
||||
created: Created
|
||||
thisRefHas: 'This {isTag|true:tag,branch} has'
|
||||
changePasswordSuccesfully: Password changed successfully
|
||||
applyChanges: Apply Changes
|
||||
showMore: View more
|
||||
|
@ -217,6 +217,7 @@ export function FileContent({
|
||||
<Container className={css.fileContent}>
|
||||
<Layout.Vertical spacing="small" style={{ maxWidth: '100%' }}>
|
||||
<LatestCommitForFile
|
||||
gitRef={gitRef}
|
||||
repoMetadata={repoMetadata}
|
||||
latestCommit={resourceContent.latest_commit}
|
||||
standaloneStyle
|
||||
|
@ -16,8 +16,10 @@
|
||||
|
||||
.folderContent {
|
||||
padding: 0 var(--spacing-xlarge) var(--spacing-xlarge) var(--spacing-xlarge) !important;
|
||||
width: 100%;
|
||||
|
||||
.table {
|
||||
height: auto;
|
||||
background-color: var(--white) !important;
|
||||
:global([class*='TableV2--row']:last-child) {
|
||||
border-bottom-left-radius: 4px !important;
|
||||
|
@ -32,15 +32,25 @@ import { Page } from 'iconoir-react'
|
||||
|
||||
import { Render } from 'react-jsx-match'
|
||||
import { chunk, sortBy, throttle } from 'lodash-es'
|
||||
import { useMutate } from 'restful-react'
|
||||
import { useGet, useMutate } from 'restful-react'
|
||||
import { Link, useHistory } from 'react-router-dom'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import type { OpenapiContentInfo, OpenapiDirContent, TypesCommit } from 'services/code'
|
||||
import { formatDate, isInViewport, LIST_FETCHING_LIMIT, PAGE_CONTAINER_WIDTH } from 'utils/Utils'
|
||||
import { findReadmeInfo, GitInfoProps, isFile, isSymlink, isSubmodule, normalizeGitRef } from 'utils/GitUtils'
|
||||
import {
|
||||
findReadmeInfo,
|
||||
GitInfoProps,
|
||||
isFile,
|
||||
isSymlink,
|
||||
isSubmodule,
|
||||
normalizeGitRef,
|
||||
RepositorySummaryData
|
||||
} from 'utils/GitUtils'
|
||||
import { LatestCommitForFolder } from 'components/LatestCommit/LatestCommit'
|
||||
import { CommitActions } from 'components/CommitActions/CommitActions'
|
||||
import { useEventListener } from 'hooks/useEventListener'
|
||||
import { useShowRequestError } from 'hooks/useShowRequestError'
|
||||
import RepositorySummary from './RepositorySummary/RepositorySummary'
|
||||
import { Readme } from './Readme'
|
||||
import CodeFolder from '../../../../icons/CodeFileFill.svg?url'
|
||||
import Submodule from '../../../../icons/Submodules.svg?url'
|
||||
@ -48,7 +58,7 @@ import Symlink from '../../../../icons/Symlink.svg?url'
|
||||
import repositoryCSS from '../../Repository.module.scss'
|
||||
import css from './FolderContent.module.scss'
|
||||
|
||||
type FolderContentProps = Pick<GitInfoProps, 'repoMetadata' | 'resourceContent' | 'gitRef'>
|
||||
type FolderContentProps = Pick<GitInfoProps, 'repoMetadata' | 'resourceContent' | 'resourcePath' | 'gitRef'>
|
||||
|
||||
const checkIcon = (row: OpenapiContentInfo): React.ReactElement => {
|
||||
if (isFile(row)) {
|
||||
@ -61,7 +71,7 @@ const checkIcon = (row: OpenapiContentInfo): React.ReactElement => {
|
||||
return <img width={14} height={14} src={CodeFolder} />
|
||||
}
|
||||
}
|
||||
export function FolderContent({ repoMetadata, resourceContent, gitRef }: FolderContentProps) {
|
||||
export function FolderContent({ repoMetadata, resourceContent, gitRef, resourcePath }: FolderContentProps) {
|
||||
const history = useHistory()
|
||||
const { routes, standalone } = useAppContext()
|
||||
const columns: Column<OpenapiContentInfo>[] = useMemo(
|
||||
@ -142,6 +152,15 @@ export function FolderContent({ repoMetadata, resourceContent, gitRef }: FolderC
|
||||
[resourceEntries, pathsChunks] // eslint-disable-line react-hooks/exhaustive-deps
|
||||
)
|
||||
const isMounted = useIsMounted()
|
||||
const {
|
||||
data: repoSummaryData,
|
||||
error: repoSummaryError,
|
||||
loading: loadingSummaryData
|
||||
} = useGet<RepositorySummaryData>({
|
||||
path: `/api/v1/repos/${repoMetadata?.path}/+/summary`
|
||||
})
|
||||
|
||||
useShowRequestError(repoSummaryError)
|
||||
|
||||
// The idea is to fetch last commit details for chunks that has atleast one path which is
|
||||
// rendered in the viewport
|
||||
@ -223,34 +242,49 @@ export function FolderContent({ repoMetadata, resourceContent, gitRef }: FolderC
|
||||
}, [scrollCallback])
|
||||
|
||||
return (
|
||||
<Container className={css.folderContent}>
|
||||
<LatestCommitForFolder repoMetadata={repoMetadata} latestCommit={resourceContent?.latest_commit} />
|
||||
|
||||
<Table<OpenapiContentInfo>
|
||||
className={css.table}
|
||||
columns={columns}
|
||||
data={mergedContentEntries}
|
||||
onRowClick={entry => {
|
||||
history.push(
|
||||
routes.toCODERepository({
|
||||
repoPath: repoMetadata.path as string,
|
||||
gitRef,
|
||||
resourcePath: entry.path
|
||||
})
|
||||
)
|
||||
}}
|
||||
getRowClassName={() => css.row}
|
||||
/>
|
||||
|
||||
<Render when={readmeInfo}>
|
||||
<Readme
|
||||
metadata={repoMetadata}
|
||||
readmeInfo={readmeInfo as OpenapiContentInfo}
|
||||
<Layout.Horizontal>
|
||||
<Container className={css.folderContent}>
|
||||
<LatestCommitForFolder
|
||||
repoMetadata={repoMetadata}
|
||||
latestCommit={resourceContent?.latest_commit}
|
||||
gitRef={gitRef}
|
||||
maxWidth={`calc(var(${PAGE_CONTAINER_WIDTH}) - 48px)`}
|
||||
repoSummaryData={repoSummaryData}
|
||||
loadingSummaryData={loadingSummaryData}
|
||||
/>
|
||||
<Table<OpenapiContentInfo>
|
||||
className={css.table}
|
||||
columns={columns}
|
||||
data={mergedContentEntries}
|
||||
onRowClick={entry => {
|
||||
history.push(
|
||||
routes.toCODERepository({
|
||||
repoPath: repoMetadata.path as string,
|
||||
gitRef,
|
||||
resourcePath: entry.path
|
||||
})
|
||||
)
|
||||
}}
|
||||
getRowClassName={() => css.row}
|
||||
/>
|
||||
|
||||
<Render when={readmeInfo}>
|
||||
<Readme
|
||||
metadata={repoMetadata}
|
||||
readmeInfo={readmeInfo as OpenapiContentInfo}
|
||||
gitRef={gitRef}
|
||||
maxWidth={`calc(var(${PAGE_CONTAINER_WIDTH}) - 48px)`}
|
||||
/>
|
||||
</Render>
|
||||
</Container>
|
||||
<Render when={!resourcePath}>
|
||||
<RepositorySummary
|
||||
metadata={repoMetadata}
|
||||
gitRef={gitRef}
|
||||
repoSummaryData={repoSummaryData}
|
||||
loadingSummaryData={loadingSummaryData}
|
||||
/>
|
||||
</Render>
|
||||
</Container>
|
||||
</Layout.Horizontal>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,52 @@
|
||||
.summaryContainer {
|
||||
height: fit-content;
|
||||
width: 25% !important;
|
||||
box-shadow: 0px 0px 1px rgba(40, 41, 61, 0.08), 0px 0.5px 2px rgba(96, 97, 112, 0.16);
|
||||
border-radius: 4px;
|
||||
margin-right: var(--spacing-xlarge) !important;
|
||||
|
||||
.heading {
|
||||
border-bottom: 1px solid var(--grey-100);
|
||||
}
|
||||
|
||||
.content {
|
||||
margin: var(--spacing-xlarge) 0;
|
||||
gap: var(--spacing-xlarge);
|
||||
font-size: 13px !important;
|
||||
.tags {
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
gap: var(--spacing-xsmall) !important;
|
||||
max-width: calc(100% - 10px) !important;
|
||||
}
|
||||
|
||||
.tag {
|
||||
padding: 3px 6px !important;
|
||||
font-weight: 400 !important;
|
||||
font-size: 12px !important;
|
||||
font-family: var(--font-family-inter) !important;
|
||||
background-color: #edf6ff !important;
|
||||
color: var(--primary-7) !important;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: var(--primary-7);
|
||||
font-size: 13px !important;
|
||||
}
|
||||
|
||||
.metaData {
|
||||
padding: var(--spacing-small) 0;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--grey-100);
|
||||
|
||||
.align {
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2023 Harness, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
// This is an auto-generated file
|
||||
export declare const align: string
|
||||
export declare const content: string
|
||||
export declare const heading: string
|
||||
export declare const link: string
|
||||
export declare const metaData: string
|
||||
export declare const summaryContainer: string
|
||||
export declare const tag: string
|
||||
export declare const tags: string
|
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2023 Harness, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import { Button, ButtonVariation, Container, Layout, Text, Utils } from '@harnessio/uicore'
|
||||
import { Color, FontVariation } from '@harnessio/design-system'
|
||||
import { GitCommit, GitFork, Label, GitPullRequest } from 'iconoir-react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { CodeIcon, RepositorySummaryData } from 'utils/GitUtils'
|
||||
import type { TypesRepository } from 'services/code'
|
||||
import { permissionProps, formatDate } from 'utils/Utils'
|
||||
import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata'
|
||||
import css from './RepositorySummary.module.scss'
|
||||
|
||||
interface RepositorySummaryProps {
|
||||
metadata: TypesRepository
|
||||
gitRef?: string
|
||||
repoSummaryData: RepositorySummaryData | null
|
||||
loadingSummaryData: boolean
|
||||
}
|
||||
|
||||
enum MetaDataType {
|
||||
BRANCH = 'branch',
|
||||
TAG = 'tag',
|
||||
COMMIT = 'commit',
|
||||
PULL_REQUEST = 'pull_request'
|
||||
}
|
||||
|
||||
interface MetaDataProps {
|
||||
type: MetaDataType
|
||||
text: string
|
||||
data: number | undefined
|
||||
}
|
||||
|
||||
const RepositorySummary = (props: RepositorySummaryProps) => {
|
||||
const { metadata, repoSummaryData, loadingSummaryData } = props
|
||||
const { getString } = useStrings()
|
||||
const { standalone, hooks, routes } = useAppContext()
|
||||
const { space } = useGetRepositoryMetadata()
|
||||
|
||||
const MetaData: React.FC<MetaDataProps> = ({ type, text, data }) => {
|
||||
let DataIcon
|
||||
let routeTo: string
|
||||
const history = useHistory()
|
||||
switch (type) {
|
||||
case MetaDataType.BRANCH:
|
||||
DataIcon = GitFork
|
||||
routeTo = routes.toCODEBranches({
|
||||
repoPath: metadata?.path as string
|
||||
})
|
||||
break
|
||||
case MetaDataType.TAG:
|
||||
DataIcon = Label
|
||||
routeTo = routes.toCODETags({
|
||||
repoPath: metadata?.path as string
|
||||
})
|
||||
break
|
||||
case MetaDataType.COMMIT:
|
||||
DataIcon = GitCommit
|
||||
routeTo = routes.toCODECommits({
|
||||
repoPath: metadata?.path as string,
|
||||
commitRef: metadata?.default_branch as string
|
||||
})
|
||||
break
|
||||
case MetaDataType.PULL_REQUEST:
|
||||
DataIcon = GitPullRequest
|
||||
routeTo = routes.toCODEPullRequests({
|
||||
repoPath: metadata?.path as string
|
||||
})
|
||||
break
|
||||
default:
|
||||
DataIcon = GitCommit
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout.Horizontal className={css.metaData}>
|
||||
<Text color={Color.BLACK} font={{ variation: FontVariation.BODY2_SEMI }} className={css.align}>
|
||||
<DataIcon height={20} width={20} color={Utils.getRealCSSColor(Color.GREY_500)} />
|
||||
{text}
|
||||
</Text>
|
||||
<Button
|
||||
className={css.link}
|
||||
icon={loadingSummaryData ? 'steps-spinner' : undefined}
|
||||
variation={ButtonVariation.LINK}
|
||||
text={data?.toLocaleString()}
|
||||
onClick={() => history.push(routeTo)}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
)
|
||||
}
|
||||
|
||||
const permPushResult = hooks?.usePermissionTranslate?.(
|
||||
{
|
||||
resource: {
|
||||
resourceType: 'CODE_REPOSITORY',
|
||||
resourceIdentifier: metadata?.uid as string
|
||||
},
|
||||
permissions: ['code_repo_edit']
|
||||
},
|
||||
[space]
|
||||
)
|
||||
|
||||
const history = useHistory()
|
||||
return (
|
||||
<Container padding={'medium'} background={Color.WHITE} className={css.summaryContainer}>
|
||||
<Container className={css.heading} padding={'small'}>
|
||||
<Text font={{ variation: FontVariation.H5 }} margin={{ bottom: 'xsmall' }}>
|
||||
{getString('summary')}
|
||||
</Text>
|
||||
<Text font={{ variation: FontVariation.SMALL_SEMI }} color={Color.GREY_450}>
|
||||
{getString('created')} {formatDate(metadata?.created || 0, 'long')}
|
||||
</Text>
|
||||
</Container>
|
||||
<Layout.Vertical padding={'small'} className={css.content}>
|
||||
<Layout.Vertical spacing="medium">
|
||||
<Text font={{ variation: FontVariation.BODY2_SEMI }} color={Color.BLACK_100} style={{ fontSize: '13px' }}>
|
||||
{metadata.description ? (
|
||||
metadata.description
|
||||
) : (
|
||||
<Button
|
||||
variation={ButtonVariation.LINK}
|
||||
text={getString('addDescription')}
|
||||
icon={CodeIcon.Add}
|
||||
onClick={() =>
|
||||
history.push(
|
||||
routes.toCODESettings({
|
||||
repoPath: metadata?.path as string
|
||||
})
|
||||
)
|
||||
}
|
||||
{...permissionProps(permPushResult, standalone)}
|
||||
/>
|
||||
)}
|
||||
</Text>
|
||||
</Layout.Vertical>
|
||||
<Layout.Vertical spacing="large">
|
||||
<MetaData
|
||||
type={MetaDataType.COMMIT}
|
||||
text={getString('commits')}
|
||||
data={repoSummaryData?.default_branch_commit_count}
|
||||
/>
|
||||
<MetaData type={MetaDataType.BRANCH} text={getString('branches')} data={repoSummaryData?.branch_count} />
|
||||
<MetaData type={MetaDataType.TAG} text={getString('tags')} data={repoSummaryData?.tag_count} />
|
||||
<MetaData
|
||||
type={MetaDataType.PULL_REQUEST}
|
||||
text={'Open Pull Requests'}
|
||||
data={repoSummaryData?.pull_req_summary.open_count}
|
||||
/>
|
||||
</Layout.Vertical>
|
||||
</Layout.Vertical>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default RepositorySummary
|
@ -42,6 +42,7 @@ export function RepositoryContent({
|
||||
{(isDir(resourceContent) && (
|
||||
<FolderContent
|
||||
resourceContent={resourceContent}
|
||||
resourcePath={resourcePath}
|
||||
repoMetadata={repoMetadata}
|
||||
gitRef={gitRef || (repoMetadata.default_branch as string)}
|
||||
/>
|
||||
|
@ -24,7 +24,6 @@ import {
|
||||
Formik,
|
||||
useToaster,
|
||||
ButtonSize,
|
||||
TextInput,
|
||||
FormInput,
|
||||
Dialog,
|
||||
StringSubstitute
|
||||
@ -217,19 +216,14 @@ const GeneralSettingsContent = (props: GeneralSettingsProps) => {
|
||||
</Container>
|
||||
<Container className={css.content}>
|
||||
{editDesc === ACCESS_MODES.EDIT ? (
|
||||
<Layout.Horizontal className={css.editContainer}>
|
||||
<TextInput
|
||||
<Layout.Vertical className={css.editContainer} margin={{ top: 'xlarge', bottom: 'xlarge' }}>
|
||||
<FormInput.TextArea
|
||||
className={cx(css.textContainer, css.textSize)}
|
||||
onChange={evt => {
|
||||
formik.setFieldValue('desc', (evt.currentTarget as HTMLInputElement)?.value)
|
||||
}}
|
||||
value={formik.values.desc || repoMetadata?.description}
|
||||
placeholder={getString('enterRepoDescription')}
|
||||
name="desc"
|
||||
/>
|
||||
<Layout.Horizontal className={css.buttonContainer}>
|
||||
<Button
|
||||
className={css.saveBtn}
|
||||
margin={{ right: 'medium' }}
|
||||
type="submit"
|
||||
text={getString('save')}
|
||||
variation={ButtonVariation.SECONDARY}
|
||||
@ -256,7 +250,7 @@ const GeneralSettingsContent = (props: GeneralSettingsProps) => {
|
||||
}}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
</Layout.Horizontal>
|
||||
</Layout.Vertical>
|
||||
) : (
|
||||
<Text color={Color.GREY_800} className={css.textSize}>
|
||||
{formik?.values?.desc || repoMetadata?.description}
|
||||
@ -301,7 +295,6 @@ const GeneralSettingsContent = (props: GeneralSettingsProps) => {
|
||||
{defaultBranch === ACCESS_MODES.EDIT ? (
|
||||
<>
|
||||
<Button
|
||||
className={css.saveBtn}
|
||||
margin={{ right: 'small' }}
|
||||
text={getString('save')}
|
||||
disabled={currentGitRef === repoMetadata?.default_branch}
|
||||
|
@ -132,19 +132,21 @@
|
||||
}
|
||||
|
||||
.textContainer {
|
||||
width: 80%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.editContainer {
|
||||
:global([class*='TextInput--main']) {
|
||||
margin-bottom: unset !important;
|
||||
font-size: 20px;
|
||||
width: 60% !important;
|
||||
textarea {
|
||||
min-height: 100px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
width: 20%;
|
||||
padding-top: var(--spacing-xsmall) !important;
|
||||
gap: 10px;
|
||||
margin-left: auto !important;
|
||||
}
|
||||
|
||||
.textSize {
|
||||
|
@ -85,6 +85,17 @@ export interface ImportSpaceFormData {
|
||||
importPipelineLabel: boolean
|
||||
}
|
||||
|
||||
export interface RepositorySummaryData {
|
||||
default_branch_commit_count: number
|
||||
branch_count: number
|
||||
tag_count: number
|
||||
pull_req_summary: {
|
||||
open_count: number
|
||||
closed_count: number
|
||||
merged_count: number
|
||||
}
|
||||
}
|
||||
|
||||
export enum RepoVisibility {
|
||||
PUBLIC = 'public',
|
||||
PRIVATE = 'private'
|
||||
|
Loading…
Reference in New Issue
Block a user