Skip to content

Commit 2e836a5

Browse files
irtazaakramfeanil
authored andcommitted
fix: add grading method view
1 parent 292a457 commit 2e836a5

14 files changed

Lines changed: 116 additions & 7 deletions

File tree

.env

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ HOTJAR_VERSION=6
4545
HOTJAR_DEBUG=false
4646
INVITE_STUDENTS_EMAIL_TO=''
4747
ENABLE_CHECKLIST_QUALITY=''
48-
ENABLE_GRADING_METHOD_IN_PROBLEMS=false
4948
# "Multi-level" blocks are unsupported in libraries
5049
LIBRARY_UNSUPPORTED_BLOCKS="conditional,step-builder,problem-builder,library_content,itembank"
5150
# Fallback in local style files

.env.development

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ HOTJAR_VERSION=6
4848
HOTJAR_DEBUG=true
4949
INVITE_STUDENTS_EMAIL_TO="[email protected]"
5050
ENABLE_CHECKLIST_QUALITY=true
51-
ENABLE_GRADING_METHOD_IN_PROBLEMS=false
5251
# "Multi-level" blocks are unsupported in libraries
5352
LIBRARY_UNSUPPORTED_BLOCKS="conditional,step-builder,problem-builder,library_content,itembank"
5453
# Fallback in local style files

.env.test

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ ENABLE_TAGGING_TAXONOMY_PAGES=true
4040
BBB_LEARN_MORE_URL=''
4141
INVITE_STUDENTS_EMAIL_TO="[email protected]"
4242
ENABLE_CHECKLIST_QUALITY=true
43-
ENABLE_GRADING_METHOD_IN_PROBLEMS=false
4443
# "Multi-level" blocks are unsupported in libraries
4544
LIBRARY_UNSUPPORTED_BLOCKS="conditional,step-builder,problem-builder,library_content,itembank"
4645
PARAGON_THEME_URLS=

src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,18 @@ export const scoringCardHooks = (scoring, updateSettings, defaultValue) => {
173173
updateSettings({ scoring: { ...scoring, weight } });
174174
};
175175

176+
const handleGradingMethodChange = (event) => {
177+
const { value } = event.target;
178+
updateSettings({ scoring: { ...scoring, gradingMethod: value } });
179+
};
180+
176181
return {
177182
attemptDisplayValue,
178183
handleUnlimitedChange,
179184
handleMaxAttemptChange,
180185
handleOnChange,
181186
handleWeightChange,
187+
handleGradingMethodChange,
182188
};
183189
};
184190

src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ describe('Problem settings hooks', () => {
147147
unlimited: false,
148148
number: 5,
149149
},
150+
gradingMethod: 'last_score',
150151
};
151152
const defaultValue = 1;
152153
test('test scoringCardHooks initializes display value when attempts.number is null', () => {
@@ -269,6 +270,11 @@ describe('Problem settings hooks', () => {
269270
output.handleWeightChange({ target: { value } });
270271
expect(updateSettings).toHaveBeenCalledWith({ scoring: { ...scoring, weight: parseFloat(value) } });
271272
});
273+
test('test handleGradingMethodChange', () => {
274+
const value = 'first_score';
275+
output.handleGradingMethodChange({ target: { value } });
276+
expect(updateSettings).toHaveBeenCalledWith({ scoring: { ...scoring, gradingMethod: value } });
277+
});
272278
});
273279

