-
-
Notifications
You must be signed in to change notification settings - Fork 204
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add detailed feedback in cross-check-pairs table (#2258)
* feat: add detailed feedback in cross-check-pairs table * refactor: remove code duplicate * refactor: create table component * refactor: prettier * fix: update imports * refactor: prettier * refactor: fixes after code review
- Loading branch information
1 parent
9091140
commit 4d47dd9
Showing
17 changed files
with
500 additions
and
444 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
client/src/modules/CrossCheck/components/criteria/CrossCheckCriteria.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { Typography } from 'antd'; | ||
import { TaskType } from '../CrossCheckCriteriaForm'; | ||
import { CrossCheckCriteriaDataDto } from 'api'; | ||
|
||
const { Text, Title } = Typography; | ||
|
||
type Props = { | ||
criteria: CrossCheckCriteriaDataDto[] | null; | ||
}; | ||
|
||
export function CrossCheckCriteria({ criteria }: Props) { | ||
if (!criteria?.length) return null; | ||
const penaltyData = criteria.filter( | ||
criteriaItem => criteriaItem.type.toLocaleLowerCase() === TaskType.Penalty && criteriaItem.point, | ||
); | ||
|
||
return ( | ||
<> | ||
{criteria | ||
.filter(criteriaItem => criteriaItem.type.toLocaleLowerCase() === TaskType.Subtask) | ||
.map(criteriaItem => ( | ||
<div key={criteriaItem.key} style={{ border: '1px solid #F5F5F5', margin: '24px 0', paddingBottom: '14px' }}> | ||
<div | ||
style={{ | ||
display: 'block', | ||
fontSize: '14px', | ||
background: '#FAFAFA', | ||
borderBottom: '1px solid #F5F5F5', | ||
padding: '14px 12px', | ||
marginBottom: '14px', | ||
}} | ||
> | ||
<Text>{criteriaItem.text}</Text> | ||
</div> | ||
|
||
{criteriaItem.textComment && ( | ||
<div style={{ padding: '0 12px', fontSize: '16px' }}> | ||
<Text strong={true}>Comment:</Text> | ||
{criteriaItem.textComment?.split('\n').map((textLine, k) => ( | ||
<p key={k} style={{ margin: '0px 0 5px 0' }}> | ||
{textLine} | ||
</p> | ||
))} | ||
</div> | ||
)} | ||
<div style={{ fontSize: '16px', padding: '0 12px' }}> | ||
<Text strong={true}>Points for criteria: {`${criteriaItem.point ?? 0}/${criteriaItem.max}`}</Text> | ||
</div> | ||
</div> | ||
))} | ||
{penaltyData?.length ? ( | ||
<div style={{ marginTop: '20px' }}> | ||
<Title level={4}>Penalty</Title> | ||
{penaltyData?.map(criteriaItem => ( | ||
<div | ||
key={criteriaItem.key} | ||
style={{ | ||
display: 'inline-block', | ||
width: '100%', | ||
backgroundColor: '#fff2f2', | ||
border: '1px #ffb0b0 solid', | ||
padding: '14px 12px', | ||
}} | ||
> | ||
<Text> | ||
{criteriaItem.text} {criteriaItem.point ?? 0} | ||
</Text> | ||
</div> | ||
))} | ||
</div> | ||
) : null} | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
66 changes: 66 additions & 0 deletions
66
client/src/modules/CrossCheckPairs/components/CrossCheckPairsTable/CrossCheckPairsTable.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { Table, TablePaginationConfig } from 'antd'; | ||
import { CrossCheckPairDto } from 'api'; | ||
import { FilterValue, SorterResult } from 'antd/lib/table/interface'; | ||
import { | ||
CustomColumnType, | ||
fields, | ||
getCrossCheckPairsColumns, | ||
} from 'modules/CrossCheckPairs/data/getCrossCheckPairsColumns'; | ||
import css from 'styled-jsx/css'; | ||
|
||
export type Filters = Omit<typeof fields, 'score' | 'submittedDate' | 'reviewedDate'>; | ||
|
||
interface CustomSorterResult<RecordType> extends SorterResult<RecordType> { | ||
column?: CustomColumnType<RecordType>; | ||
} | ||
|
||
export type Sorter<RecordType> = CustomSorterResult<RecordType> | CustomSorterResult<RecordType>[]; | ||
|
||
type CrossCheckTableProps = { | ||
loaded: boolean; | ||
crossCheckPairs: CrossCheckPairDto[]; | ||
pagination: TablePaginationConfig; | ||
onChange: ( | ||
pagination: TablePaginationConfig, | ||
filters: Record<keyof Filters, FilterValue | null>, | ||
sorter: Sorter<CrossCheckPairDto>, | ||
) => void; | ||
viewComment: (value: CrossCheckPairDto) => void; | ||
}; | ||
|
||
export const CrossCheckPairsTable = ({ | ||
loaded, | ||
crossCheckPairs, | ||
pagination, | ||
onChange, | ||
viewComment, | ||
}: CrossCheckTableProps) => { | ||
if (!loaded) return null; | ||
|
||
// where 800 is approximate sum of basic columns (GitHub, Name, etc.) | ||
const tableWidth = 800; | ||
return ( | ||
<> | ||
<Table<CrossCheckPairDto> | ||
className="table-score" | ||
showHeader | ||
scroll={{ x: tableWidth, y: 'calc(100vh - 250px)' }} | ||
pagination={pagination} | ||
dataSource={crossCheckPairs} | ||
size="small" | ||
rowClassName={'cross-check-table-row'} | ||
onChange={onChange} | ||
key="id" | ||
columns={getCrossCheckPairsColumns(viewComment)} | ||
/> | ||
<style jsx>{styles}</style> | ||
</> | ||
); | ||
}; | ||
|
||
const styles = css` | ||
:global(.cross-check-table-row, .table-score td, .table-score th) { | ||
padding: 0 5px !important; | ||
font-size: 11px; | ||
} | ||
`; |
114 changes: 114 additions & 0 deletions
114
client/src/modules/CrossCheckPairs/data/getCrossCheckPairsColumns.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { CrossCheckPairDto } from 'api'; | ||
import { ColumnType } from 'antd/lib/table/interface'; | ||
import { omit } from 'lodash'; | ||
import { dateTimeRenderer, getColumnSearchProps } from 'components/Table'; | ||
import { GithubAvatar } from 'components/GithubAvatar'; | ||
import { Button } from 'antd'; | ||
|
||
export const fields = { | ||
task: 'task', | ||
checker: 'checker', | ||
student: 'student', | ||
url: 'url', | ||
score: 'score', | ||
submittedDate: 'submittedDate', | ||
reviewedDate: 'reviewedDate', | ||
}; | ||
|
||
export interface CustomColumnType<RecordType> extends ColumnType<RecordType> { | ||
sorterField?: string; | ||
} | ||
|
||
const renderGithubLink = (value: string) => | ||
value ? ( | ||
<div> | ||
<GithubAvatar githubId={value} size={24} /> | ||
| ||
<a target="_blank" rel="noopener noreferrer" href={`https://github.com/${value}`}> | ||
{value} | ||
</a> | ||
</div> | ||
) : null; | ||
|
||
export const getCrossCheckPairsColumns = ( | ||
viewComment: (value: CrossCheckPairDto) => void, | ||
): CustomColumnType<CrossCheckPairDto>[] => [ | ||
{ | ||
title: 'Task', | ||
fixed: 'left', | ||
dataIndex: ['task', 'name'], | ||
key: fields.task, | ||
width: 100, | ||
sorter: true, | ||
sorterField: 'task', | ||
...omit(getColumnSearchProps(['task', 'name']), 'onFilter'), | ||
}, | ||
{ | ||
title: 'Checker', | ||
fixed: 'left', | ||
key: fields.checker, | ||
dataIndex: ['checker', 'githubId'], | ||
sorter: true, | ||
sorterField: 'checker', | ||
width: 150, | ||
render: renderGithubLink, | ||
...omit(getColumnSearchProps(['checkerStudent', 'githubId']), 'onFilter'), | ||
}, | ||
{ | ||
title: 'Student', | ||
key: fields.student, | ||
dataIndex: ['student', 'githubId'], | ||
sorter: true, | ||
sorterField: 'student', | ||
width: 150, | ||
render: renderGithubLink, | ||
...omit(getColumnSearchProps(['student', 'githubId']), 'onFilter'), | ||
}, | ||
{ | ||
title: 'Url', | ||
dataIndex: 'url', | ||
key: fields.url, | ||
width: 150, | ||
sorter: true, | ||
sorterField: 'url', | ||
...getColumnSearchProps('url'), | ||
}, | ||
{ | ||
title: 'Score', | ||
dataIndex: 'score', | ||
key: fields.score, | ||
width: 80, | ||
sorter: true, | ||
sorterField: 'score', | ||
render: value => <>{value ?? '(Empty)'}</>, | ||
}, | ||
{ | ||
title: 'Submitted Date', | ||
dataIndex: 'submittedDate', | ||
key: fields.submittedDate, | ||
width: 80, | ||
sorter: true, | ||
sorterField: 'submittedDate', | ||
render: dateTimeRenderer, | ||
}, | ||
{ | ||
title: 'Reviewed Date', | ||
dataIndex: 'reviewedDate', | ||
key: fields.reviewedDate, | ||
width: 80, | ||
sorter: true, | ||
sorterField: 'reviewedDate', | ||
render: (_, record) => dateTimeRenderer(record.reviewedDate), | ||
}, | ||
{ | ||
title: 'Comment', | ||
dataIndex: 'comment', | ||
key: 'comment', | ||
width: 60, | ||
render: (_, record) => ( | ||
<Button disabled={!record.historicalScores} onClick={() => viewComment(record)} type="link" size="small"> | ||
Show | ||
</Button> | ||
), | ||
}, | ||
]; |
Oops, something went wrong.