Skip to content

Commit 67cd8cc

Browse files
committed
PM-1905 - render virus scan as part of ai reviews
1 parent b4f607e commit 67cd8cc

File tree

6 files changed

+140
-80
lines changed

6 files changed

+140
-80
lines changed

src/apps/review/src/lib/components/AiReviewsTable/AiReviewsTable.module.scss

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525

2626
.scoreCol {
2727
text-align: right;
28-
29-
color: #0D61BF;
3028
}
3129
}
3230

@@ -42,10 +40,12 @@
4240
}
4341

4442
.workflowName {
45-
max-width: 200px;
46-
white-space: nowrap;
47-
overflow: hidden;
48-
text-overflow: ellipsis;
43+
> div:first-child {
44+
max-width: 200px;
45+
white-space: nowrap;
46+
overflow: hidden;
47+
text-overflow: ellipsis;
48+
}
4949
}
5050
}
5151

@@ -59,6 +59,16 @@
5959
&:global(.passed) {
6060
color: $teal-160;
6161
}
62+
&:global(.pending) {
63+
color: $black-20;
64+
display: flex;
65+
width: 16px;
66+
height: 16px;
67+
border-radius: 15px;
68+
border: 1px solid;
69+
align-items: center;
70+
justify-content: center;
71+
}
6272
}
6373
}
6474

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

Lines changed: 92 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,65 @@ import moment from 'moment'
44
import { CheckIcon, MinusCircleIcon } from '@heroicons/react/outline'
55
import { useWindowSize, WindowSize } from '~/libs/shared'
66

7-
import { AiWorkflowRunsResponse, useFetchAiWorkflowsRuns } from '../../hooks'
7+
import {
8+
AiWorkflowRun,
9+
AiWorkflowRunsResponse,
10+
AiWorkflowRunStatus,
11+
useFetchAiWorkflowsRuns,
12+
useRolePermissions,
13+
UseRolePermissionsResult,
14+
} from '../../hooks'
815
import { IconAiReview } from '../../assets/icons'
916
import { TABLE_DATE_FORMAT } from '../../../config/index.config'
17+
import { BackendSubmission } from '../../models'
1018

1119
import styles from './AiReviewsTable.module.scss'
20+
import { IconOutline, Tooltip } from '~/libs/ui'
21+
import { run } from 'node:test'
1222

1323
interface AiReviewsTableProps {
14-
submissionId: string
24+
submission: Pick<BackendSubmission, 'id'|'virusScan'>
1525
reviewers: { aiWorkflowId: string }[]
1626
}
1727

