Skip to content

Commit fe27eb2

Browse files
Merge pull request #1268 from topcoder-platform/fix-2446
Fix 2446
2 parents 1d7e43e + 49c1347 commit fe27eb2

File tree

4 files changed

+125
-91
lines changed

4 files changed

+125
-91
lines changed

src/apps/review/src/lib/components/ScorecardQuestionView/ScorecardQuestionView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ function renderResponseCommentRow({
411411
</span>
412412

413413
<MarkdownReview
414-
value={commentItem.content}
414+
value={commentItem.content.replace(/\n\n/g, '<br><br>')}
415415
className={styles.mardownReview}
416416
/>
417417
</div>

src/apps/review/src/lib/components/TableReview/TableReview.tsx

Lines changed: 15 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import {
3434
aggregateSubmissionReviews,
3535
challengeHasSubmissionLimit,
3636
isReviewPhase,
37-
isReviewPhaseCurrentlyOpen,
3837
refreshChallengeReviewData,
3938
REOPEN_MESSAGE_OTHER,
4039
REOPEN_MESSAGE_SELF,
@@ -86,69 +85,6 @@ type RestrictionResult = {
8685
message?: string
8786
}
8887

89-
function createReopenActionButtons(
90-
challengeInfo: ChallengeDetailContextModel['challengeInfo'],
91-
submission: SubmissionRow,
92-
aggregatedReviews: AggregatedReviewDetail[] | undefined,
93-
{
94-
canManageCompletedReviews,
95-
isReopening,
96-
openReopenDialog,
97-
pendingReopen,
98-
}: {
99-
canManageCompletedReviews: boolean
100-
isReopening: boolean
101-
openReopenDialog: (submission: SubmissionRow, review: AggregatedReviewDetail) => void
102-
pendingReopen: PendingReopenState | undefined
103-
},
104-
): JSX.Element[] {
105-
if (!canManageCompletedReviews) {
106-
return []
107-
}
108-
109-
const buttons: JSX.Element[] = []
110-
const reviews = aggregatedReviews ?? []
111-
112-
reviews.forEach(review => {
113-
const reviewInfo = review.reviewInfo
114-
if (!reviewInfo?.id) {
115-
return
116-
}
117-
118-
if ((reviewInfo.status ?? '').toUpperCase() !== 'COMPLETED') {
119-
return
120-
}
121-
122-
if (!isReviewPhaseCurrentlyOpen(challengeInfo, reviewInfo.phaseId)) {
123-
return
124-
}
125-
126-
const isTargetReview = pendingReopen?.review?.reviewInfo?.id === reviewInfo.id
127-
128-
function handleReopenClick(): void {
129-
openReopenDialog(submission, {
130-
...review,
131-
reviewInfo,
132-
} as AggregatedReviewDetail)
133-
}
134-
135-
buttons.push(
136-
<button
137-
key={`reopen-${reviewInfo.id}`}
138-
type='button'
139-
className={classNames(styles.actionButton, styles.textBlue)}
140-
onClick={handleReopenClick}
141-
disabled={isReopening && isTargetReview}
142-
>
143-
<i className='icon-reopen' />
144-
Reopen review
145-
</button>,
146-
)
147-
})
148-
149-
return buttons
150-
}
151-
15288
export const TableReview: FC<TableReviewProps> = (props: TableReviewProps) => {
15389
const className: string | undefined = props.className
15490
const datas: SubmissionInfo[] = props.datas
@@ -516,20 +452,6 @@ export const TableReview: FC<TableReviewProps> = (props: TableReviewProps) => {
516452
}
517453

518454
appendAction(buildPrimaryAction(), 'primary')
519-
520-
const reopenButtons = createReopenActionButtons(
521-
challengeInfo,
522-
submission,
523-
reviews,
524-
{
525-
canManageCompletedReviews,
526-
isReopening,
527-
openReopenDialog,
528-
pendingReopen,
529-
},
530-
)
531-
532-
reopenButtons.forEach(button => appendAction(button, 'reopen'))
533455
appendAction(buildHistoryAction(), 'history')
534456

535457
if (!actionEntries.length) {
@@ -559,16 +481,11 @@ export const TableReview: FC<TableReviewProps> = (props: TableReviewProps) => {
559481
</span>
560482
)
561483
}, [
562-
canManageCompletedReviews,
563484
canViewHistory,
564-
challengeInfo,
565485
handleHistoryButtonClick,
566486
hasReviewRole,
567487
historyByMember,
568-
isReopening,
569488
myReviewerResourceIds,
570-
openReopenDialog,
571-
pendingReopen,
572489
shouldShowHistoryActions,
573490
])
574491

@@ -650,7 +567,16 @@ export const TableReview: FC<TableReviewProps> = (props: TableReviewProps) => {
650567
{
651568
columnId: `score-${index}`,
652569
label: `Score ${index + 1}`,
653-
renderer: (submission: SubmissionRow) => renderScoreCell(submission, index, scoreVisibilityConfig),
570+
renderer: (submission: SubmissionRow) => renderScoreCell(
571+
submission,
572+
index,
573+
scoreVisibilityConfig,
574+
challengeInfo,
575+
pendingReopen,
576+
canManageCompletedReviews,
577+
isReopening,
578+
openReopenDialog,
579+
),
654580
type: 'element',
655581
},
656582
)
@@ -675,6 +601,11 @@ export const TableReview: FC<TableReviewProps> = (props: TableReviewProps) => {
675601
renderActionsCell,
676602
scoreVisibilityConfig,
677603
shouldShowAggregatedActions,
604+
canManageCompletedReviews,
605+
isReopening,
606+
openReopenDialog,
607+
challengeInfo,
608+
pendingReopen,
678609
])
679610

680611
const columnsMobile = useMemo<MobileTableColumn<SubmissionRow>[][]>(

src/apps/review/src/lib/components/common/TableColumnRenderers.module.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313
}
1414
}
1515

16+
.scoreReopenBlock {
17+
display: flex;
18+
gap: 4px;
19+
align-items: center;
20+
}
21+
1622
.tooltipTrigger {
1723
display: inline-block;
1824
}

src/apps/review/src/lib/components/common/TableColumnRenderers.tsx

Lines changed: 103 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@ import {
1212
VIRUS_SCAN_FAILED_MESSAGE,
1313
} from '../../utils/constants'
1414
import { getReviewRoute } from '../../utils/routes'
15+
import { ChallengeDetailContextModel, ChallengeInfo } from '../../models'
16+
import { isReviewPhaseCurrentlyOpen } from '../../utils'
1517

1618
import {
1719
formatScoreDisplay,
1820
getHandleColor,
1921
getProfileUrl,
2022
} from './columnUtils'
2123
import type {
24+
AggregatedReviewDetail,
2225
DownloadButtonConfig,
2326
ScoreVisibilityConfig,
2427
SubmissionRow,
@@ -315,13 +318,88 @@ export function renderReviewerCell(
315318
)
316319
}
317320

321+
interface PendingReopenState {
322+
review?: AggregatedReviewDetail
323+
submission?: SubmissionRow
324+
isOwnReview?: boolean
325+
}
326+
327+
function createReopenActionButtons(
328+
challengeInfo: ChallengeDetailContextModel['challengeInfo'],
329+
submission: SubmissionRow,
330+
aggregatedReviews: AggregatedReviewDetail[] | undefined,
331+
{
332+
canManageCompletedReviews,
333+
isReopening,
334+
openReopenDialog,
335+
pendingReopen,
336+
}: {
337+
canManageCompletedReviews: boolean
338+
isReopening: boolean
339+
openReopenDialog: (submission: SubmissionRow, review: AggregatedReviewDetail) => void
340+
pendingReopen: PendingReopenState | undefined
341+
},
342+
): JSX.Element[] {
343+
if (!canManageCompletedReviews) {
344+
return []
345+
}
346+
347+
const buttons: JSX.Element[] = []
348+
const reviews = aggregatedReviews ?? []
349+
350+
reviews.forEach(review => {
351+
const reviewInfo = review.reviewInfo
352+
if (!reviewInfo?.id) {
353+
return
354+
}
355+
356+
if ((reviewInfo.status ?? '').toUpperCase() !== 'COMPLETED') {
357+
return
358+
}
359+
360+
if (!isReviewPhaseCurrentlyOpen(challengeInfo, reviewInfo.phaseId)) {
361+
return
362+
}
363+
364+
const isTargetReview = pendingReopen?.review?.reviewInfo?.id === reviewInfo.id
365+
366+
function handleReopenClick(): void {
367+
openReopenDialog(submission, {
368+
...review,
369+
reviewInfo,
370+
} as AggregatedReviewDetail)
371+
}
372+
373+
buttons.push(
374+
// eslint-disable-next-line jsx-a11y/control-has-associated-label
375+
<button
376+
key={`reopen-${reviewInfo.id}`}
377+
type='button'
378+
className={classNames(styles.actionButton, styles.textBlue)}
379+
onClick={handleReopenClick}
380+
disabled={isReopening && isTargetReview}
381+
title='Reopen review'
382+
>
383+
<i className='icon-reopen' />
384+
</button>,
385+
)
386+
})
387+
388+
return buttons
389+
}
390+
318391
/**
319392
* Renders an individual review score, linking to the review detail when allowed.
320393
*/
321394
export function renderScoreCell(
322395
submission: SubmissionRow,
323396
reviewIndex: number,
324397
config: ScoreVisibilityConfig,
398+
challengeInfo?: ChallengeInfo | undefined,
399+
pendingReopen?: PendingReopenState | undefined,
400+
canManageCompletedReviews?: boolean,
401+
isReopening?: boolean,
402+
openReopenDialog?: (submission: SubmissionRow, review: AggregatedReviewDetail) => void,
325403
): JSX.Element {
326404
const configWithDefaults: ScoreVisibilityConfig = config
327405
const {
@@ -363,6 +441,20 @@ export function renderScoreCell(
363441
const formattedScore = formatScoreDisplay(reviewDetail.finalScore)
364442
const scoreLabel = formattedScore ?? '--'
365443

444+
const reopenButtons = createReopenActionButtons(
445+
challengeInfo,
446+
submission,
447+
[reviewDetail], // pass single review in an array
448+
{
449+
canManageCompletedReviews: !!canManageCompletedReviews,
450+
isReopening: !!isReopening,
451+
openReopenDialog: openReopenDialog as (submission: SubmissionRow, review: AggregatedReviewDetail) => void,
452+
pendingReopen,
453+
},
454+
)
455+
456+
const reopenButton = reopenButtons.length ? reopenButtons[0] : undefined
457+
366458
if (!canViewScorecard) {
367459
return (
368460
<Tooltip
@@ -381,13 +473,18 @@ export function renderScoreCell(
381473
const reviewUrl = getReviewUrl ? getReviewUrl(reviewId) : getReviewRoute(reviewId)
382474

383475
return (
384-
<Link
385-
to={reviewUrl}
386-
className={styles.textBlue}
387-
>
388-
{scoreLabel}
389-
</Link>
476+
<div className={styles.scoreReopenBlock}>
477+
<Link
478+
to={reviewUrl}
479+
className={styles.textBlue}
480+
>
481+
{scoreLabel}
482+
483+
</Link>
484+
<span>{reopenButton}</span>
485+
</div>
390486
)
487+
391488
}
392489

393490
/**

0 commit comments

Comments
 (0)