Skip to content

Commit bea80f9

Browse files
committed
fix(graderView-part-3): standardize grader's student view to match actual student experience
Ensures that grader's student view accurately reflects what students are seeing at the same time for past attempts view (using the "All Answers" button) Add display settings props to AnswerDetails component to control visibility of various answer elements like test cases, rubric breakdown, and MCQ/MRQ solutions.
1 parent 976dfdd commit bea80f9

File tree

12 files changed

+186
-48
lines changed

12 files changed

+186
-48
lines changed

client/app/bundles/course/assessment/pages/AssessmentStatistics/AnswerDisplay/LastAttempt.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,16 @@ const LastAttemptIndex: FC<Props> = (props) => {
8484
</Accordion>
8585
<AnswerDetails
8686
answer={answer}
87+
displaySettings={{
88+
showPrivateTestCases: true,
89+
showEvaluationTestCases: true,
90+
showMcqMrqSolution: true,
91+
showRubricBreakdown: true,
92+
showPublicTestCasesOutput: true,
93+
showPrivateTestCasesOutput: true,
94+
showEvaluationTestCasesOutput: true,
95+
showStdoutAndStderr: true,
96+
}}
8797
question={answer.question}
8898
status={HistoryFetchStatus.COMPLETED}
8999
/>

client/app/bundles/course/assessment/submission/components/AllAttempts/AllAttemptsSequenceView.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ import { useAppDispatch, useAppSelector } from 'lib/hooks/store';
1818
import useTranslation from 'lib/hooks/useTranslation';
1919
import { formatLongDateTime } from 'lib/moment';
2020

21+
import { workflowStates } from '../../constants';
2122
import { historyActions } from '../../reducers/history';
23+
import { getAssessment } from '../../selectors/assessments';
2224
import { getSubmissionQuestionHistory } from '../../selectors/history';
25+
import { getSubmission } from '../../selectors/submissions';
2326
import translations from '../../translations';
2427
import AnswerDetails from '../AnswerDetails/AnswerDetails';
2528
import TextResponseSolutions from '../TextResponseSolutions';
@@ -38,6 +41,10 @@ const AllAttemptsSequenceView: FC<Props> = (props) => {
3841
const { answerDataById, allAnswers, selectedAnswerIds, question } =
3942
useAppSelector(getSubmissionQuestionHistory(submissionId, questionId));
4043

44+
const assessment = useAppSelector(getAssessment);
45+
const submission = useAppSelector(getSubmission);
46+
const published = submission.workflowState === workflowStates.Published;
47+
4148
useEffect(() => {
4249
const answerIdsToFetch =
4350
selectedAnswerIds.filter(
@@ -94,6 +101,23 @@ const AllAttemptsSequenceView: FC<Props> = (props) => {
94101
<AnswerDetails
95102
key={answerId}
96103
answer={answerDataById?.[answerId]?.details}
104+
displaySettings={{
105+
showEvaluationTestCases:
106+
graderView || (published && assessment.showEvaluation),
107+
showEvaluationTestCasesOutput: graderView,
108+
showMcqMrqSolution:
109+
graderView || (published && assessment.showMcqMrqSolution),
110+
showPrivateTestCases:
111+
graderView || (published && assessment.showPrivate),
112+
showPrivateTestCasesOutput: graderView,
113+
showPublicTestCasesOutput:
114+
graderView || submission.showPublicTestCasesOutput,
115+
showRubricBreakdown:
116+
graderView ||
117+
(published && assessment.showRubricToStudents),
118+
showStdoutAndStderr:
119+
graderView || submission.showStdoutAndStderr,
120+
}}
97121
question={question!}
98122
status={answerDataById?.[answerId]?.status}
99123
/>

client/app/bundles/course/assessment/submission/components/AllAttempts/AllAttemptsTimelineView.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,31 @@ import CustomSlider from 'lib/components/extensions/CustomSlider';
55
import { useAppDispatch, useAppSelector } from 'lib/hooks/store';
66
import { formatLongDateTime } from 'lib/moment';
77

8+
import { workflowStates } from '../../constants';
9+
import { getAssessment } from '../../selectors/assessments';
810
import { getSubmissionQuestionHistory } from '../../selectors/history';
11+
import { getSubmission } from '../../selectors/submissions';
912
import AnswerDetails from '../AnswerDetails/AnswerDetails';
1013

1114
interface Props {
1215
questionId: number;
1316
submissionId: number;
17+
graderView: boolean;
1418
}
1519

1620
const AllAttemptsTimelineView: FC<Props> = (props) => {
17-
const { submissionId, questionId } = props;
21+
const { submissionId, questionId, graderView } = props;
1822

1923
const dispatch = useAppDispatch();
2024

2125
const { answerDataById, allAnswers, question } = useAppSelector(
2226
getSubmissionQuestionHistory(submissionId, questionId),
2327
);
2428

29+
const assessment = useAppSelector(getAssessment);
30+
const submission = useAppSelector(getSubmission);
31+
const published = submission.workflowState === workflowStates.Published;
32+
2533
// sliderIndex is the uncommited index that is updated on drag
2634
// displayedIndex is updated on drop or with any non-mouse (keyboard) events
2735
// we distinguish these because we don't want to query each answer as user drags the slider
@@ -102,6 +110,21 @@ const AllAttemptsTimelineView: FC<Props> = (props) => {
102110
<div className={sliderIndex === displayedIndex ? '' : 'opacity-60'}>
103111
<AnswerDetails
104112
answer={answerDetails}
113+
displaySettings={{
114+
showEvaluationTestCases:
115+
graderView || (published && assessment.showEvaluation),
116+
showEvaluationTestCasesOutput: graderView,
117+
showMcqMrqSolution:
118+
graderView || (published && assessment.showMcqMrqSolution),
119+
showPrivateTestCases:
120+
graderView || (published && assessment.showPrivate),
121+
showPrivateTestCasesOutput: graderView,
122+
showPublicTestCasesOutput:
123+
graderView || submission.showPublicTestCasesOutput,
124+
showRubricBreakdown:
125+
graderView || (published && assessment.showRubricToStudents),
126+
showStdoutAndStderr: graderView || submission.showStdoutAndStderr,
127+
}}
105128
question={question}
106129
status={answerStatus}
107130
/>

client/app/bundles/course/assessment/submission/components/AllAttempts/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ const AllAttemptsContent: FC<ContentProps> = (props) => {
111111
)}
112112
{viewType === 'timeline' && (
113113
<AllAttemptsTimelineView
114+
graderView={graderView}
114115
questionId={questionId}
115116
submissionId={submissionId}
116117
/>

client/app/bundles/course/assessment/submission/components/AnswerDetails/AnswerDetails.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { formatLongDateTime } from 'lib/moment';
88
import messagesTranslations from 'lib/translations/messages';
99

1010
import { HistoryFetchStatus } from '../../reducers/history';
11-
import { AnswerDetailsProps } from '../../types';
11+
import { AnswerDetailsProps, DisplaySettings } from '../../types';
1212

1313
import FileUploadDetails from './FileUploadDetails';
1414
import ForumPostResponseDetails from './ForumPostResponseDetails';
@@ -100,19 +100,26 @@ const FetchedAnswerDetails = <T extends keyof typeof QuestionType>(
100100

101101
type AnswerDetailsComponentProps<T extends keyof typeof QuestionType> = {
102102
status: HistoryFetchStatus;
103+
displaySettings: DisplaySettings;
103104
} & Partial<AnswerDetailsProps<T>>;
104105

105106
const AnswerDetails = <T extends keyof typeof QuestionType>(
106107
props: AnswerDetailsComponentProps<T>,
107108
): JSX.Element => {
108-
const { answer, question, status } = props;
109+
const { answer, question, status, displaySettings } = props;
109110

110111
const { t } = useTranslation();
111112

112113
const isAnswerRenderable =
113114
answer && question && status === HistoryFetchStatus.COMPLETED;
114115
if (isAnswerRenderable) {
115-
return <FetchedAnswerDetails answer={answer!} question={question!} />;
116+
return (
117+
<FetchedAnswerDetails
118+
answer={answer!}
119+
displaySettings={displaySettings!}
120+
question={question!}
121+
/>
122+
);
116123
}
117124
if (status === HistoryFetchStatus.ERRORED) {
118125
return (

client/app/bundles/course/assessment/submission/components/AnswerDetails/MultipleChoiceDetails.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import { AnswerDetailsProps } from '../../types';
77
const MultipleChoiceDetails = (
88
props: AnswerDetailsProps<QuestionType.MultipleChoice>,
99
): JSX.Element => {
10-
const { question, answer } = props;
10+
const { question, answer, displaySettings } = props;
11+
const { showMcqMrqSolution } = displaySettings;
1112
return (
1213
<>
1314
{question.options.map((option) => (
@@ -25,7 +26,7 @@ const MultipleChoiceDetails = (
2526
<Typography
2627
dangerouslySetInnerHTML={{ __html: option.option.trim() }}
2728
style={
28-
option.correct
29+
showMcqMrqSolution && option.correct
2930
? {
3031
backgroundColor: green[50],
3132
verticalAlign: 'middle',

client/app/bundles/course/assessment/submission/components/AnswerDetails/MultipleResponseDetails.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import { AnswerDetailsProps } from '../../types';
77
const MultipleResponseDetails = (
88
props: AnswerDetailsProps<QuestionType.MultipleResponse>,
99
): JSX.Element => {
10-
const { question, answer } = props;
10+
const { question, answer, displaySettings } = props;
11+
const { showMcqMrqSolution } = displaySettings;
1112
return (
1213
<>
1314
{question.options.map((option) => {
@@ -26,7 +27,7 @@ const MultipleResponseDetails = (
2627
<Typography
2728
dangerouslySetInnerHTML={{ __html: option.option.trim() }}
2829
style={
29-
option.correct
30+
showMcqMrqSolution && option.correct
3031
? {
3132
backgroundColor: green[50],
3233
verticalAlign: 'middle',

client/app/bundles/course/assessment/submission/components/AnswerDetails/ProgrammingAnswerDetails.tsx

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,24 @@ import { useAppDispatch } from 'lib/hooks/store';
66

77
import { AnswerDetailsProps } from '../../types';
88

9-
import CodaveriFeedbackStatus from './ProgrammingComponent/CodaveriFeedbackStatus';
109
import FileContent from './ProgrammingComponent/FileContent';
1110
import TestCases from './ProgrammingComponent/TestCases';
1211

1312
const ProgrammingAnswerDetails = (
1413
props: AnswerDetailsProps<QuestionType.Programming>,
1514
): JSX.Element => {
16-
const { answer } = props;
15+
const { answer, displaySettings } = props;
1716
const annotations = answer.annotations ?? [];
1817

18+
const {
19+
showPrivateTestCases,
20+
showEvaluationTestCases,
21+
showPublicTestCasesOutput,
22+
showPrivateTestCasesOutput,
23+
showEvaluationTestCasesOutput,
24+
showStdoutAndStderr,
25+
} = displaySettings;
26+
1927
const dispatch = useAppDispatch();
2028

2129
useEffect(() => {
@@ -35,8 +43,18 @@ const ProgrammingAnswerDetails = (
3543
file={file}
3644
/>
3745
))}
38-
<TestCases testCase={answer.testCases} />
39-
<CodaveriFeedbackStatus status={answer.codaveriFeedback} />
46+
<TestCases
47+
showEvaluationTestCases={showEvaluationTestCases}
48+
showEvaluationTestCasesOutput={showEvaluationTestCasesOutput}
49+
showPrivateTestCases={showPrivateTestCases}
50+
showPrivateTestCasesOutput={showPrivateTestCasesOutput}
51+
showPublicTestCasesOutput={showPublicTestCasesOutput}
52+
showStdoutAndStderr={showStdoutAndStderr}
53+
testCase={answer.testCases}
54+
/>
55+
{/* might not need this component because unpublished annotations (i.e Codaveri) are not shown in Answer Details */}
56+
{/* students can see this status bar in past attempts view, which is not relevant to them */}
57+
{/* <CodaveriFeedbackStatus status={answer.codaveriFeedback} /> */}
4058
</>
4159
);
4260
};

client/app/bundles/course/assessment/submission/components/AnswerDetails/ProgrammingComponent/TestCaseRow.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import ExpandableCode from 'lib/components/core/ExpandableCode';
77

88
interface Props {
99
result: TestCaseResult;
10+
showTestCaseOutput: boolean;
1011
}
1112

1213
const TestCaseClassName = {
@@ -16,7 +17,7 @@ const TestCaseClassName = {
1617
};
1718

1819
const TestCaseRow: FC<Props> = (props) => {
19-
const { result } = props;
20+
const { result, showTestCaseOutput } = props;
2021

2122
const nameRegex = /\/?(\w+)$/;
2223
const idMatch = result.identifier?.match(nameRegex);
@@ -56,9 +57,11 @@ const TestCaseRow: FC<Props> = (props) => {
5657
<ExpandableCode>{result.expected || ''}</ExpandableCode>
5758
</TableCell>
5859

59-
<TableCell className="w-full pt-1">
60-
<ExpandableCode>{result.output || ''}</ExpandableCode>
61-
</TableCell>
60+
{showTestCaseOutput && (
61+
<TableCell className="w-full pt-1">
62+
<ExpandableCode>{result.output || ''}</ExpandableCode>
63+
</TableCell>
64+
)}
6265

6366
<TableCell>{testCaseIcon}</TableCell>
6467
</TableRow>

0 commit comments

Comments
 (0)