mirror of
https://github.com/harness/drone.git
synced 2025-05-16 17:09:58 +08:00
feat: Allow empty PR description
This commit is contained in:
parent
674dcc11d2
commit
404631a22d
@ -27,7 +27,7 @@ import type { CODERoutes } from 'RouteDefinitions'
|
||||
import css from './CommitsView.module.scss'
|
||||
|
||||
interface CommitsViewProps extends Pick<GitInfoProps, 'repoMetadata'> {
|
||||
commits: TypesCommit[]
|
||||
commits: TypesCommit[] | null
|
||||
emptyTitle: string
|
||||
emptyMessage: string
|
||||
prHasChanged?: boolean
|
||||
@ -116,7 +116,7 @@ export function CommitsView({
|
||||
/>
|
||||
)}
|
||||
</Layout.Horizontal>
|
||||
{!!commits.length &&
|
||||
{!!commits?.length &&
|
||||
Object.entries(commitsGroupedByDate).map(([date, commitsByDate]) => {
|
||||
return (
|
||||
<ThreadSection
|
||||
|
@ -8,7 +8,11 @@ export enum UserPreference {
|
||||
PULL_REQUEST_CREATION_OPTION = 'PULL_REQUEST_CREATION_OPTION'
|
||||
}
|
||||
|
||||
export function useUserPreference<T = string>(key: UserPreference, defaultValue: T): [T, (val: T) => void] {
|
||||
export function useUserPreference<T = string>(
|
||||
key: UserPreference,
|
||||
defaultValue: T,
|
||||
filter: (val: T) => boolean = () => true
|
||||
): [T, (val: T) => void] {
|
||||
const prefKey = `CODE_MOD_USER_PREF__${key}`
|
||||
const convert = useCallback(
|
||||
val => {
|
||||
@ -40,14 +44,16 @@ export function useUserPreference<T = string>(key: UserPreference, defaultValue:
|
||||
const savePreference = useCallback(
|
||||
(val: T) => {
|
||||
try {
|
||||
if (filter(val)) {
|
||||
localStorage[prefKey] = Array.isArray(val) || typeof val === 'object' ? JSON.stringify(val) : val
|
||||
}
|
||||
} catch (exception) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('useUserPreference: Failed to stringify object', val)
|
||||
}
|
||||
setPreference(val)
|
||||
},
|
||||
[prefKey]
|
||||
[prefKey, filter]
|
||||
)
|
||||
|
||||
return [preference, savePreference]
|
||||
|
@ -85,16 +85,12 @@ export default function Compare() {
|
||||
return showToaster(getString('pr.titleIsRequired'))
|
||||
}
|
||||
|
||||
if (!description) {
|
||||
return showToaster(getString('pr.descIsRequired'))
|
||||
}
|
||||
|
||||
const pullReqUrl = window.location.href.split('compare')?.[0]
|
||||
const payload: OpenapiCreatePullReqRequest = {
|
||||
target_branch: targetGitRef,
|
||||
source_branch: sourceGitRef,
|
||||
title: title,
|
||||
description: description,
|
||||
description: description || '',
|
||||
is_draft: creationType === PRCreationType.DRAFT
|
||||
}
|
||||
|
||||
@ -243,7 +239,7 @@ export default function Compare() {
|
||||
</Container>
|
||||
<Container className={css.markdownContainer}>
|
||||
<Layout.Vertical spacing="small">
|
||||
<Text font={{ variation: FontVariation.SMALL_BOLD }}>{getString('description')} *</Text>
|
||||
<Text font={{ variation: FontVariation.SMALL_BOLD }}>{getString('description')}</Text>
|
||||
<MarkdownEditorWithPreview
|
||||
value={description}
|
||||
onChange={setDescription}
|
||||
|
@ -27,13 +27,17 @@ import css from './Conversation.module.scss'
|
||||
export interface ConversationProps extends Pick<GitInfoProps, 'repoMetadata' | 'pullRequestMetadata'> {
|
||||
onCommentUpdate: () => void
|
||||
prHasChanged?: boolean
|
||||
showEditDescription?: boolean
|
||||
onCancelEditDescription: () => void
|
||||
}
|
||||
|
||||
export const Conversation: React.FC<ConversationProps> = ({
|
||||
repoMetadata,
|
||||
pullRequestMetadata,
|
||||
onCommentUpdate,
|
||||
prHasChanged
|
||||
prHasChanged,
|
||||
showEditDescription,
|
||||
onCancelEditDescription
|
||||
}) => {
|
||||
const { getString } = useStrings()
|
||||
const { currentUser } = useAppContext()
|
||||
@ -116,6 +120,10 @@ export const Conversation: React.FC<ConversationProps> = ({
|
||||
onCommentUpdate()
|
||||
refetchActivities()
|
||||
}, [onCommentUpdate, refetchActivities])
|
||||
const hasDescription = useMemo(
|
||||
() => !!pullRequestMetadata?.description?.length,
|
||||
[pullRequestMetadata?.description?.length]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (prHasChanged) {
|
||||
@ -136,12 +144,17 @@ export const Conversation: React.FC<ConversationProps> = ({
|
||||
<Layout.Horizontal>
|
||||
<Container width={`70%`}>
|
||||
<Layout.Vertical spacing="xlarge">
|
||||
{(hasDescription || showEditDescription) && (
|
||||
<DescriptionBox
|
||||
repoMetadata={repoMetadata}
|
||||
pullRequestMetadata={pullRequestMetadata}
|
||||
onCommentUpdate={onCommentUpdate}
|
||||
onCancelEditDescription={onCancelEditDescription}
|
||||
/>
|
||||
<Layout.Horizontal className={css.sortContainer} padding={{ top: 'xxlarge', bottom: 'medium' }}>
|
||||
)}
|
||||
<Layout.Horizontal
|
||||
className={css.sortContainer}
|
||||
padding={{ top: hasDescription || showEditDescription ? 'xxlarge' : undefined, bottom: 'medium' }}>
|
||||
<Container>
|
||||
<Select
|
||||
items={activityFilters}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { Container, useToaster } from '@harness/uicore'
|
||||
import cx from 'classnames'
|
||||
import { useMutate } from 'restful-react'
|
||||
@ -12,10 +12,15 @@ import { getErrorMessage } from 'utils/Utils'
|
||||
import type { ConversationProps } from './Conversation'
|
||||
import css from './Conversation.module.scss'
|
||||
|
||||
export const DescriptionBox: React.FC<ConversationProps> = ({
|
||||
interface DescriptionBoxProps extends Omit<ConversationProps, 'onCancelEditDescription'> {
|
||||
onCancelEditDescription: () => void
|
||||
}
|
||||
|
||||
export const DescriptionBox: React.FC<DescriptionBoxProps> = ({
|
||||
repoMetadata,
|
||||
pullRequestMetadata,
|
||||
onCommentUpdate: refreshPullRequestMetadata
|
||||
onCommentUpdate: refreshPullRequestMetadata,
|
||||
onCancelEditDescription
|
||||
}) => {
|
||||
const [edit, setEdit] = useState(false)
|
||||
const [dirty, setDirty] = useState(false)
|
||||
@ -28,6 +33,10 @@ export const DescriptionBox: React.FC<ConversationProps> = ({
|
||||
path: `/api/v1/repos/${repoMetadata.path}/+/pullreq/${pullRequestMetadata.number}`
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
setEdit(!pullRequestMetadata?.description?.length)
|
||||
}, [pullRequestMetadata?.description?.length])
|
||||
|
||||
return (
|
||||
<Container className={cx({ [css.box]: !edit, [css.desc]: !edit })}>
|
||||
<Container padding={!edit ? { left: 'small', bottom: 'small' } : undefined}>
|
||||
@ -37,14 +46,13 @@ export const DescriptionBox: React.FC<ConversationProps> = ({
|
||||
onSave={value => {
|
||||
const payload: OpenapiUpdatePullReqRequest = {
|
||||
title: pullRequestMetadata.title,
|
||||
description: value
|
||||
description: value || ''
|
||||
}
|
||||
mutate(payload)
|
||||
.then(() => {
|
||||
setContent(value)
|
||||
setOriginalContent(value)
|
||||
setEdit(false)
|
||||
// setUpdated(Date.now())
|
||||
refreshPullRequestMetadata()
|
||||
})
|
||||
.catch(exception => showError(getErrorMessage(exception), 0, getString('pr.failedToUpdate')))
|
||||
@ -52,6 +60,7 @@ export const DescriptionBox: React.FC<ConversationProps> = ({
|
||||
onCancel={() => {
|
||||
setContent(originalContent)
|
||||
setEdit(false)
|
||||
onCancelEditDescription()
|
||||
}}
|
||||
setDirty={setDirty}
|
||||
i18n={{
|
||||
@ -62,6 +71,7 @@ export const DescriptionBox: React.FC<ConversationProps> = ({
|
||||
cancel: getString('cancel')
|
||||
}}
|
||||
editorHeight="400px"
|
||||
autoFocusAndPositioning
|
||||
/>
|
||||
)) || (
|
||||
<Container className={css.mdWrapper}>
|
||||
|
@ -133,7 +133,8 @@ export const PullRequestActionsBox: React.FC<PullRequestActionsBoxProps> = ({
|
||||
|
||||
const [mergeOption, setMergeOption] = useUserPreference<PRMergeOption>(
|
||||
UserPreference.PULL_REQUEST_MERGE_STRATEGY,
|
||||
mergeOptions[1]
|
||||
mergeOptions[1],
|
||||
option => option.method !== 'close'
|
||||
)
|
||||
const [draftOption, setDraftOption] = useState<PRDraftOption>(draftOptions[0])
|
||||
const permPushResult = hooks?.usePermissionTranslate?.(
|
||||
|
@ -1,26 +1,14 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import {
|
||||
Container,
|
||||
PageBody,
|
||||
Text,
|
||||
FontVariation,
|
||||
Tabs,
|
||||
Layout,
|
||||
Button,
|
||||
ButtonVariation,
|
||||
ButtonSize,
|
||||
TextInput,
|
||||
useToaster
|
||||
} from '@harness/uicore'
|
||||
import { useGet, useMutate } from 'restful-react'
|
||||
import { Render, Match, Truthy, Else } from 'react-jsx-match'
|
||||
import { Container, PageBody, Tabs } from '@harness/uicore'
|
||||
import { useGet } from 'restful-react'
|
||||
import { Render } from 'react-jsx-match'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { RepositoryPageHeader } from 'components/RepositoryPageHeader/RepositoryPageHeader'
|
||||
import { voidFn, getErrorMessage } from 'utils/Utils'
|
||||
import { CodeIcon, GitInfoProps } from 'utils/GitUtils'
|
||||
import { CodeIcon } from 'utils/GitUtils'
|
||||
import type { TypesPullReq, TypesPullReqStats, TypesRepository } from 'services/code'
|
||||
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
|
||||
import { TabTitleWithCount, tabContainerCSS } from 'components/TabTitleWithCount/TabTitleWithCount'
|
||||
@ -29,6 +17,7 @@ import { Conversation } from './Conversation/Conversation'
|
||||
import { Checks } from './Checks/Checks'
|
||||
import { Changes } from '../../components/Changes/Changes'
|
||||
import { PullRequestCommits } from './PullRequestCommits/PullRequestCommits'
|
||||
import { PullRequestTitle } from './PullRequestTitle'
|
||||
import css from './PullRequest.module.scss'
|
||||
|
||||
export default function PullRequest() {
|
||||
@ -61,6 +50,7 @@ export default function PullRequest() {
|
||||
return loading || (prLoading && !prData)
|
||||
}, [loading, prLoading, prData])
|
||||
const [stats, setStats] = useState<TypesPullReqStats>()
|
||||
const [showEditDescription, setShowEditDescription] = useState(false)
|
||||
const prHasChanged = useMemo(() => {
|
||||
if (stats && prData?.stats) {
|
||||
if (
|
||||
@ -74,6 +64,9 @@ export default function PullRequest() {
|
||||
}
|
||||
return false
|
||||
}, [prData?.stats, stats])
|
||||
const onAddDescriptionClick = useCallback(() => {
|
||||
setShowEditDescription(true)
|
||||
}, [])
|
||||
|
||||
useEffect(
|
||||
function setStatsIfNotSet() {
|
||||
@ -120,7 +113,13 @@ export default function PullRequest() {
|
||||
<Container className={css.main}>
|
||||
<RepositoryPageHeader
|
||||
repoMetadata={repoMetadata}
|
||||
title={repoMetadata && prData ? <PullRequestTitle repoMetadata={repoMetadata} {...prData} /> : ''}
|
||||
title={
|
||||
repoMetadata && prData ? (
|
||||
<PullRequestTitle repoMetadata={repoMetadata} {...prData} onAddDescriptionClick={onAddDescriptionClick} />
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
dataTooltipId="repositoryPullRequests"
|
||||
extraBreadcrumbLinks={
|
||||
repoMetadata && [
|
||||
@ -165,8 +164,13 @@ export default function PullRequest() {
|
||||
<Conversation
|
||||
repoMetadata={repoMetadata as TypesRepository}
|
||||
pullRequestMetadata={prData as TypesPullReq}
|
||||
onCommentUpdate={voidFn(refetchPullRequest)}
|
||||
onCommentUpdate={() => {
|
||||
setShowEditDescription(false)
|
||||
refetchPullRequest()
|
||||
}}
|
||||
prHasChanged={prHasChanged}
|
||||
showEditDescription={showEditDescription}
|
||||
onCancelEditDescription={() => setShowEditDescription(false)}
|
||||
/>
|
||||
)
|
||||
},
|
||||
@ -237,92 +241,6 @@ export default function PullRequest() {
|
||||
)
|
||||
}
|
||||
|
||||
interface PullRequestTitleProps extends TypesPullReq, Pick<GitInfoProps, 'repoMetadata'> {
|
||||
onSaveDone?: (newTitle: string) => Promise<boolean>
|
||||
}
|
||||
|
||||
const PullRequestTitle: React.FC<PullRequestTitleProps> = ({ repoMetadata, title, number, description }) => {
|
||||
const [original, setOriginal] = useState(title)
|
||||
const [val, setVal] = useState(title)
|
||||
const [edit, setEdit] = useState(false)
|
||||
const { getString } = useStrings()
|
||||
const { showError } = useToaster()
|
||||
const { mutate } = useMutate({
|
||||
verb: 'PATCH',
|
||||
path: `/api/v1/repos/${repoMetadata.path}/+/pullreq/${number}`
|
||||
})
|
||||
const submitChange = useCallback(() => {
|
||||
mutate({
|
||||
title: val,
|
||||
description
|
||||
})
|
||||
.then(() => {
|
||||
setEdit(false)
|
||||
setOriginal(val)
|
||||
})
|
||||
.catch(exception => showError(getErrorMessage(exception), 0))
|
||||
}, [description, val, mutate, showError])
|
||||
|
||||
return (
|
||||
<Layout.Horizontal spacing="xsmall" className={css.prTitle}>
|
||||
<Match expr={edit}>
|
||||
<Truthy>
|
||||
<Container>
|
||||
<Layout.Horizontal spacing="small">
|
||||
<TextInput
|
||||
wrapperClassName={css.input}
|
||||
value={val}
|
||||
onFocus={event => event.target.select()}
|
||||
onInput={event => setVal(event.currentTarget.value)}
|
||||
autoFocus
|
||||
onKeyDown={event => {
|
||||
switch (event.key) {
|
||||
case 'Enter':
|
||||
submitChange()
|
||||
break
|
||||
case 'Escape': // does not work, maybe TextInput cancels ESC?
|
||||
setEdit(false)
|
||||
break
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
variation={ButtonVariation.PRIMARY}
|
||||
text={getString('save')}
|
||||
size={ButtonSize.MEDIUM}
|
||||
disabled={(val || '').trim().length === 0 || title === val}
|
||||
onClick={submitChange}
|
||||
/>
|
||||
<Button
|
||||
variation={ButtonVariation.TERTIARY}
|
||||
text={getString('cancel')}
|
||||
size={ButtonSize.MEDIUM}
|
||||
onClick={() => setEdit(false)}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
</Container>
|
||||
</Truthy>
|
||||
<Else>
|
||||
<>
|
||||
<Text tag="h1" font={{ variation: FontVariation.H4 }}>
|
||||
{original} <span className={css.prNumber}>#{number}</span>
|
||||
</Text>
|
||||
<Button
|
||||
variation={ButtonVariation.ICON}
|
||||
tooltip={getString('edit')}
|
||||
tooltipProps={{ isDark: true, position: 'right' }}
|
||||
size={ButtonSize.SMALL}
|
||||
icon="code-edit"
|
||||
className={css.btn}
|
||||
onClick={() => setEdit(true)}
|
||||
/>
|
||||
</>
|
||||
</Else>
|
||||
</Match>
|
||||
</Layout.Horizontal>
|
||||
)
|
||||
}
|
||||
|
||||
enum PullRequestSection {
|
||||
CONVERSATION = 'conversation',
|
||||
COMMITS = 'commits',
|
||||
|
@ -43,7 +43,7 @@ export const PullRequestCommits: React.FC<CommitProps> = ({
|
||||
return (
|
||||
<PullRequestTabContentWrapper loading={loading} error={error} onRetry={voidFn(refetch)}>
|
||||
<CommitsView
|
||||
commits={commits || []}
|
||||
commits={commits}
|
||||
repoMetadata={repoMetadata}
|
||||
emptyTitle={getString('noCommits')}
|
||||
emptyMessage={getString('noCommitsPR')}
|
||||
|
121
web/src/pages/PullRequest/PullRequestTitle.tsx
Normal file
121
web/src/pages/PullRequest/PullRequestTitle.tsx
Normal file
@ -0,0 +1,121 @@
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import {
|
||||
Container,
|
||||
Text,
|
||||
FontVariation,
|
||||
Layout,
|
||||
Button,
|
||||
ButtonVariation,
|
||||
ButtonSize,
|
||||
TextInput,
|
||||
useToaster
|
||||
} from '@harness/uicore'
|
||||
import { useMutate } from 'restful-react'
|
||||
import { Match, Truthy, Else } from 'react-jsx-match'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { ButtonRoleProps, getErrorMessage } from 'utils/Utils'
|
||||
import type { GitInfoProps } from 'utils/GitUtils'
|
||||
import type { TypesPullReq } from 'services/code'
|
||||
import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator'
|
||||
import css from './PullRequest.module.scss'
|
||||
|
||||
interface PullRequestTitleProps extends TypesPullReq, Pick<GitInfoProps, 'repoMetadata'> {
|
||||
onSaveDone?: (newTitle: string) => Promise<boolean>
|
||||
onAddDescriptionClick: () => void
|
||||
}
|
||||
|
||||
export const PullRequestTitle: React.FC<PullRequestTitleProps> = ({
|
||||
repoMetadata,
|
||||
title,
|
||||
number,
|
||||
description,
|
||||
onAddDescriptionClick
|
||||
}) => {
|
||||
const [original, setOriginal] = useState(title)
|
||||
const [val, setVal] = useState(title)
|
||||
const [edit, setEdit] = useState(false)
|
||||
const { getString } = useStrings()
|
||||
const { showError } = useToaster()
|
||||
const { mutate } = useMutate({
|
||||
verb: 'PATCH',
|
||||
path: `/api/v1/repos/${repoMetadata.path}/+/pullreq/${number}`
|
||||
})
|
||||
const submitChange = useCallback(() => {
|
||||
mutate({
|
||||
title: val,
|
||||
description
|
||||
})
|
||||
.then(() => {
|
||||
setEdit(false)
|
||||
setOriginal(val)
|
||||
})
|
||||
.catch(exception => showError(getErrorMessage(exception), 0))
|
||||
}, [description, val, mutate, showError])
|
||||
|
||||
return (
|
||||
<Layout.Horizontal spacing="small" className={css.prTitle}>
|
||||
<Match expr={edit}>
|
||||
<Truthy>
|
||||
<Container>
|
||||
<Layout.Horizontal spacing="small">
|
||||
<TextInput
|
||||
wrapperClassName={css.input}
|
||||
value={val}
|
||||
onFocus={event => event.target.select()}
|
||||
onInput={event => setVal(event.currentTarget.value)}
|
||||
autoFocus
|
||||
onKeyDown={event => {
|
||||
switch (event.key) {
|
||||
case 'Enter':
|
||||
submitChange()
|
||||
break
|
||||
case 'Escape': // does not work, maybe TextInput cancels ESC?
|
||||
setEdit(false)
|
||||
break
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
variation={ButtonVariation.PRIMARY}
|
||||
text={getString('save')}
|
||||
size={ButtonSize.MEDIUM}
|
||||
disabled={(val || '').trim().length === 0 || title === val}
|
||||
onClick={submitChange}
|
||||
/>
|
||||
<Button
|
||||
variation={ButtonVariation.TERTIARY}
|
||||
text={getString('cancel')}
|
||||
size={ButtonSize.MEDIUM}
|
||||
onClick={() => setEdit(false)}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
</Container>
|
||||
</Truthy>
|
||||
<Else>
|
||||
<>
|
||||
<Text tag="h1" font={{ variation: FontVariation.H4 }}>
|
||||
{original} <span className={css.prNumber}>#{number}</span>
|
||||
</Text>
|
||||
<Button
|
||||
variation={ButtonVariation.ICON}
|
||||
tooltip={getString('edit')}
|
||||
tooltipProps={{ isDark: true, position: 'right' }}
|
||||
size={ButtonSize.SMALL}
|
||||
icon="code-edit"
|
||||
className={css.btn}
|
||||
onClick={() => setEdit(true)}
|
||||
/>
|
||||
{!(description || '').trim().length && (
|
||||
<>
|
||||
<PipeSeparator height={10} />
|
||||
<a {...ButtonRoleProps} onClick={onAddDescriptionClick}>
|
||||
Add Description
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</Else>
|
||||
</Match>
|
||||
</Layout.Horizontal>
|
||||
)
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
.title {
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
|
||||
.convoIcon {
|
||||
padding-top: 1px !important;
|
||||
}
|
||||
@ -20,7 +21,7 @@
|
||||
|
||||
.titleRow {
|
||||
padding-left: var(--spacing-small);
|
||||
align-items: start;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,8 @@ import {
|
||||
StringSubstitute,
|
||||
Icon,
|
||||
FontVariation,
|
||||
FlexExpander
|
||||
FlexExpander,
|
||||
Utils
|
||||
} from '@harness/uicore'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useGet } from 'restful-react'
|
||||
@ -30,6 +31,8 @@ import type { TypesPullReq, TypesRepository } from 'services/code'
|
||||
import { ResourceListingPagination } from 'components/ResourceListingPagination/ResourceListingPagination'
|
||||
import { UserPreference, useUserPreference } from 'hooks/useUserPreference'
|
||||
import { NoResultCard } from 'components/NoResultCard/NoResultCard'
|
||||
import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator'
|
||||
import { GitRefLink } from 'components/GitRefLink/GitRefLink'
|
||||
import { PullRequestStateLabel } from 'components/PullRequestStateLabel/PullRequestStateLabel'
|
||||
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
|
||||
import { ExecutionStatusLabel } from 'components/ExecutionStatusLabel/ExecutionStatusLabel'
|
||||
@ -97,7 +100,7 @@ export default function PullRequests() {
|
||||
<Layout.Horizontal className={css.titleRow} spacing="medium">
|
||||
<PullRequestStateLabel iconSize={22} data={row.original} iconOnly />
|
||||
<Container padding={{ left: 'small' }}>
|
||||
<Layout.Vertical spacing="small">
|
||||
<Layout.Vertical spacing="xsmall">
|
||||
<Text color={Color.GREY_800} className={css.title}>
|
||||
{row.original.title}
|
||||
<Icon
|
||||
@ -110,6 +113,8 @@ export default function PullRequests() {
|
||||
{row.original.stats?.conversations}
|
||||
</Text>
|
||||
</Text>
|
||||
<Container>
|
||||
<Layout.Horizontal spacing="small" style={{ alignItems: 'center' }}>
|
||||
<Text color={Color.GREY_500} font={{ size: 'small' }}>
|
||||
<StringSubstitute
|
||||
str={getString('pr.statusLine')}
|
||||
@ -120,7 +125,9 @@ export default function PullRequests() {
|
||||
<strong>
|
||||
<ReactTimeago
|
||||
date={
|
||||
(row.original.state == 'merged' ? row.original.merged : row.original.created) as number
|
||||
(row.original.state == 'merged'
|
||||
? row.original.merged
|
||||
: row.original.created) as number
|
||||
}
|
||||
/>
|
||||
</strong>
|
||||
@ -129,10 +136,32 @@ export default function PullRequests() {
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
<PipeSeparator height={10} />
|
||||
<Container>
|
||||
<Layout.Horizontal spacing="xsmall" style={{ alignItems: 'center' }} onClick={Utils.stopEvent}>
|
||||
<GitRefLink
|
||||
text={row.original.target_branch as string}
|
||||
url={routes.toCODERepository({
|
||||
repoPath: repoMetadata?.path as string,
|
||||
gitRef: row.original.target_branch
|
||||
})}
|
||||
/>
|
||||
<Text color={Color.GREY_500}>←</Text>
|
||||
<GitRefLink
|
||||
text={row.original.source_branch as string}
|
||||
url={routes.toCODERepository({
|
||||
repoPath: repoMetadata?.path as string,
|
||||
gitRef: row.original.source_branch
|
||||
})}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
</Container>
|
||||
</Layout.Horizontal>
|
||||
</Container>
|
||||
</Layout.Vertical>
|
||||
</Container>
|
||||
<FlexExpander />
|
||||
{/* fix state when api is fully implemented */}
|
||||
{/* TODO: Pass proper state when check api is fully implemented */}
|
||||
<ExecutionStatusLabel data={{ state: 'success' }} />
|
||||
</Layout.Horizontal>
|
||||
)
|
||||
|
@ -115,7 +115,7 @@ export function formatNumber(num: number | bigint): string {
|
||||
* support (hit Enter/Space will trigger click event)
|
||||
*/
|
||||
export const ButtonRoleProps = {
|
||||
onKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
onKeyDown: (e: React.KeyboardEvent<HTMLElement>) => {
|
||||
if (e.key === 'Enter' || e.key === ' ' || e.key === 'Spacebar' || e.which === 13 || e.which === 32) {
|
||||
;(e.target as unknown as { click: () => void })?.click?.()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user