Skip to content

Commit 44eb39e

Browse files
committed
CHG make autograde page submission tests same as what students see
1 parent 3a3fc32 commit 44eb39e

File tree

4 files changed

+231
-374
lines changed

4 files changed

+231
-374
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
1-
import React from 'react';
1+
import React, {useState} from 'react';
2+
23
import makeStyles from '@mui/styles/makeStyles';
3-
import Typography from '@mui/material/Typography';
4-
import Accordion from '@mui/material/Accordion';
5-
import AccordionSummary from '@mui/material/AccordionSummary';
6-
import AccordionDetails from '@mui/material/AccordionDetails';
7-
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
8-
import CircularProgress from '@mui/material/CircularProgress';
9-
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
104
import green from '@mui/material/colors/green';
11-
import CancelIcon from '@mui/icons-material/Cancel';
12-
import Fab from '@mui/material/Fab';
13-
import AssessmentIcon from '@mui/icons-material/Assessment';
14-
import HighlightOffIcon from '@mui/icons-material/HighlightOff';
155
import {Tooltip} from '@mui/material';
16-
import IconButton from '@mui/material/IconButton';
6+
import Box from '@mui/material/Box';
7+
import Button from '@mui/material/Button';
8+
import DeleteForeverIcon from '@mui/icons-material/DeleteForever';
9+
10+
import {useHistory} from 'react-router-dom';
11+
import {useSnackbar} from 'notistack';
12+
import axios from 'axios';
13+
import clsx from 'clsx';
14+
15+
import SubmissionTestExpanded from '../SubmissionTestExpanded/SubmissionTestExpanded';
16+
import SubmissionContent from '../SubmissionContent/SubmissionContent';
17+
import SubmissionTest from '../SubmissionTest/SubmissionTest';
18+
import SubmissionHeader from '../SubmissionHeader/SubmissionHeader';
19+
import {submissionUpdateSubscribe} from '../../../constant';
20+
import standardStatusHandler from '../../../utils/standardStatusHandler';
21+
import {translateSubmission} from '../../../utils/submission';
22+
import standardErrorHandler from '../../../utils/standardErrorHandler';
23+
1724

