Skip to content

Commit 9a11080

Browse files
authored
Merge pull request #1297 from topcoder-platform/PM-1906_ai-scorecard-browsing-ui
PM-1906 ai scorecard browsing UI
2 parents 8de38c5 + cf5bb7a commit 9a11080

40 files changed

+801
-113
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,11 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => {
144144
<td className={styles.scoreCol}>
145145
{run.status === 'SUCCESS' ? (
146146
run.workflow.scorecard ? (
147-
<a href={`/scorecard/${run.workflow.scorecard.id}`}>{run.score}</a>
147+
<a
148+
href={`./ai-scorecard/${props.submission.id}/${run.workflow.id}`}
149+
>
150+
{run.score}
151+
</a>
148152
) : run.score
149153
) : '-'}
150154
</td>

src/apps/review/src/lib/components/Scorecard/ScorecardAttachments/ScorecardAttachments.module.scss

Whitespace-only changes.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { FC } from 'react'
2+
3+
// import styles from './ScorecardAttachments.module.scss'
4+
5+
interface ScorecardAttachmentsProps {
6+
className?: string
7+
}
8+
9+
const ScorecardAttachments: FC<ScorecardAttachmentsProps> = props => (
10+
<div className={props.className}>
11+
attachments
12+
</div>
13+
)
14+
15+
export default ScorecardAttachments
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as ScorecardAttachments } from './ScorecardAttachments'
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
@import '@libs/ui/styles/includes';
2+
3+
.wrap {
4+
}
5+
6+
.headerBar {
7+
display: flex;
8+
align-items: center;
9+
gap: $sp-4;
10+
11+
background: #00797A;
12+
padding: $sp-4;
13+
14+
font-family: "Nunito Sans", sans-serif;
15+
font-weight: bold;
16+
font-size: 16px;
17+
line-height: 22px;
18+
color: #FFFFFF;
19+
20+
cursor: pointer;
21+
transition: 0.15s ease-in-out;
22+
23+
&:hover {
24+
background: darken(#00797A, 1.5%);
25+
}
26+
27+
&:active {
28+
transition: none;
29+
background: darken(#00797A, 3%);
30+
}
31+
32+
&.toggled {
33+
.toggleBtn {
34+
svg {
35+
transform: rotate(180deg);
36+
}
37+
}
38+
}
39+
40+
@include ltemd {
41+
flex-wrap: wrap;
42+
row-gap: $sp-2;
43+
44+
.score {
45+
order: 7;
46+
width: 100%;
47+
margin-left: $sp-10;
48+
}
49+
}
50+
}
51+
52+
.index {
53+
width: 24px;
54+
}
55+
56+
.mx {
57+
margin: 0 auto;
58+
}
59+
60+
.toggleBtn {
61+
cursor: pointer;
62+
width: 24px;
63+
64+
svg {
65+
display: block;
66+
width: 16px;
67+
height: 16px;
68+
transition: 0.15s ease-in-out;
69+
}
70+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { FC, useCallback, useMemo } from 'react'
2+
import classNames from 'classnames'
3+
4+
import { IconOutline } from '~/libs/ui'
5+
6+
import { ScorecardGroup as ScorecardGroupModel } from '../../../../models'
7+
import { ScorecardSection } from '../ScorecardSection'
8+
import { ScorecardViewerContextValue, useScorecardContext } from '../ScorecardViewer.context'
9+
import { ScorecardScore } from '../ScorecardScore'
10+
import { calcGroupScore } from '../utils'
11+
12+
import styles from './ScorecardGroup.module.scss'
13+
14+
interface ScorecardGroupProps {
15+
index: number
16+
group: ScorecardGroupModel
17+
}
18+
19+
const ScorecardGroup: FC<ScorecardGroupProps> = props => {
20+
const { aiFeedbackItems }: ScorecardViewerContextValue = useScorecardContext()
21+
const allFeedbackItems = aiFeedbackItems || []
22+
const { toggleItem, toggledItems }: ScorecardViewerContextValue = useScorecardContext()
23+
24+
const isVissible = !toggledItems[props.group.id]
25+
const toggle = useCallback(() => toggleItem(props.group.id), [props.group, toggleItem])
26+
27+
const score = useMemo(() => (
28+
calcGroupScore(props.group, allFeedbackItems)
29+
), [props.group, allFeedbackItems])
30+
31+
return (
32+
<div className={styles.wrap}>
33+
<div className={classNames(styles.headerBar, isVissible && styles.toggled)} onClick={toggle}>
34+
<span className={styles.index}>
35+
{props.index}
36+
.
37+
</span>
38+
<span className={styles.name}>
39+
{props.group.name}
40+
</span>
41+
<span className={styles.mx} />
42+
<span className={styles.score}>
43+
<ScorecardScore
44+
score={score}
45+
scaleMax={1}
46+
weight={props.group.weight}
47+
/>
48+
</span>
49+
<span className={styles.toggleBtn}>
50+
<IconOutline.ChevronDownIcon />
51+
</span>
52+
</div>
53+
54+
{isVissible && props.group.sections.map((section, index) => (
55+
<ScorecardSection key={section.id} section={section} index={[props.index, index + 1].join('.')} />
56+
))}
57+
</div>
58+
)
59+
}
60+
61+
export default ScorecardGroup
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as ScorecardGroup } from './ScorecardGroup'
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@import '@libs/ui/styles/includes';
2+
3+
.wrap {
4+
p {
5+
margin-bottom: $sp-4;
6+
7+
@include ltemd {
8+
margin-bottom: $sp-2;
9+
}
10+
}
11+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { FC, useMemo } from 'react'
2+
3+
import { IconAiReview } from '~/apps/review/src/lib/assets/icons'
4+
import { ScorecardQuestion } from '~/apps/review/src/lib/models'
5+
6+
import { ScorecardViewerContextValue, useScorecardContext } from '../../ScorecardViewer.context'
7+
import { ScorecardQuestionRow } from '../ScorecardQuestionRow'
8+
import { ScorecardScore } from '../../ScorecardScore'
9+
10+
import styles from './AiFeedback.module.scss'
11+
12+
interface AiFeedbackProps {
13+
question: ScorecardQuestion
14+
}
15+
16+
const AiFeedback: FC<AiFeedbackProps> = props => {
17+
const { aiFeedbackItems }: ScorecardViewerContextValue = useScorecardContext()
18+
const feedback = useMemo(() => (
19+
aiFeedbackItems?.find(r => r.scorecardQuestionId === props.question.id)
20+
), [props.question.id, aiFeedbackItems])
21+
22+
if (!aiFeedbackItems?.length || !feedback) {
23+
return <></>
24+
}
25+
26+
const isYesNo = props.question.type === 'YES_NO'
27+
28+
return (
29+
<ScorecardQuestionRow
30+
icon={<IconAiReview />}
31+
index='AI Feedback'
32+
className={styles.wrap}
33+
score={(
34+
<ScorecardScore
35+
score={feedback.questionScore}
36+
scaleMax={props.question.scaleMax}
37+
weight={props.question.weight}
38+
/>
39+
)}
40+
>
41+
{isYesNo && (
42+
<p>
43+
<strong>{feedback.questionScore ? 'Yes' : 'No'}</strong>
44+
</p>
45+
)}
46+
{feedback.content}
47+
</ScorecardQuestionRow>
48+
)
49+
}
50+
51+
export default AiFeedback
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as AiFeedback } from './AiFeedback'

0 commit comments

Comments
 (0)