28+
const aiRunInProgress = (aiRun: Pick<AiWorkflowRun, 'status'>) =>
29+
[
30+
AiWorkflowRunStatus.INIT,
31+
AiWorkflowRunStatus.QUEUED,
32+
AiWorkflowRunStatus.DISPATCHED,
33+
AiWorkflowRunStatus.IN_PROGRESS,
34+
].includes(aiRun.status)
35+
36+
const aiRunFailed = (aiRun: Pick<AiWorkflowRun, 'status'>) =>
37+
[
38+
AiWorkflowRunStatus.FAILURE,
39+
AiWorkflowRunStatus.CANCELLED,
40+
].includes(aiRun.status)
41+
1842
const AiReviewsTable: FC<AiReviewsTableProps> = props => {
1943
const aiWorkflowIds = useMemo(() => props.reviewers.map(r => r.aiWorkflowId), [props.reviewers])
20-
const { runs, isLoading }: AiWorkflowRunsResponse = useFetchAiWorkflowsRuns(props.submissionId, aiWorkflowIds)
44+
const { runs, isLoading }: AiWorkflowRunsResponse = useFetchAiWorkflowsRuns(props.submission.id, aiWorkflowIds)
2145

2246
const windowSize: WindowSize = useWindowSize()
2347
const isTablet = useMemo(
2448
() => (windowSize.width ?? 0) <= 984,
2549
[windowSize.width],
2650
)
51+
const { isAdmin }: UseRolePermissionsResult = useRolePermissions()
52+
53+
const aiRuns = useMemo(() => [
54+
...runs,
55+
{
56+
id: '-1',
57+
completedAt: (props.submission as BackendSubmission).submittedDate,
58+
status: AiWorkflowRunStatus.SUCCESS,
59+
score: props.submission.virusScan === true ? 100 : 0,
60+
workflow: {
61+
name: 'Virus Scan',
62+
description: '',
63+
}
64+
} as AiWorkflowRun
65+
].filter(r => isAdmin || !aiRunFailed(r)), [runs, props.submission])
2766

2867
if (isTablet) {
2968
return (
@@ -32,11 +71,7 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => {
3271
<div className={styles.mobileLoading}>Loading...</div>
3372
)}
3473

35-
{!runs.length && !isLoading && (
36-
<div className={styles.mobileLoading}>No reviews</div>
37-
)}
38-
39-
{runs.map(run => (
74+
{aiRuns.map(run => (
4075
<div key={run.id} className={styles.mobileCard}>
4176
<div className={styles.mobileRow}>
4277
<div className={styles.label}>Reviewer</div>
@@ -64,16 +99,20 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => {
6499
<div className={styles.mobileRow}>
65100
<div className={styles.label}>Score</div>
66101
<div className={styles.value}>
67-
{run.status === 'SUCCESS' ? run.score : '-'}
102+
{run.status === 'SUCCESS' ? (
103+
run.workflow.scorecard ? (
104+
<a href={`/scorecard/${run.workflow.scorecard.id}`}>{run.score}</a>
105+
) : run.score
106+
) : '-'}
68107
</div>
69108
</div>
70109

71110
<div className={styles.mobileRow}>
72111
<div className={styles.label}>Result</div>
73112
<div className={`${styles.value} ${styles.resultCol}`}>
74-
{run.status === 'SUCCESS' ? (
113+
{run.status === 'SUCCESS' && (
75114
<div className={styles.result}>
76-
{run.score >= run.workflow.scorecard.minimumPassingScore ? (
115+
{run.score >= (run.workflow.scorecard?.minimumPassingScore ?? 0) ? (
77116
<>
78117
<CheckIcon className='icon icon-xl passed' />
79118
{' '}
@@ -87,8 +126,22 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => {
87126
</>
88127
)}
89128
</div>
90-
) : (
91-
'-'
129+
)}
130+
{aiRunInProgress(run) && (
131+
<div className={styles.result}>
132+
<span className='icon pending'>
133+
<IconOutline.MinusIcon className='icon-sm' />
134+
</span>
135+
{' '}
136+
To be filled
137+
</div>
138+
)}
139+
{aiRunFailed(run) && (
140+
<div className={styles.result}>
141+
<span className='icon'>
142+
<IconOutline.XCircleIcon className='icon-xl' />
143+
</span>
144+
</div>
92145
)}
93146
</div>
94147
</div>
@@ -114,15 +167,17 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => {
114167
</tr>
115168
)}
116169

117-
{runs.map(run => (
170+
{aiRuns.map(run => (
118171
<tr key={run.id}>
119172
<td>
120173
<div className={styles.aiReviewer}>
121174
<span className={styles.icon}>
122175
<IconAiReview />
123176
</span>
124177
<span className={styles.workflowName} title={run.workflow.name}>
125-
{run.workflow.name}
178+
<Tooltip content={run.workflow.name} triggerOn='hover'>
179+
{run.workflow.name}
180+
</Tooltip>
126181
</span>
127182
</div>
128183
</td>
@@ -134,12 +189,16 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => {
134189
)}
135190
</td>
136191
<td className={styles.scoreCol}>
137-
{run.status === 'SUCCESS' && run.score}
192+
{run.status === 'SUCCESS' ? (
193+
run.workflow.scorecard ? (
194+
<a href={`/scorecard/${run.workflow.scorecard.id}`}>{run.score}</a>
195+
) : run.score
196+
) : '-'}
138197
</td>
139198
<td className={styles.resultCol}>
140199
{run.status === 'SUCCESS' && (
141200
<div className={styles.result}>
142-
{run.score >= run.workflow.scorecard.minimumPassingScore
201+
{run.score >= (run.workflow.scorecard?.minimumPassingScore ?? 0)
143202
? (
144203
<>
145204
<CheckIcon className='icon icon-xl passed' />
@@ -156,6 +215,22 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => {
156215
)}
157216
</div>
158217
)}
218+
{aiRunInProgress(run) && (
219+
<div className={styles.result}>
220+
<span className='icon pending'>
221+
<IconOutline.MinusIcon className='icon-sm' />
222+
</span>
223+
{' '}
224+
To be filled
225+
</div>
226+
)}
227+
{aiRunFailed(run) && (
228+
<div className={styles.result}>
229+
<span className='icon'>
230+
<IconOutline.XCircleIcon className='icon-xl' />
231+
</span>
232+
</div>
233+
)}
159234
</td>
160235
</tr>
161236
))}

src/apps/review/src/lib/components/ChallengeDetailsContent/TabContentSubmissions.tsx

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -319,42 +319,18 @@ export const TabContentSubmissions: FC<Props> = props => {
319319
type: 'element',
320320
},
321321
{
322-
label: 'Virus Scan',
323-
propertyName: 'virusScan',
324-
renderer: (submission: BackendSubmission) => {
325-
if (submission.virusScan === true) {
326-
return (
327-
<span className={styles.virusOkIcon} title='Scan passed' aria-label='Scan passed'>
328-
<IconOutline.CheckCircleIcon />
329-
</span>
330-
)
331-
}
332-
333-
if (submission.virusScan === false) {
334-
return (
335-
<span className={styles.virusWarnIcon} title='Scan failed' aria-label='Scan failed'>
336-
<IconOutline.ExclamationIcon />
337-
</span>
338-
)
339-
}
340-
341-
return <span>-</span>
342-
},
343-
type: 'element',
344-
},
345-
...(!props.aiReviewers?.length ? [] : [{
346322
className: styles.aiReviewerRow,
347323
label: 'Reviewer',
348324
mobileColSpan: 2,
349-
propertyName: 'submittedDate',
325+
propertyName: 'virusScan',
350326
renderer: (submission: BackendSubmission) => (
351327
<CollapsibleAiReviewsRow
352328
aiReviewers={props.aiReviewers!}
353-
submissionId={submission.id}
329+
submission={submission}
354330
/>
355331
),
356332
type: 'element',
357-
} as TableColumn<BackendSubmission>]),
333+
},
358334
]
359335

360336
if (shouldShowHistoryActions) {

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@ import classNames from 'classnames'
44
import { IconOutline } from '~/libs/ui'
55

66
import { AiReviewsTable } from '../AiReviewsTable'
7+
import { BackendSubmission } from '../../models'
78

89
import styles from './CollapsibleAiReviewsRow.module.scss'
910

1011
interface CollapsibleAiReviewsRowProps {
1112
aiReviewers: { aiWorkflowId: string }[]
12-
submissionId: string
13+
submission: BackendSubmission
1314
}
1415

1516
const CollapsibleAiReviewsRow: FC<CollapsibleAiReviewsRowProps> = props => {
16-
const aiReviewersCount = props.aiReviewers.length
17+
const aiReviewersCount = props.aiReviewers.length + 1
1718

1819
const [isOpen, setIsOpen] = useState(false)
1920

@@ -34,7 +35,7 @@ const CollapsibleAiReviewsRow: FC<CollapsibleAiReviewsRowProps> = props => {
3435
<div className={styles.table}>
3536
<AiReviewsTable
3637
reviewers={props.aiReviewers}
37-
submissionId={props.submissionId}
38+
submission={props.submission}
3839
/>
3940
</div>
4041
)}

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

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ export const SubmissionHistoryModal: FC<SubmissionHistoryModalProps> = (props: S
100100
[props.submissions],
101101
)
102102

103+
const aiReviewersCount = useMemo(() => (props.aiReviewers?.length ?? 0) + 1, [props.aiReviewers]);
104+
103105
const [toggledRows, setToggledRows] = useState(new Set<string>())
104106

105107
const resolvedMemberInfo = useMemo(() => {
@@ -256,38 +258,23 @@ export const SubmissionHistoryModal: FC<SubmissionHistoryModalProps> = (props: S
256258
<td className={styles.cellDate}>
257259
{submittedDisplay}
258260
</td>
259-
<td className={styles.cellVirusScan}>
260-
{resolvedVirusScan === true ? (
261-
<span className={styles.virusOkIcon} title='Scan passed' aria-label='Scan passed'>
262-
<IconOutline.CheckCircleIcon />
263-
</span>
264-
) : resolvedVirusScan === false ? (
265-
<span className={styles.virusWarnIcon} title='Scan failed' aria-label='Scan failed'>
266-
<IconOutline.ExclamationIcon />
267-
</span>
268-
) : (
269-
<span>-</span>
270-
)}
261+
<td className={styles.aiReviewers}>
262+
<span className={styles.reviewersDropown} onClick={toggle}>
263+
{aiReviewersCount}
264+
{' '}
265+
AI Reviewer
266+
{aiReviewersCount === 1 ? '' : 's'}
267+
<IconOutline.ChevronDownIcon className='icon-xl' />
268+
</span>
271269
</td>
272-
{!!props.aiReviewers?.length && (
273-
<td className={styles.aiReviewers}>
274-
<span className={styles.reviewersDropown} onClick={toggle}>
275-
{props.aiReviewers.length}
276-
{' '}
277-
AI Reviewer
278-
{props.aiReviewers.length === 1 ? '' : 's'}
279-
<IconOutline.ChevronDownIcon className='icon-xl' />
280-
</span>
281-
</td>
282-
)}
283270
</tr>
284271
{toggledRows.has(submission.id) && (
285272
<tr>
286273
<td className={styles.aiReviewersTableRow} colSpan={4}>
287274
<div className={styles.aiReviewersTable}>
288275
<AiReviewsTable
289276
reviewers={props.aiReviewers!}
290-
submissionId={submission.id}
277+
submission={submission}
291278
/>
292279
</div>
293280
</td>
@@ -321,7 +308,6 @@ export const SubmissionHistoryModal: FC<SubmissionHistoryModalProps> = (props: S
321308
<tr>
322309
<th className={styles.cellSubmission}>Submission ID</th>
323310
<th className={styles.cellDate}>Submitted</th>
324-
<th className={styles.cellVirusScan}>Virus Scan</th>
325311
<th className={styles.cellVirusScan}>Reviewer</th>
326312
</tr>
327313
</thead>

0 commit comments

Comments
 (0)