feat: [repo-summar/code-1950] added repoSummary and commit divergence tracker (#2066)

This commit is contained in:
Ritik Kapoor 2024-05-27 19:55:19 +00:00 committed by Harness
parent 0d72a20450
commit c035c53e4d
15 changed files with 575 additions and 76 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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>
)
}

View File

@ -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;
}
}
}
}

View File

@ -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

View File

@ -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

View File

@ -42,6 +42,7 @@ export function RepositoryContent({
{(isDir(resourceContent) && (
<FolderContent
resourceContent={resourceContent}
resourcePath={resourcePath}
repoMetadata={repoMetadata}
gitRef={gitRef || (repoMetadata.default_branch as string)}
/>

View File

@ -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}

View File

@ -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 {

View File

@ -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'