mirror of
https://github.com/harness/drone.git
synced 2025-05-21 19:39:59 +08:00
feat: [CODE-215]: Move GitBlame to a separate tab + UI tweaks per Design
This commit is contained in:
parent
345540594f
commit
dc15e6bb18
@ -45,7 +45,7 @@ interface FormData {
|
||||
newBranch?: string
|
||||
}
|
||||
|
||||
interface CommitModalButtonProps extends Omit<ButtonProps, 'onClick' | 'onSubmit'>, Pick<GitInfoProps, 'repoMetadata'> {
|
||||
interface CommitModalProps extends Pick<GitInfoProps, 'repoMetadata'> {
|
||||
commitAction: GitCommitAction
|
||||
gitRef: string
|
||||
resourcePath: string
|
||||
@ -57,7 +57,7 @@ interface CommitModalButtonProps extends Omit<ButtonProps, 'onClick' | 'onSubmit
|
||||
onSuccess: (data: RepoCommitFilesResponse, newBranch?: string) => void
|
||||
}
|
||||
|
||||
export const CommitModalButton: React.FC<CommitModalButtonProps> = ({
|
||||
export function useCommitModal({
|
||||
repoMetadata,
|
||||
commitAction,
|
||||
gitRef,
|
||||
@ -67,9 +67,8 @@ export const CommitModalButton: React.FC<CommitModalButtonProps> = ({
|
||||
disableBranchCreation = false,
|
||||
payload = '',
|
||||
sha,
|
||||
onSuccess,
|
||||
...props
|
||||
}) => {
|
||||
onSuccess
|
||||
}: CommitModalProps) {
|
||||
const ModalComponent: React.FC = () => {
|
||||
const { getString } = useStrings()
|
||||
const [targetBranchOption, setTargetBranchOption] = useState(CommitToGitRefOption.DIRECTLY)
|
||||
@ -229,5 +228,46 @@ export const CommitModalButton: React.FC<CommitModalButtonProps> = ({
|
||||
|
||||
const [openModal, hideModal] = useModalHook(ModalComponent, [onSuccess, gitRef, resourcePath, commitTitlePlaceHolder])
|
||||
|
||||
return [openModal, hideModal]
|
||||
}
|
||||
|
||||
interface CommitModalButtonProps extends Omit<ButtonProps, 'onClick' | 'onSubmit'>, Pick<GitInfoProps, 'repoMetadata'> {
|
||||
commitAction: GitCommitAction
|
||||
gitRef: string
|
||||
resourcePath: string
|
||||
commitTitlePlaceHolder: string
|
||||
disableBranchCreation?: boolean
|
||||
oldResourcePath?: string
|
||||
payload?: string
|
||||
sha?: string
|
||||
onSuccess: (data: RepoCommitFilesResponse, newBranch?: string) => void
|
||||
}
|
||||
|
||||
export const CommitModalButton: React.FC<CommitModalButtonProps> = ({
|
||||
repoMetadata,
|
||||
commitAction,
|
||||
gitRef,
|
||||
resourcePath,
|
||||
commitTitlePlaceHolder,
|
||||
oldResourcePath,
|
||||
disableBranchCreation = false,
|
||||
payload = '',
|
||||
sha,
|
||||
onSuccess,
|
||||
...props
|
||||
}) => {
|
||||
const [openModal] = useCommitModal({
|
||||
repoMetadata,
|
||||
commitAction,
|
||||
gitRef,
|
||||
resourcePath,
|
||||
commitTitlePlaceHolder,
|
||||
oldResourcePath,
|
||||
disableBranchCreation,
|
||||
payload,
|
||||
sha,
|
||||
onSuccess
|
||||
})
|
||||
|
||||
return <Button onClick={openModal} {...props} />
|
||||
}
|
||||
|
@ -1,16 +1,5 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
Button,
|
||||
Container,
|
||||
Color,
|
||||
Layout,
|
||||
FlexExpander,
|
||||
Text,
|
||||
FontVariation,
|
||||
Avatar,
|
||||
ButtonVariation,
|
||||
ButtonSize
|
||||
} from '@harness/uicore'
|
||||
import { Container, Color, Layout, FlexExpander, Text, FontVariation, Avatar } from '@harness/uicore'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Render } from 'react-jsx-match'
|
||||
import ReactTimeago from 'react-timeago'
|
||||
@ -19,9 +8,8 @@ import type { TypesCommit } from 'services/code'
|
||||
import { CommitActions } from 'components/CommitActions/CommitActions'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import { formatDate } from 'utils/Utils'
|
||||
import { CodeIcon, GitInfoProps } from 'utils/GitUtils'
|
||||
import type { GitInfoProps } from 'utils/GitUtils'
|
||||
import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import css from './LatestCommit.module.scss'
|
||||
|
||||
interface LatestCommitProps extends Pick<GitInfoProps, 'repoMetadata'> {
|
||||
@ -60,7 +48,6 @@ export function LatestCommitForFolder({ repoMetadata, latestCommit, standaloneSt
|
||||
|
||||
export function LatestCommitForFile({ repoMetadata, latestCommit, standaloneStyle }: LatestCommitProps) {
|
||||
const { routes } = useAppContext()
|
||||
const { getString } = useStrings()
|
||||
const commitURL = routes.toCODECommits({
|
||||
repoPath: repoMetadata.path as string,
|
||||
commitRef: latestCommit?.sha as string
|
||||
@ -77,22 +64,17 @@ export function LatestCommitForFile({ repoMetadata, latestCommit, standaloneStyl
|
||||
{latestCommit?.author?.identity?.name || latestCommit?.author?.identity?.email}
|
||||
</Text>
|
||||
<PipeSeparator height={9} />
|
||||
|
||||
<Link to={commitURL} className={css.commitLink}>
|
||||
{latestCommit?.title}
|
||||
</Link>
|
||||
<PipeSeparator height={9} />
|
||||
<CommitActions sha={latestCommit?.sha as string} href={commitURL} />
|
||||
<PipeSeparator height={9} />
|
||||
<Text font={{ variation: FontVariation.SMALL }} color={Color.GREY_400}>
|
||||
{getString('onDate', { date: formatDate(latestCommit?.author?.when as string) })}
|
||||
{formatDate(latestCommit?.author?.when as string)}
|
||||
</Text>
|
||||
|
||||
<FlexExpander />
|
||||
<Button
|
||||
size={ButtonSize.SMALL}
|
||||
icon={CodeIcon.History}
|
||||
text={getString('history')}
|
||||
variation={ButtonVariation.PRIMARY}
|
||||
/>
|
||||
<CommitActions sha={latestCommit?.sha as string} href={commitURL} />
|
||||
</Layout.Horizontal>
|
||||
</Container>
|
||||
</Render>
|
||||
|
@ -14,6 +14,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
.isDark {
|
||||
.icon {
|
||||
svg path {
|
||||
fill: var(--white) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: var(--white) !important;
|
||||
padding: var(--spacing-xsmall) var(--spacing-small) !important;
|
||||
|
@ -13,6 +13,7 @@ type OptionsMenuItem = React.ComponentProps<typeof Menu.Item> & {
|
||||
text?: string
|
||||
hasIcon?: boolean
|
||||
iconName?: string
|
||||
iconSize?: number
|
||||
}
|
||||
|
||||
export interface OptionsMenuButtonProps extends ButtonProps {
|
||||
@ -42,14 +43,22 @@ export const OptionsMenuButton = ({
|
||||
<Menu.Item
|
||||
icon={
|
||||
(item as OptionsMenuItem).hasIcon ? (
|
||||
<Icon size={12} className={css.icon} name={(item as OptionsMenuItem).iconName as IconName} />
|
||||
<Icon
|
||||
size={(item as OptionsMenuItem).iconSize || 12}
|
||||
className={css.icon}
|
||||
name={(item as OptionsMenuItem).iconName as IconName}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
key={(item as React.ComponentProps<typeof Menu.Item>)?.text as string}
|
||||
className={cx(Classes.POPOVER_DISMISS, {
|
||||
className={cx(
|
||||
Classes.POPOVER_DISMISS,
|
||||
{
|
||||
[css.danger]: (item as OptionsMenuItem).isDanger,
|
||||
[css.isDark]: isDark
|
||||
})}
|
||||
},
|
||||
(item as OptionsMenuItem).className
|
||||
)}
|
||||
{...omit(
|
||||
item as IMenuItemProps & React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
||||
'isDanger',
|
||||
|
17
web/src/components/PlainButton/PlainButton.module.scss
Normal file
17
web/src/components/PlainButton/PlainButton.module.scss
Normal file
@ -0,0 +1,17 @@
|
||||
.btn {
|
||||
--border: 1px solid var(--grey-200) !important;
|
||||
--background-color: var(--white) !important;
|
||||
--background-color-active: var(--white) !important;
|
||||
--box-shadow: none !important;
|
||||
|
||||
&:active,
|
||||
&:hover,
|
||||
&[class*='bp3-active'] {
|
||||
--border: 1px solid var(--primary-7) !important;
|
||||
}
|
||||
|
||||
.prefix {
|
||||
color: var(--grey-450) !important;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
7
web/src/components/PlainButton/PlainButton.module.scss.d.ts
vendored
Normal file
7
web/src/components/PlainButton/PlainButton.module.scss.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/* eslint-disable */
|
||||
// this is an auto-generated file
|
||||
declare const styles: {
|
||||
readonly btn: string
|
||||
readonly prefix: string
|
||||
}
|
||||
export default styles
|
5
web/src/components/PlainButton/PlainButton.tsx
Normal file
5
web/src/components/PlainButton/PlainButton.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Button, ButtonProps } from '@harness/uicore'
|
||||
import css from './PlainButton.module.scss'
|
||||
|
||||
export const PlainButton: React.FC<ButtonProps> = props => <Button className={css.btn} {...props} />
|
@ -48,7 +48,7 @@ export function RepositoryPageHeader({
|
||||
</Fragment>
|
||||
))}
|
||||
</Layout.Horizontal>
|
||||
<Container padding={{ top: 'large', bottom: 'small' }}>
|
||||
<Container padding={{ top: 'small', bottom: 'small' }}>
|
||||
{typeof title === 'string' ? (
|
||||
<Text tag="h1" font={{ variation: FontVariation.H4 }} tooltipProps={{ dataTooltipId }}>
|
||||
{title}
|
||||
|
@ -17,6 +17,7 @@ export interface StringsMap {
|
||||
and: string
|
||||
approve: string
|
||||
ascending: string
|
||||
blame: string
|
||||
blameCommitLine: string
|
||||
botAlerts: string
|
||||
branch: string
|
||||
@ -95,6 +96,7 @@ export interface StringsMap {
|
||||
diff: string
|
||||
disableWebhookContent: string
|
||||
disableWebhookTitle: string
|
||||
download: string
|
||||
draft: string
|
||||
edit: string
|
||||
editFile: string
|
||||
@ -307,6 +309,7 @@ export interface StringsMap {
|
||||
viewAllBranches: string
|
||||
viewAllTags: string
|
||||
viewCommitDetails: string
|
||||
viewRaw: string
|
||||
viewed: string
|
||||
webhook: string
|
||||
webhookAllEventsSelected: string
|
||||
|
@ -364,7 +364,7 @@ deleteRepoText: Are you sure you want to delete the repository '{REPONAME}'?
|
||||
deleteRepoTitle: Delete the repository
|
||||
resolve: Resolve
|
||||
generateCloneCred: + Generate Clone Credential
|
||||
generateCloneText: "Please generate clone credential if it’s your first time"
|
||||
generateCloneText: 'Please generate clone credential if it’s your first time'
|
||||
getMyCloneTitle: Get My Clone Credential
|
||||
cloneText: Your clone credentials have been generated. Please make sure to copy and store your password somewhere safe, you won't be able to see it again.
|
||||
manageApiToken: Manage Api Token
|
||||
@ -372,3 +372,6 @@ userName: User Name
|
||||
passwordApi: Password (API Token)
|
||||
firstTimeTitle: Please generate Git Credentials if it’s your first time to clone the repository
|
||||
manageCredText: You can also manage your git credential {URL}
|
||||
blame: Blame
|
||||
viewRaw: View Raw
|
||||
download: Download
|
||||
|
@ -37,7 +37,6 @@
|
||||
height: 24px;
|
||||
margin-top: var(--spacing-8);
|
||||
|
||||
|
||||
> svg {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
|
@ -105,7 +105,6 @@ export default function PullRequest() {
|
||||
: PullRequestSection.CONVERSATION,
|
||||
[pullRequestSection]
|
||||
)
|
||||
// /repos/${paramsInPath.repo_ref}/pullreq/${paramsInPath.pullreq_number}/metadata
|
||||
|
||||
return (
|
||||
<Container className={css.main}>
|
||||
|
@ -1,4 +1,6 @@
|
||||
.main {
|
||||
padding: var(--spacing-large) var(--spacing-xlarge) 0 var(--spacing-xlarge) !important;
|
||||
|
||||
div[class*='TextInput'] {
|
||||
margin-bottom: 0 !important;
|
||||
margin-left: 0 !important;
|
||||
@ -11,7 +13,8 @@
|
||||
|
||||
> div {
|
||||
align-items: center;
|
||||
padding-bottom: var(--spacing-xlarge) !important;
|
||||
padding-bottom: var(--spacing-large) !important;
|
||||
// border-bottom: 1px solid var(--grey-100);
|
||||
}
|
||||
|
||||
.btnColorFix > span[data-icon] {
|
||||
|
@ -16,3 +16,63 @@
|
||||
padding: var(--spacing-xxlarge) 0 var(--spacing-large) var(--spacing-medium) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.fileContent {
|
||||
padding: var(--spacing-small) var(--spacing-xlarge) var(--spacing-xlarge) var(--spacing-xlarge) !important;
|
||||
}
|
||||
|
||||
.gitBlame {
|
||||
padding: var(--spacing-xlarge) !important;
|
||||
}
|
||||
|
||||
.tabsContainer {
|
||||
background-color: var(--primary-bg) !important;
|
||||
|
||||
> div > div[role='tablist'] {
|
||||
background-color: var(--white) !important;
|
||||
padding-left: var(--spacing-large) !important;
|
||||
padding-right: var(--spacing-xlarge) !important;
|
||||
border-bottom: 1px solid var(--grey-200) !important;
|
||||
}
|
||||
|
||||
> div > div[role='tabpanel'] {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
[aria-selected='true'] {
|
||||
.tabTitle,
|
||||
.tabTitle:hover {
|
||||
color: var(--grey-900) !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.tabTitle {
|
||||
font-weight: 500;
|
||||
color: var(--grey-700);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 24px;
|
||||
margin-top: var(--spacing-8);
|
||||
|
||||
> svg {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.count {
|
||||
margin-left: var(--spacing-small);
|
||||
display: inline-block;
|
||||
border-radius: 8px;
|
||||
font-weight: 500;
|
||||
font-size: var(--font-size-small);
|
||||
color: var(--primary-7) !important;
|
||||
background-color: var(--primary-1) !important;
|
||||
padding: 3px 6px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.tabTitle:not:first-child {
|
||||
margin-left: var(--spacing-8) !important;
|
||||
}
|
||||
}
|
||||
|
@ -4,5 +4,10 @@ declare const styles: {
|
||||
readonly container: string
|
||||
readonly heading: string
|
||||
readonly content: string
|
||||
readonly fileContent: string
|
||||
readonly gitBlame: string
|
||||
readonly tabsContainer: string
|
||||
readonly tabTitle: string
|
||||
readonly count: string
|
||||
}
|
||||
export default styles
|
||||
|
@ -1,21 +1,20 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import {
|
||||
Button,
|
||||
ButtonSize,
|
||||
ButtonVariation,
|
||||
Color,
|
||||
Container,
|
||||
FlexExpander,
|
||||
Heading,
|
||||
Layout,
|
||||
useToggle,
|
||||
Tabs,
|
||||
Utils
|
||||
} from '@harness/uicore'
|
||||
import { Else, Match, Render, Truthy } from 'react-jsx-match'
|
||||
import { Render } from 'react-jsx-match'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { SourceCodeViewer } from 'components/SourceCodeViewer/SourceCodeViewer'
|
||||
import type { OpenapiContentInfo, RepoFileContent } from 'services/code'
|
||||
import {
|
||||
CodeIcon,
|
||||
decodeGitContent,
|
||||
findMarkdownInfo,
|
||||
GitCommitAction,
|
||||
@ -26,13 +25,20 @@ import {
|
||||
import { filenameToLanguage } from 'utils/Utils'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import { LatestCommitForFile } from 'components/LatestCommit/LatestCommit'
|
||||
import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator'
|
||||
import { CommitModalButton } from 'components/CommitModalButton/CommitModalButton'
|
||||
import { useCommitModal } from 'components/CommitModalButton/CommitModalButton'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { OptionsMenuButton } from 'components/OptionsMenuButton/OptionsMenuButton'
|
||||
import { PlainButton } from 'components/PlainButton/PlainButton'
|
||||
import { Readme } from '../FolderContent/Readme'
|
||||
import { GitBlame } from './GitBlame'
|
||||
import css from './FileContent.module.scss'
|
||||
|
||||
enum FileSection {
|
||||
CONTENT = 'content',
|
||||
BLAME = 'blame',
|
||||
HISTORY = 'history'
|
||||
}
|
||||
|
||||
export function FileContent({
|
||||
repoMetadata,
|
||||
gitRef,
|
||||
@ -42,58 +48,18 @@ export function FileContent({
|
||||
const { routes } = useAppContext()
|
||||
const { getString } = useStrings()
|
||||
const history = useHistory()
|
||||
const [showGitBlame, toggleGitBlame] = useToggle(false)
|
||||
const content = useMemo(
|
||||
() => decodeGitContent((resourceContent?.content as RepoFileContent)?.data),
|
||||
[resourceContent?.content]
|
||||
)
|
||||
const markdownInfo = useMemo(() => findMarkdownInfo(resourceContent), [resourceContent])
|
||||
|
||||
return (
|
||||
<Layout.Vertical spacing="small">
|
||||
<LatestCommitForFile repoMetadata={repoMetadata} latestCommit={resourceContent.latest_commit} standaloneStyle />
|
||||
<Container className={css.container} background={Color.WHITE}>
|
||||
<Layout.Horizontal padding="small" className={css.heading}>
|
||||
<Heading level={5} color={Color.BLACK}>
|
||||
{resourceContent.name}
|
||||
</Heading>
|
||||
<FlexExpander />
|
||||
<Layout.Horizontal spacing="xsmall">
|
||||
<Button
|
||||
variation={ButtonVariation.ICON}
|
||||
icon={CodeIcon.Edit}
|
||||
tooltip={isRefATag(gitRef) ? getString('editNotAllowed') : getString('edit')}
|
||||
tooltipProps={{ isDark: true }}
|
||||
disabled={isRefATag(gitRef)}
|
||||
onClick={() => {
|
||||
history.push(
|
||||
routes.toCODEFileEdit({
|
||||
repoPath: repoMetadata.path as string,
|
||||
const [openDeleteFileModal] = useCommitModal({
|
||||
repoMetadata,
|
||||
gitRef,
|
||||
resourcePath
|
||||
})
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
variation={ButtonVariation.ICON}
|
||||
tooltip={getString('copy')}
|
||||
icon={CodeIcon.Copy}
|
||||
tooltipProps={{ isDark: true }}
|
||||
onClick={() => Utils.copy(content)}
|
||||
/>
|
||||
<CommitModalButton
|
||||
variation={ButtonVariation.ICON}
|
||||
icon={CodeIcon.Delete}
|
||||
disabled={isRefATag(gitRef)}
|
||||
tooltip={getString(isRefATag(gitRef) ? 'deleteNotAllowed' : 'delete')}
|
||||
tooltipProps={{ isDark: true }}
|
||||
repoMetadata={repoMetadata}
|
||||
gitRef={gitRef}
|
||||
resourcePath={resourcePath}
|
||||
commitAction={GitCommitAction.DELETE}
|
||||
commitTitlePlaceHolder={getString('deleteFile').replace('__path__', resourcePath)}
|
||||
onSuccess={(_commitInfo, newBranch) => {
|
||||
resourcePath,
|
||||
commitAction: GitCommitAction.DELETE,
|
||||
commitTitlePlaceHolder: getString('deleteFile').replace('__path__', resourcePath),
|
||||
onSuccess: (_commitInfo, newBranch) => {
|
||||
if (newBranch) {
|
||||
history.replace(
|
||||
routes.toCODECompare({
|
||||
@ -109,26 +75,107 @@ export function FileContent({
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<Container className={css.tabsContainer}>
|
||||
<Tabs
|
||||
id="fileTabs"
|
||||
defaultSelectedTabId={FileSection.CONTENT}
|
||||
large={false}
|
||||
tabList={[
|
||||
{
|
||||
id: FileSection.CONTENT,
|
||||
title: getString('content'),
|
||||
panel: (
|
||||
<Container className={css.fileContent}>
|
||||
<Layout.Vertical spacing="small">
|
||||
<LatestCommitForFile
|
||||
repoMetadata={repoMetadata}
|
||||
latestCommit={resourceContent.latest_commit}
|
||||
standaloneStyle
|
||||
/>
|
||||
<Container className={css.container} background={Color.WHITE}>
|
||||
<Layout.Horizontal padding="small" className={css.heading}>
|
||||
<Heading level={5} color={Color.BLACK}>
|
||||
{resourceContent.name}
|
||||
</Heading>
|
||||
<FlexExpander />
|
||||
<Layout.Horizontal spacing="xsmall" style={{ alignItems: 'center' }}>
|
||||
<PlainButton
|
||||
withoutCurrentColor
|
||||
size={ButtonSize.SMALL}
|
||||
variation={ButtonVariation.TERTIARY}
|
||||
iconProps={{ size: 16 }}
|
||||
text={getString('edit')}
|
||||
icon="code-edit"
|
||||
tooltip={isRefATag(gitRef) ? getString('editNotAllowed') : undefined}
|
||||
tooltipProps={{ isDark: true }}
|
||||
disabled={isRefATag(gitRef)}
|
||||
onClick={() => {
|
||||
history.push(
|
||||
routes.toCODEFileEdit({
|
||||
repoPath: repoMetadata.path as string,
|
||||
gitRef,
|
||||
resourcePath
|
||||
})
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<PipeSeparator />
|
||||
<Container padding={{ left: 'small', right: 'xsmall' }}>
|
||||
<Button
|
||||
variation={ButtonVariation.SECONDARY}
|
||||
text={showGitBlame ? 'View File' : 'Blame'}
|
||||
onClick={toggleGitBlame}
|
||||
<OptionsMenuButton
|
||||
isDark={true}
|
||||
icon="Options"
|
||||
iconProps={{ size: 14 }}
|
||||
style={{ padding: '5px' }}
|
||||
width="145px"
|
||||
items={[
|
||||
{
|
||||
hasIcon: true,
|
||||
iconName: 'arrow-right',
|
||||
text: getString('viewRaw'),
|
||||
onClick: () => {
|
||||
window.open(
|
||||
`/code/api/v1/repos/${
|
||||
repoMetadata?.path
|
||||
}/+/raw/${resourcePath}?${`git_ref=${gitRef}`}`,
|
||||
'_blank'
|
||||
)
|
||||
}
|
||||
},
|
||||
'-',
|
||||
{
|
||||
hasIcon: true,
|
||||
iconName: 'cloud-download',
|
||||
text: getString('download'),
|
||||
download: resourceContent?.name || 'download',
|
||||
href: `/code/api/v1/repos/${
|
||||
repoMetadata?.path
|
||||
}/+/raw/${resourcePath}?${`git_ref=${gitRef}`}`
|
||||
},
|
||||
{
|
||||
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
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</Container>
|
||||
</Layout.Horizontal>
|
||||
</Layout.Horizontal>
|
||||
|
||||
<Render when={(resourceContent?.content as RepoFileContent)?.data}>
|
||||
<Container className={css.content}>
|
||||
<Match expr={showGitBlame}>
|
||||
<Truthy>
|
||||
<GitBlame repoMetadata={repoMetadata} resourcePath={resourcePath} />
|
||||
</Truthy>
|
||||
<Else>
|
||||
<Render when={!markdownInfo}>
|
||||
<SourceCodeViewer language={filenameToLanguage(resourceContent?.name)} source={content} />
|
||||
</Render>
|
||||
@ -141,11 +188,24 @@ export function FileContent({
|
||||
gitRef={gitRef}
|
||||
/>
|
||||
</Render>
|
||||
</Else>
|
||||
</Match>
|
||||
</Container>
|
||||
</Render>
|
||||
</Container>
|
||||
</Layout.Vertical>
|
||||
</Container>
|
||||
)
|
||||
},
|
||||
{
|
||||
id: FileSection.BLAME,
|
||||
title: getString('blame'),
|
||||
panel: (
|
||||
<Container className={css.gitBlame}>
|
||||
<GitBlame repoMetadata={repoMetadata} resourcePath={resourcePath} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
@ -5,9 +5,16 @@
|
||||
|
||||
:global {
|
||||
.cm-editor {
|
||||
border: none !important;
|
||||
|
||||
.cm-scroller {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.cm-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.cm-line {
|
||||
&,
|
||||
* {
|
||||
@ -28,8 +35,7 @@
|
||||
|
||||
.gitBlame {
|
||||
--code-editor-border-color: var(--grey-200);
|
||||
|
||||
padding: 0 var(--spacing-xlarge) 0 var(--spacing-small) !important;
|
||||
// padding: 0 var(--spacing-xlarge) 0 var(--spacing-small) !important;
|
||||
|
||||
:global {
|
||||
.cm-gutter {
|
||||
|
@ -240,6 +240,7 @@ const GitBlameRenderer = React.memo(function GitBlameSourceViewer({
|
||||
className={css.main}
|
||||
onViewUpdate={onViewUpdate}
|
||||
extensions={extensions.of([])}
|
||||
maxHeight="auto"
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
@ -1,4 +1,6 @@
|
||||
.folderContent {
|
||||
padding: 0 var(--spacing-xlarge) var(--spacing-xlarge) var(--spacing-xlarge) !important;
|
||||
|
||||
.table {
|
||||
background-color: var(--white) !important;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Container, Color, Layout, Button, FlexExpander, ButtonVariation, Heading, Icon } from '@harness/uicore'
|
||||
import { Container, Color, Layout, FlexExpander, ButtonVariation, Heading, Icon, ButtonSize } from '@harness/uicore'
|
||||
import { Render } from 'react-jsx-match'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useGet } from 'restful-react'
|
||||
@ -7,8 +7,10 @@ import cx from 'classnames'
|
||||
import { MarkdownViewer } from 'components/MarkdownViewer/MarkdownViewer'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import type { OpenapiContentInfo, OpenapiGetContentOutput, RepoFileContent, TypesRepository } from 'services/code'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { useShowRequestError } from 'hooks/useShowRequestError'
|
||||
import { CodeIcon, decodeGitContent } from 'utils/GitUtils'
|
||||
import { decodeGitContent } from 'utils/GitUtils'
|
||||
import { PlainButton } from 'components/PlainButton/PlainButton'
|
||||
import css from './Readme.module.scss'
|
||||
|
||||
interface FolderContentProps {
|
||||
@ -20,6 +22,7 @@ interface FolderContentProps {
|
||||
}
|
||||
|
||||
function ReadmeViewer({ metadata, gitRef, readmeInfo, contentOnly, maxWidth }: FolderContentProps) {
|
||||
const { getString } = useStrings()
|
||||
const history = useHistory()
|
||||
const { routes } = useAppContext()
|
||||
|
||||
@ -43,9 +46,13 @@ function ReadmeViewer({ metadata, gitRef, readmeInfo, contentOnly, maxWidth }: F
|
||||
<Heading level={5}>{readmeInfo.name}</Heading>
|
||||
<FlexExpander />
|
||||
{loading && <Icon name="spinner" color={Color.PRIMARY_7} />}
|
||||
<Button
|
||||
variation={ButtonVariation.ICON}
|
||||
icon={CodeIcon.Edit}
|
||||
<PlainButton
|
||||
withoutCurrentColor
|
||||
size={ButtonSize.SMALL}
|
||||
variation={ButtonVariation.TERTIARY}
|
||||
iconProps={{ size: 16 }}
|
||||
text={getString('edit')}
|
||||
icon="code-edit"
|
||||
onClick={() => {
|
||||
history.push(
|
||||
routes.toCODEFileEdit({
|
||||
|
@ -1,3 +1,5 @@
|
||||
.resourceContent {
|
||||
background-color: var(--primary-bg);
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ export function RepositoryContent({
|
||||
resourceContent
|
||||
}: Pick<GitInfoProps, 'repoMetadata' | 'gitRef' | 'resourcePath' | 'resourceContent'>) {
|
||||
return (
|
||||
<Container padding="xlarge" className={css.resourceContent}>
|
||||
<Container className={css.resourceContent}>
|
||||
<ContentHeader
|
||||
repoMetadata={repoMetadata}
|
||||
gitRef={gitRef}
|
||||
|
@ -27,18 +27,17 @@ export function permissionProps(permResult: { disabled: boolean; tooltip: JSX.El
|
||||
}
|
||||
|
||||
export function generateAlphaNumericHash(length: number) {
|
||||
let result = '';
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
const charactersLength = characters.length;
|
||||
let result = ''
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||
const charactersLength = characters.length
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength))
|
||||
}
|
||||
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
export const dayAgoInMS = 86400000
|
||||
|
||||
export const getErrorMessage = (error: Unknown): string =>
|
||||
|
Loading…
Reference in New Issue
Block a user