1825
const useStyles = makeStyles((theme) => ({
1926
heading: {
@@ -37,83 +44,222 @@ const useStyles = makeStyles((theme) => ({
3744
left: -6,
3845
zIndex: 1,
3946
},
47+
submissionContentContainer: {
48+
width: '100%',
49+
marginTop: theme.spacing(2),
50+
},
4051
}));
4152

53+
const regrade = (
54+
{submission, setSubmission, setStep, setErrorStop},
55+
continueSubscribe,
56+
enqueueSnackbar,
57+
) => () => {
58+
if (!submission.processed) {
59+
return enqueueSnackbar('Submission must first finish tests before regrading.', {variant: 'warning'});
60+
}
61+
62+
axios
63+
.get(`/api/public/submissions/regrade/${submission.commit}`)
64+
.then((response) => {
65+
const data = standardStatusHandler(response, enqueueSnackbar);
66+
if (data) {
67+
setErrorStop(false);
68+
setStep(-1);
69+
setSubmission(null);
70+
continueSubscribe();
71+
enqueueSnackbar('Regrading submission', {variant: 'success'});
72+
} else {
73+
enqueueSnackbar(`Unable to regrade`, {variant: 'error'});
74+
}
75+
})
76+
.catch((error) => {
77+
enqueueSnackbar(error.toString(), {variant: 'error'});
78+
});
79+
};
80+
4281

43-
export default function SubmissionTests({tests, stop}) {
82+
export default function SubmissionTests({submissionId}) {
4483
const classes = useStyles();
84+
const [step, setStep] = useState(0);
85+
const [modalTest, setModalTest] = useState(null);
86+
const [isExpanded, setIsExpanded] = useState(false);
87+
const [submission, setSubmission] = useState(null);
88+
const {enqueueSnackbar} = useSnackbar();
89+
const history = useHistory();
90+
91+
const continueSubscribe = () => setTimeout(() => {
92+
if (step < submissionUpdateSubscribe) {
93+
setStep((state) => ++state);
94+
}
95+
}, 1000);
96+
97+
React.useEffect(() => {
98+
if (!submissionId) {
99+
return;
100+
}
101+
axios.get(
102+
`/api/public/submissions/get/${submissionId}`,
103+
).then((response) => {
104+
const data = standardStatusHandler(response, enqueueSnackbar);
105+
if (!data) {
106+
return;
107+
}
108+
109+
const newSubmission = translateSubmission(data.submission);
110+
111+
// sort all the tests in Alpha Order
112+
newSubmission.tests.sort(function(a, b) {
113+
return a.test.order > b.test.order;
114+
});
45115

46-
if (!tests) {
116+
setSubmission(newSubmission);
117+
118+
119+
if (!submission) {
120+
return continueSubscribe();
121+
}
122+
123+
if (submission.build.passed !== newSubmission.build.passed) {
124+
if (newSubmission.build.passed === true) {
125+
enqueueSnackbar('Build passed', {variant: 'success'});
126+
} else if (newSubmission.build.passed === false) {
127+
return enqueueSnackbar('Build failed', {variant: 'error'});
128+
}
129+
}
130+
131+
for (let index = 0; index < submission.tests.length; index++) {
132+
const oldTest = submission.tests[index];
133+
const newTest = newSubmission.tests[index];
134+
135+
if (oldTest.result.passed === null && newTest.result.passed !== null) {
136+
enqueueSnackbar(
137+
`${newTest.test.name} ${newTest.result.passed ? 'passed' : 'failed'}`,
138+
{variant: (newTest.result.passed ? 'success' : 'error')});
139+
}
140+
}
141+
142+
if (!submission.processed) {
143+
continueSubscribe();
144+
}
145+
}).catch((error) => enqueueSnackbar(error.toString(), {variant: 'error'}));
146+
}, [step, submissionId]);
147+
148+
const expandModal = (test) => {
149+
setModalTest(test);
150+
setIsExpanded(true);
151+
};
152+
153+
const closeModal = () => {
154+
setIsExpanded(false);
155+
setModalTest(null);
156+
};
157+
158+
if (!submissionId || !submission) {
47159
return null;
48160
}
49161

162+
const pipelineLogTest = {
163+
test: {
164+
name: 'Pipeline Log',
165+
},
166+
result: {
167+
test_name: 'Pipeline Log',
168+
passed: !!submission?.build?.passed,
169+
message: 'Not Visible to Students',
170+
output_type: 'text',
171+
output: submission?.pipeline_log ?? null,
172+
},
173+
};
174+
175+
const buildTest = {
176+
test: {
177+
name: 'Build',
178+
},
179+
result: {
180+
test_name: 'Build',
181+
passed: !!submission?.build?.passed,
182+
message: !!submission?.build?.passed ? 'Build Succeeded' : 'Build Failed',
183+
output_type: 'text',
184+
output: submission?.build?.stdout ?? null,
185+
},
186+
};
187+
188+
50189
return (
51190
<React.Fragment>
52-
{tests.map((test, index) => (
53-
<Accordion key={`test-${index}`}>
54-
<AccordionSummary
55-
expandIcon={<ExpandMoreIcon/>}
56-
aria-controls="panel2a-content"
57-
id="panel2a-header"
58-
>
59-
<div className={classes.wrapper}>
60-
<Fab
61-
aria-label="save"
62-
color={stop ? 'error' : (test.result.passed === false ? 'error' : 'primary')}
63-
>
64-
{stop ? (
65-
<CancelIcon/>
66-
) : (
67-
<React.Fragment>
68-
{test.result.passed === null ? (
69-
<AssessmentIcon/>
70-
) : (test.result.passed === true) ? (
71-
<CheckCircleIcon/>
72-
) : (test.result.passed === false) ? (
73-
<CancelIcon/>
74-
) : null}
75-
</React.Fragment>
76-
)}
77-
</Fab>
78-
{stop ? null : (
79-
test.result.passed === null && <CircularProgress size={68} className={classes.fabProgress}/>
80-
)}
81-
</div>
82-
<Typography className={classes.heading}>{test.test.name}</Typography>
83-
{test.test.hidden ? (
84-
<div className={classes.hiddenIcon}>
85-
<Tooltip title={'Test hidden to students'}>
86-
<IconButton size="large">
87-
<HighlightOffIcon/>
88-
</IconButton>
89-
</Tooltip>
90-
</div>
91-
) : null}
92-
</AccordionSummary>
93-
<AccordionDetails>
94-
<div>
95-
<Typography key={'message'} variant={'h5'} className={classes.heading}>
96-
{test.result.message}
97-
</Typography>
98-
{test.result.passed !== null && !!test.result.stdout ?
99-
test.result.stdout.trim().split('\n')
100-
.map((line, index) => (
101-
line.trim().length !== 0 ?
102-
<Typography
103-
variant={'body1'}
104-
color={'textSecondary'}
105-
width={100}
106-
key={`line-${index}`}
107-
>
108-
{line}
109-
</Typography> :
110-
<br/>
111-
)) :
112-
null}
113-
</div>
114-
</AccordionDetails>
115-
</Accordion>
116-
))}
191+
{!!submission?.pipeline_log && (
192+
<Box sx={{m: 1}}>
193+
<Tooltip title="Delete submission forever from Anubis">
194+
<Button
195+
variant={'contained'}
196+
color={'error'}
197+
startIcon={<DeleteForeverIcon/>}
198+
className={clsx(classes.dataItem)}
199+
onClick={() => {
200+
axios.delete(`/api/admin/submissions/delete/${submissionId}`).then((response) => {
201+
const data = standardStatusHandler(response, enqueueSnackbar);
202+
if (data) {
203+
history.go(-1);
204+
}
205+
}).catch(standardErrorHandler(enqueueSnackbar));
206+
}}
207+
>
208+
Delete
209+
</Button>
210+
</Tooltip>
211+
</Box>
212+
)}
213+
<Box className={classes.headerContainer}>
214+
<SubmissionHeader
215+
admin={!!submission?.pipeline_log}
216+
regrade={regrade(
217+
{submission, setSubmission, setStep},
218+
continueSubscribe,
219+
enqueueSnackbar,
220+
)}
221+
{...submission}
222+
/>
223+
</Box>
224+
<Box className={classes.submissionContentContainer}>
225+
<SubmissionContent submission={submission}>
226+
{submission?.pipeline_log && (
227+
<SubmissionTest
228+
test={pipelineLogTest}
229+
processing={submission.processing}
230+
expandModal={() => expandModal(pipelineLogTest)}
231+
/>
232+
)}
233+
{!submission.commit.startsWith('fake-') && (
234+
<SubmissionTest
235+
test={buildTest}
236+
processing={submission.processing}
237+
expandModal={() => expandModal(buildTest)}
238+
/>
239+
)}
240+
{submission?.tests && submission.tests.map((test, index) => (
241+
<SubmissionTest
242+
key={index}
243+
test={test}
244+
processing={submission.processing}
245+
expandModal={() => expandModal(test)}
246+
/>
247+
))}
248+
</SubmissionContent>
249+
</Box>
250+
{modalTest &&
251+
<SubmissionTestExpanded
252+
open={isExpanded}
253+
submissionID={submission.commit}
254+
assignmentName={submission.assignment_name}
255+
testName={modalTest.result.test_name}
256+
testSuccess={modalTest.result.passed}
257+
testOutputType={modalTest.result.output_type}
258+
testOutput={modalTest.result.output}
259+
testMessage={modalTest.result.message}
260+
onClose={() => closeModal()}
261+
/>
262+
}
117263
</React.Fragment>
118264
);
119265
}

web/src/pages/core/admin/Autograde/Submission.jsx

+2-8
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,8 @@ export default function Submission() {
8181
<Grid item xs={12}>
8282
<QuestionsCard questions={questions}/>
8383
</Grid>
84-
<Grid item xs={12} md={4}>
85-
<SubmissionSummary submission={submission} regrade={null}/>
86-
</Grid>
87-
<Grid item xs={12} md={4}>
88-
<SubmissionBuild build={submission?.build}/>
89-
</Grid>
90-
<Grid item xs={12} md={4}>
91-
<SubmissionTests tests={submission?.tests}/>
84+
<Grid item xs={12}>
85+
<SubmissionTests submissionId={submission?.id}/>
9286
</Grid>
9387
</Grid>
9488
</Grid>

0 commit comments

Comments
 (0)