274280
describe('Show answer card hooks', () => {

src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ SettingsWidget.propTypes = {
203203
showanswer: PropTypes.string,
204204
showResetButton: PropTypes.bool,
205205
rerandomize: PropTypes.string,
206+
gradingMethod: PropTypes.string,
206207
}).isRequired,
207208
images: PropTypes.shape({}).isRequired,
208209
isLibrary: PropTypes.bool.isRequired,

src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ describe('SettingsWidget', () => {
3333
maxAttempts: 2,
3434
showanswer: 'finished',
3535
showResetButton: false,
36+
gradingMethod: 'last_score',
3637
},
3738
images: {},
3839
isLibrary: false,

src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/messages.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ const messages = defineMessages({
8282
defaultMessage: 'Points',
8383
description: 'Scoring weight input label',
8484
},
85+
scoringGradingMethodInputLabel: {
86+
id: 'authoring.problemeditor.settings.scoring.grading.method.inputLabel',
87+
defaultMessage: 'Grading Method',
88+
description: 'Grading method input label',
89+
},
90+
gradingMethodSummary: {
91+
id: 'authoring.problemeditor.settings.scoring.grading.method',
92+
defaultMessage: '{gradingMethod}',
93+
description: 'Summary text for scoring grading method',
94+
},
8595
unlimitedAttemptsSummary: {
8696
id: 'authoring.problemeditor.settings.scoring.unlimited',
8797
defaultMessage: 'Unlimited attempts',
@@ -107,6 +117,11 @@ const messages = defineMessages({
107117
defaultMessage: 'Specify point weight and the number of answer attempts',
108118
description: 'Descriptive text for scoring settings',
109119
},
120+
scoringSettingsLabelWithGradingMethod: {
121+
id: 'authoring.problemeditor.settings.scoring.label.withGradingMethod',
122+
defaultMessage: 'Specify grading method, point weight and the number of answer attempts',
123+
description: 'Descriptive text for scoring settings when grading method is enabled',
124+
},
110125
attemptsHint: {
111126
id: 'authoring.problemeditor.settings.scoring.attempts.hint',
112127
defaultMessage: 'If a default value is not set in advanced settings, unlimited attempts are allowed',
@@ -117,6 +132,11 @@ const messages = defineMessages({
117132
defaultMessage: 'If a value is not set, the problem is worth one point',
118133
description: 'Summary text for scoring weight',
119134
},
135+
gradingMethodHint: {
136+
id: 'authoring.problemeditor.settings.scoring.grading.method.hint',
137+
defaultMessage: 'Define the grading method for this problem. By default, it is the score of the last submission made by the student.',
138+
description: 'Summary text for scoring grading method',
139+
},
120140
showAnswerSettingsTitle: {
121141
id: 'authoring.problemeditor.settings.showAnswer.title',
122142
defaultMessage: 'Show answer',

src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ScoringCard.jsx

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { selectors } from '../../../../../../data/redux';
88
import SettingsOption from '../SettingsOption';
99
import messages from '../messages';
1010
import { scoringCardHooks } from '../hooks';
11+
import { GradingMethod, GradingMethodKeys } from '../../../../../../data/constants/problem';
1112

1213
const ScoringCard = ({
1314
scoring,
@@ -23,28 +24,62 @@ const ScoringCard = ({
2324
handleUnlimitedChange,
2425
handleMaxAttemptChange,
2526
handleWeightChange,
27+
handleGradingMethodChange,
2628
handleOnChange,
2729
attemptDisplayValue,
2830
} = scoringCardHooks(scoring, updateSettings, defaultValue);
2931

30-
const getScoringSummary = (weight, attempts, unlimited) => {
32+
const getScoringSummary = (weight, attempts, unlimited, gradingMethod) => {
3133
let summary = intl.formatMessage(messages.weightSummary, { weight });
3234
summary += ` ${String.fromCharCode(183)} `;
3335
summary += unlimited
3436
? intl.formatMessage(messages.unlimitedAttemptsSummary)
3537
: intl.formatMessage(messages.attemptsSummary, { attempts: attempts || defaultValue });
38+
39+
const methodMessage = gradingMethod ? GradingMethod[gradingMethod] : null;
40+
41+
if (methodMessage) {
42+
summary += ` ${String.fromCharCode(183)} `;
43+
summary += intl.formatMessage(messages.gradingMethodSummary, {
44+
gradingMethod: intl.formatMessage(methodMessage),
45+
});
46+
}
47+
3648
return summary;
3749
};
3850

3951
return (
4052
<SettingsOption
4153
title={intl.formatMessage(messages.scoringSettingsTitle)}
42-
summary={getScoringSummary(scoring.weight, scoring.attempts.number, scoring.attempts.unlimited)}
54+
summary={getScoringSummary(scoring.weight, scoring.attempts.number, scoring.attempts.unlimited, scoring.gradingMethod)}
4355
className="scoringCard"
4456
>
4557
<div className="mb-4">
46-
<FormattedMessage {...messages.scoringSettingsLabel} />
58+
<FormattedMessage {...messages.scoringSettingsLabelWithGradingMethod} />
4759
</div>
60+
<Form.Group>
61+
<Form.Control
62+
as="select"
63+
value={scoring.gradingMethod}
64+
onChange={handleGradingMethodChange}
65+
floatingLabel={intl.formatMessage(messages.scoringGradingMethodInputLabel)}
66+
>
67+
{Object.values(GradingMethodKeys).map((gradingMethod) => {
68+
const optionDisplayName = GradingMethod[gradingMethod];
69+
return (
70+
<option
71+
key={gradingMethod}
72+
value={gradingMethod}
73+
>
74+
{intl.formatMessage(optionDisplayName)}
75+
</option>
76+
);
77+
})}
78+
</Form.Control>
79+
<Form.Control.Feedback>
80+
<FormattedMessage {...messages.gradingMethodHint} />
81+
</Form.Control.Feedback>
82+
</Form.Group>
4883
<Form.Group>
4984
<Form.Control
5085
type="number"

src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ScoringCard.test.jsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
} from '@src/testUtils';
55
import ScoringCard from './ScoringCard';
66
import { selectors } from '../../../../../../data/redux';
7+
import { GradingMethodKeys } from '../../../../../../data/constants/problem';
78

89
const { app } = selectors;
910

@@ -14,6 +15,7 @@ describe('ScoringCard', () => {
1415
unlimited: false,
1516
number: 5,
1617
},
18+
gradingMethod: GradingMethodKeys.LAST_SCORE,
1719
updateSettings: jest.fn().mockName('args.updateSettings'),
1820
};
1921

@@ -59,6 +61,17 @@ describe('ScoringCard', () => {
5961
expect(props.updateSettings).toHaveBeenCalled();
6062
});
6163

64+
test('should call updateSettings when changing grading method', () => {
65+
render(<ScoringCard {...props} />);
66+
fireEvent.click(screen.getByText('Scoring'));
67+
const gradingSelect = screen.getByRole('combobox', { name: 'Grading method' });
68+
expect(gradingSelect).toBeInTheDocument();
69+
expect(gradingSelect.value).toBe(GradingMethodKeys.LAST_SCORE);
70+
71+
fireEvent.change(gradingSelect, { target: { value: GradingMethodKeys.HIGHEST_SCORE } });
72+
expect(props.updateSettings).toHaveBeenCalled();
73+
});
74+
6275
test('should call updateSettings when clicking attempts button', () => {
6376
const scoringUnlimited = { ...scoring, attempts: { unlimited: true, number: 0 } };
6477
render(<ScoringCard {...props} scoring={scoringUnlimited} />);

0 commit comments

Comments
 (0)