Skip to content

Commit 6abe321

Browse files
committed
PM-2136 - ai workflow runs sidebar switcher
1 parent ec25968 commit 6abe321

24 files changed

+540
-156
lines changed

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

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -49,29 +49,6 @@
4949
}
5050
}
5151

52-
.result {
53-
display: flex;
54-
align-items: center;
55-
gap: $sp-2;
56-
57-
:global(.icon) {
58-
color: #C1294F;
59-
&:global(.passed) {
60-
color: $teal-160;
61-
}
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-
}
72-
}
73-
}
74-
7552
.mobileCard {
7653
border-top: 1px solid #A8A8A8;
7754
margin-top: $sp-2;

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

Lines changed: 7 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,27 @@
11
import { FC, useMemo } from 'react'
22
import moment from 'moment'
33

4-
import { CheckIcon, MinusCircleIcon } from '@heroicons/react/outline'
54
import { useWindowSize, WindowSize } from '~/libs/shared'
6-
import { IconOutline, Tooltip } from '~/libs/ui'
5+
import { Tooltip } from '~/libs/ui'
76

87
import {
98
AiWorkflowRun,
109
AiWorkflowRunsResponse,
11-
AiWorkflowRunStatus,
10+
AiWorkflowRunStatusEnum,
1211
useFetchAiWorkflowsRuns,
13-
useRolePermissions,
14-
UseRolePermissionsResult,
1512
} from '../../hooks'
1613
import { IconAiReview } from '../../assets/icons'
1714
import { TABLE_DATE_FORMAT } from '../../../config/index.config'
1815
import { BackendSubmission } from '../../models'
1916

17+
import { AiWorkflowRunStatus } from './AiWorkflowRunStatus'
2018
import styles from './AiReviewsTable.module.scss'
2119

2220
interface AiReviewsTableProps {
2321
submission: Pick<BackendSubmission, 'id'|'virusScan'>
2422
reviewers: { aiWorkflowId: string }[]
2523
}
2624

27-
const aiRunInProgress = (aiRun: Pick<AiWorkflowRun, 'status'>): boolean => [
28-
AiWorkflowRunStatus.INIT,
29-
AiWorkflowRunStatus.QUEUED,
30-
AiWorkflowRunStatus.DISPATCHED,
31-
AiWorkflowRunStatus.IN_PROGRESS,
32-
].includes(aiRun.status)
33-
34-
const aiRunFailed = (aiRun: Pick<AiWorkflowRun, 'status'>): boolean => [
35-
AiWorkflowRunStatus.FAILURE,
36-
AiWorkflowRunStatus.CANCELLED,
37-
].includes(aiRun.status)
3825

3926
const AiReviewsTable: FC<AiReviewsTableProps> = props => {
4027
const aiWorkflowIds = useMemo(() => props.reviewers.map(r => r.aiWorkflowId), [props.reviewers])
@@ -45,21 +32,20 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => {
4532
() => (windowSize.width ?? 0) <= 984,
4633
[windowSize.width],
4734
)
48-
const { isAdmin }: UseRolePermissionsResult = useRolePermissions()
4935

5036
const aiRuns = useMemo(() => [
5137
...runs,
5238
{
5339
completedAt: (props.submission as BackendSubmission).submittedDate,
5440
id: '-1',
5541
score: props.submission.virusScan === true ? 100 : 0,
56-
status: AiWorkflowRunStatus.SUCCESS,
42+
status: AiWorkflowRunStatusEnum.SUCCESS,
5743
workflow: {
5844
description: '',
5945
name: 'Virus Scan',
6046
},
6147
} as AiWorkflowRun,
62-
].filter(r => isAdmin || !aiRunFailed(r)), [runs, props.submission])
48+
], [runs, props.submission])
6349

