feat: [CODE-3426] add support for combined label activity on PR page (#3638)

* Apply suggestion from code review
* Apply suggestion from code review
* feat: [CODE-3426] add support for combined label activity on PR page
This commit is contained in:
Ritik Kapoor 2025-04-09 17:27:52 +00:00 committed by Harness
parent 8d7fc35548
commit ef5251a6b9
4 changed files with 72 additions and 29 deletions

View File

@ -903,6 +903,7 @@ export interface StringsMap {
'prReview.codeowners': string
'prReview.defaultReviewers': string
'prReview.filterByReviews': string
'prReview.labelsAssigned': string
'prReview.removed': string
'prReview.requested': string
'prReview.selfAssigned': string

View File

@ -390,6 +390,7 @@ prReview:
filterByReviews: Filter by Reviews
codeowners: '{author} requested review from {codeowners} as {count|1:code owner,code owners}'
defaultReviewers: '{author} requested review from {reviewers} as {count|1:default reviewer,default reviewers}'
labelsAssigned: '{count|0:label,labels}'
webhookListingContent: 'create,delete,deployment ...'
general: 'General'
webhooks: 'Webhooks'

View File

@ -31,7 +31,7 @@ import { CommitActions } from 'components/CommitActions/CommitActions'
import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator'
import { TimePopoverWithLocal } from 'utils/timePopoverLocal/TimePopoverWithLocal'
import { Label } from 'components/Label/Label'
import { CommentType } from '../PullRequestUtils'
import { ActivityLabel, CommentType } from '../PullRequestUtils'
import css from './Conversation.module.scss'
interface SystemCommentProps extends Pick<GitInfoProps, 'pullReqMetadata'> {
@ -76,6 +76,51 @@ const formatListWithAndFragment = (names: string[]): React.ReactNode => {
}
}
const RenderScopedLabel = ({ labelObj }: { labelObj: ActivityLabel }) => {
return (
<Label
name={labelObj.label}
label_color={labelObj.label_color}
label_value={{
name: labelObj.value,
color: labelObj.value_color
}}
scope={labelObj.label_scope}
/>
)
}
const formatLabelListWithAndFragment = (labels: ActivityLabel[]): JSX.Element => {
if (!labels || !Array.isArray(labels)) {
return <></>
}
switch (labels.length) {
case 0:
return <></>
case 1:
return <RenderScopedLabel labelObj={labels[0]} />
case 2:
return (
<>
<RenderScopedLabel labelObj={labels[0]} /> and <RenderScopedLabel labelObj={labels[1]} />
</>
)
default:
return (
<>
{labels.slice(0, -1).map((labelObj, index) => (
<React.Fragment key={index}>
<RenderScopedLabel labelObj={labelObj} />
{index < labels.length - 2 ? ', ' : ''}
</React.Fragment>
))}{' '}
and <RenderScopedLabel labelObj={labels[labels.length - 1]} />
</>
)
}
}
//ToDo : update all comment options with the correct payload type and remove Unknown
export const SystemComment: React.FC<SystemCommentProps> = ({ pullReqMetadata, commentItems, repoMetadataPath }) => {
const { getString } = useStrings()
@ -395,24 +440,28 @@ export const SystemComment: React.FC<SystemCommentProps> = ({ pullReqMetadata, c
}
case CommentType.LABEL_MODIFY: {
const labelList = (payload?.payload as any)?.labels || []
const labelsListElement = formatLabelListWithAndFragment(labelList)
return (
<Container className={css.mergedBox}>
<Layout.Horizontal spacing="small" style={{ alignItems: 'center' }}>
<Avatar name={payload?.author?.display_name} size="small" hoverCard={false} />
<Text tag="div">
<Match expr={(payload?.payload as Unknown).type}>
<Match expr={(payload?.payload as Unknown)?.type}>
<Case val={LabelActivity.ASSIGN}>
<strong>{payload?.author?.display_name}</strong> {getString('labels.applied')}
<Label
name={(payload?.payload as Unknown).label}
label_color={(payload?.payload as Unknown).label_color}
label_value={{
name: (payload?.payload as Unknown).value,
color: (payload?.payload as Unknown).value_color
{Array.isArray(labelList) && labelList.length > 0 ? (
<>{labelsListElement}</>
) : (
<RenderScopedLabel labelObj={payload?.payload as ActivityLabel} />
)}{' '}
<StringSubstitute
str={getString('prReview.labelsAssigned')}
vars={{
count: labelList?.length || 0
}}
scope={(payload?.payload as Unknown).label_scope}
/>
<span>{getString('labels.label')}</span>
</Case>
<Case val={LabelActivity.RE_ASSIGN}>
<strong>{payload?.author?.display_name}</strong> <span>{getString('labels.updated')}</span>
@ -426,27 +475,11 @@ export const SystemComment: React.FC<SystemCommentProps> = ({ pullReqMetadata, c
scope={(payload?.payload as Unknown).label_scope}
/>
<span>{getString('labels.labelTo')}</span>
<Label
name={(payload?.payload as Unknown).label}
label_color={(payload?.payload as Unknown).label_color}
label_value={{
name: (payload?.payload as Unknown).value,
color: (payload?.payload as Unknown).value_color
}}
scope={(payload?.payload as Unknown).label_scope}
/>
<RenderScopedLabel labelObj={payload?.payload as ActivityLabel} />
</Case>
<Case val={LabelActivity.UN_ASSIGN}>
<strong>{payload?.author?.display_name}</strong> <span>{getString('labels.removed')}</span>
<Label
name={(payload?.payload as Unknown).label}
label_color={(payload?.payload as Unknown).label_color}
label_value={{
name: (payload?.payload as Unknown).value,
color: (payload?.payload as Unknown).value_color
}}
scope={(payload?.payload as Unknown).label_scope}
/>
<RenderScopedLabel labelObj={payload?.payload as ActivityLabel} />
<span>{getString('labels.label')}</span>
</Case>
</Match>

View File

@ -17,7 +17,7 @@
import type { SelectOption } from '@harnessio/uicore'
import type { UseStringsReturn } from 'framework/strings'
import type { CommentItem } from 'components/CommentBox/CommentBox'
import type { PullRequestSection } from 'utils/Utils'
import type { ColorName, PullRequestSection } from 'utils/Utils'
import { MergeStrategy } from 'utils/GitUtils'
import type {
EnumMergeMethod,
@ -217,3 +217,11 @@ export const defaultReviewerResponseWithDecision = (
}
})
}
export type ActivityLabel = {
label: string
label_color: ColorName
label_scope: number
value: string
value_color: ColorName
}