add support for submodules and symlinks (#378)

This commit is contained in:
Calvin Lee 2023-08-31 17:38:53 +00:00 committed by Harness
parent ac8f1932ba
commit c131873c82
7 changed files with 95 additions and 34 deletions

View File

@ -1,5 +1,4 @@
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.3333 6.30333H13.3333V4.66699H7.99996L6.66663 2.66699H2.66663V13.3337M15.3333 6.30333L13.3333 13.3337H2.66663M15.3333 6.30333H4.66663L2.66663 13.3337" stroke="#383946" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15 6.5H4.5L3 13H13L15 6.5Z" fill="#383946"/>
<path opacity="0.3" d="M8.66663 2.66634H13.3333" stroke="#383946" stroke-linecap="round" stroke-linejoin="round"/>
<svg viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.16406 6.41683V2.6835C1.16406 2.59067 1.20094 2.50165 1.26658 2.43601C1.33221 2.37037 1.42124 2.3335 1.51406 2.3335H5.1179C5.20132 2.33349 5.282 2.36328 5.3454 2.4175L7.19106 3.9995C7.25446 4.05371 7.33514 4.0835 7.41856 4.0835H12.4807C12.5267 4.0835 12.5722 4.09255 12.6147 4.11014C12.6571 4.12773 12.6957 4.15351 12.7282 4.18601C12.7607 4.21851 12.7865 4.25709 12.8041 4.29956C12.8217 4.34202 12.8307 4.38753 12.8307 4.4335V6.41683M1.16406 6.41683V11.3168C1.16406 11.4097 1.20094 11.4987 1.26658 11.5643C1.33221 11.63 1.42124 11.6668 1.51406 11.6668H12.4807C12.5736 11.6668 12.6626 11.63 12.7282 11.5643C12.7939 11.4987 12.8307 11.4097 12.8307 11.3168V6.41683M1.16406 6.41683H6.9974H12.8307" stroke="#4F5162" stroke-width="0.875" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="1" y="6" width="12" height="6" fill="#4F5162"/>
</svg>

Before

Width:  |  Height:  |  Size: 479 B

After

Width:  |  Height:  |  Size: 929 B

View File

@ -0,0 +1,5 @@
<svg viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.16406 6.41683V2.6835C1.16406 2.59067 1.20094 2.50165 1.26658 2.43601C1.33221 2.37037 1.42124 2.3335 1.51406 2.3335H5.1179C5.20132 2.33349 5.282 2.36328 5.3454 2.4175L7.19106 3.9995C7.25446 4.05371 7.33514 4.0835 7.41856 4.0835H12.4807C12.5267 4.0835 12.5722 4.09255 12.6147 4.11014C12.6571 4.12773 12.6957 4.15351 12.7282 4.18601C12.7607 4.21851 12.7865 4.25709 12.8041 4.29956C12.8217 4.34202 12.8307 4.38753 12.8307 4.4335V6.41683M1.16406 6.41683V11.3168C1.16406 11.4097 1.20094 11.4987 1.26658 11.5643C1.33221 11.63 1.42124 11.6668 1.51406 11.6668H12.4807C12.5736 11.6668 12.6626 11.63 12.7282 11.5643C12.7939 11.4987 12.8307 11.4097 12.8307 11.3168V6.41683M1.16406 6.41683H6.9974H12.8307" stroke="#4F5162" stroke-width="0.875" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="1" y="6" width="12" height="6" fill="#4F5162"/>
<path d="M7 7.6665L8.33333 8.99984M8.33333 8.99984H5M8.33333 8.99984L7 10.3332" stroke="white" stroke-width="0.88" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,4 @@
<svg viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 7.6665L8.33333 8.99984M8.33333 8.99984H5M8.33333 8.99984L7 10.3332M2.33594 12.4832V1.5165C2.33594 1.42368 2.37281 1.33465 2.43845 1.26902C2.50409 1.20338 2.59311 1.1665 2.68594 1.1665H9.48294C9.57573 1.16659 9.6647 1.20351 9.73027 1.26917L11.5666 3.1055C11.5993 3.13811 11.6251 3.17685 11.6428 3.2195C11.6604 3.26215 11.6694 3.30786 11.6693 3.354V12.4832C11.6693 12.5291 11.6602 12.5746 11.6426 12.6171C11.625 12.6596 11.5993 12.6982 11.5668 12.7307C11.5343 12.7632 11.4957 12.7889 11.4532 12.8065C11.4107 12.8241 11.3652 12.8332 11.3193 12.8332H2.68594C2.63997 12.8332 2.59446 12.8241 2.552 12.8065C2.50953 12.7889 2.47095 12.7632 2.43845 12.7307C2.40595 12.6982 2.38017 12.6596 2.36258 12.6171C2.34499 12.5746 2.33594 12.5291 2.33594 12.4832Z" stroke="#4F5162" stroke-width="0.875" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.33594 1.1665V3.14984C9.33594 3.24266 9.37281 3.33169 9.43845 3.39732C9.50409 3.46296 9.59311 3.49984 9.68594 3.49984H11.6693" stroke="#4F5162" stroke-width="0.875" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -35,7 +35,7 @@ import { OptionsMenuButton } from 'components/OptionsMenuButton/OptionsMenuButto
import { PlainButton } from 'components/PlainButton/PlainButton'
import { CommitsView } from 'components/CommitsView/CommitsView'
import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
import { FileCategory, useFileContentViewerDecision } from 'utils/FileUtils'
import { FileCategory, RepoContentExtended, useFileContentViewerDecision } from 'utils/FileUtils'
import { useDownloadRawFile } from 'hooks/useDownloadRawFile'
import { usePageIndex } from 'hooks/usePageIndex'
import { Readme } from '../FolderContent/Readme'
@ -233,7 +233,12 @@ export function FileContent({
</Layout.Horizontal>
</Layout.Horizontal>
<Render when={(resourceContent?.content as RepoFileContent)?.data}>
<Render
when={
(resourceContent?.content as RepoFileContent)?.data ||
(resourceContent?.content as RepoContentExtended)?.target ||
(resourceContent?.content as RepoContentExtended)?.url
}>
<Container className={css.content}>
<Match expr={isViewable}>
<Falsy>
@ -375,6 +380,18 @@ export function FileContent({
source={decodeGitContent(base64Data)}
/>
</Case>
<Case val={FileCategory.SUBMODULE}>
<SourceCodeViewer
language={filenameToLanguage(filename)}
source={decodeGitContent(base64Data)}
/>
</Case>
<Case val={FileCategory.SYMLINK}>
<SourceCodeViewer
language={filenameToLanguage(filename)}
source={decodeGitContent(base64Data)}
/>
</Case>
</Match>
</Center>
</Falsy>

View File

@ -9,7 +9,7 @@
text-transform: none;
color: var(--grey-400);
font-weight: 500;
font-size: 13px;
font-size: 12px;
}
}
@ -24,7 +24,7 @@
margin-bottom: 0;
.rowText {
font-size: 13px;
font-size: 12px;
font-weight: 400;
}
}
@ -63,7 +63,7 @@
&,
.text {
font-size: 13px;
font-size: 12px;
font-weight: 400;
cursor: pointer !important;
}

View File

@ -9,10 +9,11 @@ import {
TextProps,
useIsMounted
} from '@harnessio/uicore'
import { Icon } from '@harnessio/icons'
import { Color } from '@harnessio/design-system'
import cx from 'classnames'
import type { CellProps, Column } from 'react-table'
import { Page } from 'iconoir-react'
import { Render } from 'react-jsx-match'
import { chunk, sortBy, throttle } from 'lodash-es'
import { useMutate } from 'restful-react'
@ -20,17 +21,30 @@ 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 } from 'utils/Utils'
import { findReadmeInfo, CodeIcon, GitInfoProps, isFile } from 'utils/GitUtils'
import { findReadmeInfo, GitInfoProps, isFile, isSymlink, isSubmodule } from 'utils/GitUtils'
import { LatestCommitForFolder } from 'components/LatestCommit/LatestCommit'
import { CommitActions } from 'components/CommitActions/CommitActions'
import { useEventListener } from 'hooks/useEventListener'
import { Readme } from './Readme'
import repositoryCSS from '../../Repository.module.scss'
import CodeFile from '../../../../icons/CodeFileFill.svg'
import CodeFolder from '../../../../icons/CodeFileFill.svg'
import Submodule from '../../../../icons/Submodules.svg'
import Symlink from '../../../../icons/Symlink.svg'
import css from './FolderContent.module.scss'
type FolderContentProps = Pick<GitInfoProps, 'repoMetadata' | 'resourceContent' | 'gitRef'>
const checkIcon = (row: OpenapiContentInfo): React.ReactElement => {
if (isFile(row)) {
return <Page width={14} height={14} />
} else if (isSymlink(row)) {
return <img width={14} height={14} src={Symlink} />
} else if (isSubmodule(row)) {
return <img width={14} height={14} src={Submodule} />
} else {
return <img width={14} height={14} src={CodeFolder} />
}
}
export function FolderContent({ repoMetadata, resourceContent, gitRef }: FolderContentProps) {
const history = useHistory()
const { routes, standalone } = useAppContext()
@ -40,23 +54,25 @@ export function FolderContent({ repoMetadata, resourceContent, gitRef }: FolderC
Header: 'Files',
id: 'name',
width: '30%',
Cell: ({ row }: CellProps<OpenapiContentInfo>) => (
<Container>
<Layout.Horizontal spacing="small">
{isFile(row.original) ? <Icon name={CodeIcon.File} /> : <img width={16} height={16} src={CodeFile} />}
<ListingItemLink
url={routes.toCODERepository({
repoPath: repoMetadata.path as string,
gitRef,
resourcePath: row.original.path
})}
text={row.original.name as string}
data-resource-path={row.original.path}
lineClamp={1}
/>
</Layout.Horizontal>
</Container>
)
Cell: ({ row }: CellProps<OpenapiContentInfo>) => {
return (
<Container>
<Layout.Horizontal spacing="small">
{checkIcon(row.original)}
<ListingItemLink
url={routes.toCODERepository({
repoPath: repoMetadata.path as string,
gitRef,
resourcePath: row.original.path
})}
text={row.original.name as string}
data-resource-path={row.original.path}
lineClamp={1}
/>
</Layout.Horizontal>
</Container>
)
}
},
{
Header: 'Date',

View File

@ -22,6 +22,13 @@ interface UseFileViewerDecisionResult {
isText: boolean
}
export interface RepoContentExtended extends RepoFileContent {
size?: number
target?: string
commit_sha?: string
url?: string
}
export function useFileContentViewerDecision({
repoMetadata,
gitRef,
@ -32,6 +39,9 @@ export function useFileContentViewerDecision({
const metadata = useMemo(() => {
const filename = resourceContent.name as string
const extension = filename?.split('.').pop() || ''
const isSymlink = resourceContent?.type === 'symlink'
const isSubmodule = resourceContent?.type === 'submodule'
const isMarkdown = extension.toLowerCase() === 'md'
const isPdf = extension.toLowerCase() === 'pdf'
const isSVG = extension.toLowerCase() === 'svg'
@ -40,7 +50,9 @@ export function useFileContentViewerDecision({
const isVideo = VideoExtensions.includes(extension.toLowerCase())
const isText = !!(
SpecialTextFiles.find(name => name.toLowerCase() === filename?.toLowerCase()) ||
TextExtensions.includes(extension.toLowerCase())
TextExtensions.includes(extension.toLowerCase()) ||
isSymlink ||
isSubmodule
)
const category = isMarkdown
? FileCategory.MARKDOWN
@ -54,12 +66,17 @@ export function useFileContentViewerDecision({
? FileCategory.AUDIO
: isVideo
? FileCategory.VIDEO
: isSymlink
? FileCategory.SYMLINK
: isSubmodule
? FileCategory.SUBMODULE
: isText
? FileCategory.TEXT
: FileCategory.OTHER
const isViewable = isPdf || isSVG || isImage || isAudio || isVideo || isText
const resourceData = resourceContent?.content as RepoFileContent
const isFileTooLarge = resourceData?.size !== resourceData?.data_size
const isViewable = isPdf || isSVG || isImage || isAudio || isVideo || isText || isSubmodule || isSymlink
const resourceData = resourceContent?.content as RepoContentExtended
const isFileTooLarge =
resourceData?.size && resourceData?.data_size ? resourceData?.size !== resourceData?.data_size : false
const rawURL = `/code/api/v1/repos/${repoMetadata?.path}/+/raw/${resourcePath}?routingId=${routingId}&git_ref=${gitRef}`
return {
category,
@ -73,7 +90,8 @@ export function useFileContentViewerDecision({
size: resourceData?.size || 0,
// base64 data returned from content API. This snapshot can be truncated by backend
base64Data: resourceData?.data || '',
base64Data: resourceData?.data || resourceData?.target || resourceData?.url || '',
rawURL
}
}, [resourceContent.content]) // eslint-disable-line react-hooks/exhaustive-deps
@ -91,6 +109,8 @@ export enum FileCategory {
AUDIO = 'AUDIO',
VIDEO = 'VIDEO',
TEXT = 'TEXT',
SYMLINK = 'SYMLINK',
SUBMODULE = 'SUBMODULE',
OTHER = 'OTHER'
}