import React, { useEffect, useMemo, useRef, useState } from 'react' import { useGet } from 'restful-react' import { ButtonSize, ButtonVariation, Container, FlexExpander, Heading, Layout, StringSubstitute, Tabs, Utils } from '@harnessio/uicore' import { Icon } from '@harnessio/icons' import { Color } from '@harnessio/design-system' import { Document, Page, pdfjs } from 'react-pdf' import { Render, Match, Truthy, Falsy, Case, Else } from 'react-jsx-match' import { Link, useHistory } from 'react-router-dom' import { SourceCodeViewer } from 'components/SourceCodeViewer/SourceCodeViewer' import type { OpenapiContentInfo, RepoFileContent, TypesCommit } from 'services/code' import { decodeGitContent, findMarkdownInfo, GitCommitAction, GitInfoProps, isRefATag, makeDiffRefs } from 'utils/GitUtils' import { filenameToLanguage, permissionProps, LIST_FETCHING_LIMIT, RenameDetails, FileSection } from 'utils/Utils' import { useAppContext } from 'AppContext' import { LatestCommitForFile } from 'components/LatestCommit/LatestCommit' import { useCommitModal } from 'components/CommitModalButton/CommitModalButton' import { useStrings } from 'framework/strings' import { getConfig } from 'services/config' import { OptionsMenuButton } from 'components/OptionsMenuButton/OptionsMenuButton' import { PlainButton } from 'components/PlainButton/PlainButton' import { CommitsView } from 'components/CommitsView/CommitsView' import { useGetSpaceParam } from 'hooks/useGetSpaceParam' import { FileCategory, RepoContentExtended, useFileContentViewerDecision } from 'utils/FileUtils' import { useDownloadRawFile } from 'hooks/useDownloadRawFile' import { usePageIndex } from 'hooks/usePageIndex' import { Readme } from '../FolderContent/Readme' import { GitBlame } from './GitBlame' import RenameContentHistory from './RenameContentHistory' import css from './FileContent.module.scss' export function FileContent({ repoMetadata, gitRef, resourcePath, resourceContent, commitRef }: Pick) { const { routes } = useAppContext() const { getString } = useStrings() const downloadFile = useDownloadRawFile() const { category, isText, isFileTooLarge, isViewable, filename, extension, size, base64Data, rawURL } = useFileContentViewerDecision({ repoMetadata, gitRef, resourcePath, resourceContent }) const history = useHistory() const [activeTab, setActiveTab] = React.useState(FileSection.CONTENT) const content = useMemo( () => decodeGitContent((resourceContent?.content as RepoFileContent)?.data), [resourceContent?.content] ) const markdownInfo = useMemo(() => findMarkdownInfo(resourceContent), [resourceContent]) const [openDeleteFileModal] = useCommitModal({ repoMetadata, gitRef, resourcePath, commitAction: GitCommitAction.DELETE, commitTitlePlaceHolder: getString('deleteFile').replace('__path__', resourcePath), onSuccess: (_commitInfo, newBranch) => { if (newBranch) { history.replace( routes.toCODECompare({ repoPath: repoMetadata.path as string, diffRefs: makeDiffRefs(repoMetadata?.default_branch as string, newBranch) }) ) } else { history.push( routes.toCODERepository({ repoPath: repoMetadata.path as string, gitRef }) ) } } }) const { standalone } = useAppContext() const { hooks } = useAppContext() const space = useGetSpaceParam() const permPushResult = hooks?.usePermissionTranslate?.( { resource: { resourceType: 'CODE_REPOSITORY' }, permissions: ['code_repo_push'] }, [space] ) const permsFinal = useMemo(() => { const perms = permissionProps(permPushResult, standalone) if (isRefATag(gitRef) && perms) { return { tooltip: perms.tooltip, disabled: true } } if (isRefATag(gitRef)) { return { tooltip: getString('editNotAllowed'), disabled: true } } else if (perms?.disabled) { return { disabled: perms.disabled, tooltip: perms.tooltip } } return { disabled: isRefATag(gitRef) || false, tooltip: undefined } }, [permPushResult, gitRef]) // eslint-disable-line react-hooks/exhaustive-deps const [pdfWidth, setPdfWidth] = useState(700) const ref = useRef(null) const [numPages, setNumPages] = useState() useEffect(() => { if (ref.current) { const width = Math.min(Math.max(ref.current.clientWidth - 100, 700), 1800) if (pdfWidth !== width) { setPdfWidth(width) } } }, [pdfWidth, ref.current?.clientWidth]) const [page] = usePageIndex() const { data: commits } = useGet<{ commits: TypesCommit[]; rename_details: RenameDetails[] }>({ path: `/api/v1/repos/${repoMetadata?.path}/+/commits`, queryParams: { limit: LIST_FETCHING_LIMIT, page, git_ref: commitRef || gitRef || repoMetadata?.default_branch, path: resourcePath }, lazy: !repoMetadata }) const editButtonDisabled = useMemo(() => permsFinal.disabled || !isText, [permsFinal.disabled, isText]) const editAsText = useMemo( () => editButtonDisabled && !isFileTooLarge && category === FileCategory.OTHER, [editButtonDisabled, isFileTooLarge, category] ) return ( setActiveTab(id)} tabList={[ { id: FileSection.CONTENT, title: getString('content'), panel: ( {resourceContent.name} { history.push( routes.toCODEFileEdit({ repoPath: repoMetadata.path as string, gitRef, resourcePath }) ) }} /> { const url = standalone ? rawURL.replace(/^\/code/, '') : getConfig(rawURL).replace('//', '/') window.open(url, '_blank') } }, '-', { hasIcon: true, iconName: 'cloud-download', text: getString('download'), onClick: () => downloadFile({ repoMetadata, resourcePath, gitRef, filename }) }, { hasIcon: true, iconName: 'code-copy', iconSize: 16, text: getString('copy'), onClick: () => Utils.copy(content) }, { hasIcon: true, iconName: 'code-delete', iconSize: 16, title: getString(isRefATag(gitRef) ? 'deleteNotAllowed' : 'delete'), disabled: isRefATag(gitRef), text: getString('delete'), onClick: openDeleteFileModal } ]} />
rawURL: {rawURL} { Utils.stopEvent(e) downloadFile({ repoMetadata, resourcePath, gitRef, filename }) }}> {getString('download')}
setNumPages(nextNumPages)}> {Array.from(new Array(numPages), (_el, index) => ( ))} { Utils.stopEvent(e) downloadFile({ repoMetadata, resourcePath, gitRef, filename }) }}> {getString('clickHereToDownload')} ) }} />
{filename} {filename} setNumPages(nextNumPages)}> {Array.from(new Array(numPages), (_el, index) => ( ))}
) }, { id: FileSection.BLAME, title: getString('blame'), panel: ( {[resourcePath + gitRef].map(key => ( ))} ) }, { id: FileSection.HISTORY, title: getString('history'), panel: ( <> {repoMetadata && !!commits?.commits?.length && ( <> {commits?.rename_details && repoMetadata ? ( ) : null} )} ) } ]} />
) } const Center: React.FC = ({ children }) => ( {children} )