6450
if (isTablet) {
6551
return (
@@ -107,39 +93,7 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => {
10793
<div className={styles.mobileRow}>
10894
<div className={styles.label}>Result</div>
10995
<div className={`${styles.value} ${styles.resultCol}`}>
110-
{run.status === 'SUCCESS' && (
111-
<div className={styles.result}>
112-
{run.score >= (run.workflow.scorecard?.minimumPassingScore ?? 0) ? (
113-
<>
114-
<CheckIcon className='icon icon-xl passed' />
115-
{' '}
116-
Passed
117-
</>
118-
) : (
119-
<>
120-
<MinusCircleIcon className='icon icon-xl' />
121-
{' '}
122-
Failed
123-
</>
124-
)}
125-
</div>
126-
)}
127-
{aiRunInProgress(run) && (
128-
<div className={styles.result}>
129-
<span className='icon pending'>
130-
<IconOutline.MinusIcon className='icon-sm' />
131-
</span>
132-
{' '}
133-
To be filled
134-
</div>
135-
)}
136-
{aiRunFailed(run) && (
137-
<div className={styles.result}>
138-
<span className='icon'>
139-
<IconOutline.XCircleIcon className='icon-xl' />
140-
</span>
141-
</div>
142-
)}
96+
<AiWorkflowRunStatus run={run} />
14397
</div>
14498
</div>
14599
</div>
@@ -196,41 +150,7 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => {
196150
) : '-'}
197151
</td>
198152
<td className={styles.resultCol}>
199-
{run.status === 'SUCCESS' && (
200-
<div className={styles.result}>
201-
{run.score >= (run.workflow.scorecard?.minimumPassingScore ?? 0)
202-
? (
203-
<>
204-
<CheckIcon className='icon icon-xl passed' />
205-
{' '}
206-
Passed
207-
</>
208-
)
209-
: (
210-
<>
211-
<MinusCircleIcon className='icon icon-xl' />
212-
{' '}
213-
Failed
214-
</>
215-
)}
216-
</div>
217-
)}
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-
)}
153+
<AiWorkflowRunStatus run={run} />
234154
</td>
235155
</tr>
236156
))}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
@import '@libs/ui/styles/includes';
2+
3+
.result {
4+
display: flex;
5+
align-items: center;
6+
gap: $sp-2;
7+
}
8+
9+
.icon {
10+
display: flex;
11+
width: 20px;
12+
height: 20px;
13+
border-radius: 10px;
14+
border: 1px solid #e9ecef;
15+
background: #fff;
16+
align-items: center;
17+
justify-content: center;
18+
19+
&.failed,
20+
&.failed-score {
21+
color: #C1294F;
22+
}
23+
24+
&.passed {
25+
color: $teal-160;
26+
}
27+
28+
&.pending {
29+
color: $black-20;
30+
border-color: $black-20;
31+
}
32+
}
33+
34+
.score {
35+
font-size: 14px;
36+
.failed-score {
37+
color: #C1294F;
38+
}
39+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { FC, ReactNode, useCallback, useMemo } from 'react'
2+
import classNames from 'classnames'
3+
4+
import { IconOutline } from '~/libs/ui'
5+
6+
import { aiRunFailed, aiRunInProgress, AiWorkflowRun, AiWorkflowRunStatusEnum } from '../../hooks'
7+
8+
import StatusLabel from './StatusLabel'
9+
10+
interface AiWorkflowRunStatusProps {
11+
run: Pick<AiWorkflowRun, 'status'|'score'|'workflow'>
12+
hideLabel?: boolean
13+
showScore?: boolean
14+
}
15+
16+
export const AiWorkflowRunStatus: FC<AiWorkflowRunStatusProps> = props => {
17+
const isInProgress = useMemo(() => aiRunInProgress(props.run), [props.run.status])
18+
const isFailed = useMemo(() => aiRunFailed(props.run), [props.run.status])
19+
const isPassing = props.run.status === 'SUCCESS' && props.run.score >= (props.run.workflow.scorecard?.minimumPassingScore ?? 0)
20+
const status = isInProgress ? 'pending' : isFailed ? 'failed' : (
21+
isPassing ? 'passed' : 'failed-score'
22+
);
23+
24+
const score = props.showScore ? props.run.score : undefined;
25+
26+
return (
27+
<>
28+
{props.run.status === 'SUCCESS' && isPassing && (
29+
<StatusLabel icon={<IconOutline.CheckIcon className='icon-xl' />} hideLabel={props.hideLabel} label='Passed' status={status} score={score} />
30+
)}
31+
{props.run.status === 'SUCCESS' && !isPassing && (
32+
<StatusLabel icon={<IconOutline.MinusCircleIcon className='icon-xl' />} hideLabel={props.hideLabel} label='Failed' status={status} score={score} />
33+
)}
34+
{isInProgress && (
35+
<StatusLabel icon={<IconOutline.MinusIcon className='icon-md' />} hideLabel={props.hideLabel} label='To be filled' status={status} score={score} />
36+
)}
37+
{isFailed && (
38+
<StatusLabel icon={<IconOutline.XCircleIcon className='icon-xl' />} status={status} score={score} />
39+
)}
40+
</>
41+
)
42+
}
43+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
@import '@libs/ui/styles/includes';
2+
3+
.wrap {
4+
display: flex;
5+
align-items: center;
6+
gap: $sp-2;
7+
}
8+
9+
.icon {
10+
display: flex;
11+
width: 20px;
12+
height: 20px;
13+
border-radius: 10px;
14+
border: 1px solid #e9ecef;
15+
background: #fff;
16+
align-items: center;
17+
justify-content: center;
18+
19+
&.failed,
20+
&.failed-score {
21+
color: #C1294F;
22+
}
23+
24+
&.passed {
25+
color: $teal-160;
26+
}
27+
28+
&.pending {
29+
color: #e9ecef;
30+
border-color: #e9ecef;
31+
}
32+
}
33+
34+
.score {
35+
font-size: 14px;
36+
.failed-score {
37+
color: #C1294F;
38+
}
39+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { FC, ReactNode } from 'react'
2+
3+
import styles from './StatusLabel.module.scss'
4+
import classNames from 'classnames'
5+
6+
interface StatusLabelProps {
7+
icon: ReactNode
8+
hideLabel?: boolean
9+
label?: string
10+
score?: number
11+
status: 'pending' | 'failed' | 'passed' | 'failed-score'
12+
}
13+
14+
const StatusLabel: FC<StatusLabelProps> = props => {
15+
16+
return (
17+
<div className={styles.wrap}>
18+
{props.score && (
19+
<span className={classNames(styles[props.status], styles.score)}>{props.score}</span>
20+
)}
21+
{props.icon && (
22+
<span className={classNames(styles.icon, styles[props.status])}>
23+
{props.icon}
24+
</span>
25+
)}
26+
{!props.hideLabel && props.label}
27+
</div>
28+
)
29+
}
30+
31+
export default StatusLabel
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { default as AiReviewsTable } from './AiReviewsTable'
2+
export * from './AiWorkflowRunStatus'

0 commit comments

Comments
 (0)