@@ -3,13 +3,17 @@ import PropTypes from 'prop-types';
33import ImmutablePropTypes from 'react-immutable-proptypes' ;
44import { FormattedMessage } from 'react-intl' ;
55import { Table } from 'react-bootstrap' ;
6+ import { defaultMemoize } from 'reselect' ;
67
78import NoSolutionYetTableRow from './NoSolutionYetTableRow' ;
89import SolutionsTableRow from './SolutionsTableRow' ;
910import { LoadingIcon } from '../../icons' ;
11+ import { EMPTY_ARRAY } from '../../../helpers/common' ;
1012
1113import styles from './SolutionsTable.less' ;
1214
15+ const createHighlightsIndex = defaultMemoize ( highlights => new Set ( highlights ) ) ;
16+
1317const SolutionsTable = ( {
1418 assignmentId,
1519 groupId,
@@ -18,122 +22,128 @@ const SolutionsTable = ({
1822 noteMaxlen = null ,
1923 compact = false ,
2024 selected = null ,
25+ highlights = EMPTY_ARRAY ,
2126 assignmentSolver = null ,
2227 assignmentSolversLoading = false ,
2328 showActionButtons = true ,
2429 onSelect = null ,
25- } ) => (
26- < Table responsive className = { styles . solutionsTable } >
27- < thead >
28- < tr >
29- < th />
30- < th />
31- < th >
32- < FormattedMessage id = "app.solutionsTable.submissionDate" defaultMessage = "Date of submission" />
33- </ th >
34- < th className = "text-center" >
35- < FormattedMessage id = "app.solutionsTable.solutionValidity" defaultMessage = "Validity" />
36- </ th >
37- < th className = "text-center" >
38- < FormattedMessage id = "app.solutionsTable.receivedPoints" defaultMessage = "Points" />
39- </ th >
40- < th className = "text-center" >
41- < FormattedMessage id = "app.solutionsTable.environment" defaultMessage = "Target language" />
42- </ th >
30+ } ) => {
31+ const highlightsIndex = createHighlightsIndex ( highlights ) ;
4332
44- { ! compact && (
33+ return (
34+ < Table responsive className = { styles . solutionsTable } >
35+ < thead >
36+ < tr >
37+ < th />
38+ < th />
4539 < th >
46- < FormattedMessage id = "app.solutionsTable.note" defaultMessage = "Note" />
40+ < FormattedMessage id = "app.solutionsTable.submissionDate" defaultMessage = "Date of submission" />
41+ </ th >
42+ < th className = "text-center" >
43+ < FormattedMessage id = "app.solutionsTable.solutionValidity" defaultMessage = "Validity" />
44+ </ th >
45+ < th className = "text-center" >
46+ < FormattedMessage id = "app.solutionsTable.receivedPoints" defaultMessage = "Points" />
47+ </ th >
48+ < th className = "text-center" >
49+ < FormattedMessage id = "app.solutionsTable.environment" defaultMessage = "Target language" />
4750 </ th >
48- ) }
4951
50- { ( ! compact || showActionButtons ) && (
51- < td className = "text-right text-muted small" >
52- { assignmentSolversLoading ? (
53- < LoadingIcon />
54- ) : (
55- < >
56- { assignmentSolver &&
57- ( assignmentSolver . get ( 'lastAttemptIndex' ) > 5 ||
58- assignmentSolver . get ( 'lastAttemptIndex' ) > solutions . size ) && (
59- < >
60- { ! compact && (
61- < FormattedMessage
62- id = "app.solutionsTable.attemptsCount"
63- defaultMessage = "Solutions submitted: {count}"
64- values = { { count : assignmentSolver . get ( 'lastAttemptIndex' ) } }
65- />
66- ) }
52+ { ! compact && (
53+ < th >
54+ < FormattedMessage id = "app.solutionsTable.note" defaultMessage = "Note" />
55+ </ th >
56+ ) }
6757
68- { assignmentSolver . get ( 'lastAttemptIndex' ) > solutions . size && (
69- < span >
70- { ! compact && < > </ > } (
58+ { ( ! compact || showActionButtons ) && (
59+ < td className = "text-right text-muted small" >
60+ { assignmentSolversLoading ? (
61+ < LoadingIcon />
62+ ) : (
63+ < >
64+ { assignmentSolver &&
65+ ( assignmentSolver . get ( 'lastAttemptIndex' ) > 5 ||
66+ assignmentSolver . get ( 'lastAttemptIndex' ) > solutions . size ) && (
67+ < >
68+ { ! compact && (
7169 < FormattedMessage
72- id = "app.solutionsTable.attemptsDeleted "
73- defaultMessage = "{deleted} deleted "
74- values = { { deleted : assignmentSolver . get ( 'lastAttemptIndex' ) - solutions . size } }
70+ id = "app.solutionsTable.attemptsCount "
71+ defaultMessage = "Solutions submitted: {count} "
72+ values = { { count : assignmentSolver . get ( 'lastAttemptIndex' ) } }
7573 />
76- )
77- </ span >
78- ) }
79- </ >
74+ ) }
75+
76+ { assignmentSolver . get ( 'lastAttemptIndex' ) > solutions . size && (
77+ < span >
78+ { ! compact && < > </ > } (
79+ < FormattedMessage
80+ id = "app.solutionsTable.attemptsDeleted"
81+ defaultMessage = "{deleted} deleted"
82+ values = { { deleted : assignmentSolver . get ( 'lastAttemptIndex' ) - solutions . size } }
83+ />
84+ )
85+ </ span >
86+ ) }
87+ </ >
88+ ) }
89+
90+ { ! compact && ! assignmentSolver && solutions . size > 5 && (
91+ < FormattedMessage
92+ id = "app.solutionsTable.rowsCount"
93+ defaultMessage = "Total records: {count}"
94+ values = { { count : solutions . size } }
95+ />
8096 ) }
97+ </ >
98+ ) }
99+ </ td >
100+ ) }
101+ </ tr >
102+ </ thead >
103+ { solutions . size === 0 ? (
104+ < NoSolutionYetTableRow />
105+ ) : (
106+ solutions . map ( ( data , idx ) => {
107+ if ( ! data ) {
108+ return (
109+ < tbody key = { idx } >
110+ < tr >
111+ < td colSpan = { compact ? 6 : 7 } className = "text-center" >
112+ < LoadingIcon size = "xs" />
113+ </ td >
114+ </ tr >
115+ </ tbody >
116+ ) ;
117+ }
118+
119+ const id = data . id ;
120+ const runtimeEnvironment =
121+ data . runtimeEnvironmentId &&
122+ runtimeEnvironments &&
123+ runtimeEnvironments . find ( ( { id } ) => id === data . runtimeEnvironmentId ) ;
81124
82- { ! compact && ! assignmentSolver && solutions . size > 5 && (
83- < FormattedMessage
84- id = "app.solutionsTable.rowsCount"
85- defaultMessage = "Total records: {count}"
86- values = { { count : solutions . size } }
87- />
88- ) }
89- </ >
90- ) }
91- </ td >
92- ) }
93- </ tr >
94- </ thead >
95- { solutions . size === 0 ? (
96- < NoSolutionYetTableRow />
97- ) : (
98- solutions . map ( ( data , idx ) => {
99- if ( ! data ) {
100125 return (
101- < tbody key = { idx } >
102- < tr >
103- < td colSpan = { compact ? 6 : 7 } className = "text-center" >
104- < LoadingIcon size = "xs" />
105- </ td >
106- </ tr >
107- </ tbody >
126+ < SolutionsTableRow
127+ key = { id }
128+ id = { id }
129+ status = { data . lastSubmission ? data . lastSubmission . evaluationStatus : null }
130+ runtimeEnvironment = { runtimeEnvironment }
131+ assignmentId = { assignmentId }
132+ groupId = { groupId }
133+ noteMaxlen = { noteMaxlen }
134+ compact = { compact }
135+ selected = { id === selected }
136+ highlighted = { highlightsIndex . has ( id ) }
137+ showActionButtons = { showActionButtons }
138+ onSelect = { onSelect }
139+ { ...data }
140+ />
108141 ) ;
109- }
110-
111- const id = data . id ;
112- const runtimeEnvironment =
113- data . runtimeEnvironmentId &&
114- runtimeEnvironments &&
115- runtimeEnvironments . find ( ( { id } ) => id === data . runtimeEnvironmentId ) ;
116-
117- return (
118- < SolutionsTableRow
119- key = { id }
120- id = { id }
121- status = { data . lastSubmission ? data . lastSubmission . evaluationStatus : null }
122- runtimeEnvironment = { runtimeEnvironment }
123- assignmentId = { assignmentId }
124- groupId = { groupId }
125- noteMaxlen = { noteMaxlen }
126- compact = { compact }
127- selected = { id === selected }
128- showActionButtons = { showActionButtons }
129- onSelect = { onSelect }
130- { ...data }
131- />
132- ) ;
133- } )
134- ) }
135- </ Table >
136- ) ;
142+ } )
143+ ) }
144+ </ Table >
145+ ) ;
146+ } ;
137147
138148SolutionsTable . propTypes = {
139149 assignmentId : PropTypes . string . isRequired ,
@@ -143,6 +153,7 @@ SolutionsTable.propTypes = {
143153 noteMaxlen : PropTypes . number ,
144154 compact : PropTypes . bool ,
145155 selected : PropTypes . string ,
156+ highlights : PropTypes . array ,
146157 assignmentSolver : ImmutablePropTypes . map ,
147158 assignmentSolversLoading : PropTypes . bool ,
148159 showActionButtons : PropTypes . bool ,
0 commit comments