Merge pull request #200 from openedx/kenclary/TNL-10332

fix: various style and UX fixes. TNL-10332.
This commit is contained in:
kenclary
2023-01-23 13:01:26 -05:00
committed by GitHub
11 changed files with 139 additions and 40 deletions

View File

@@ -36,7 +36,7 @@ export const messages = {
}, },
noHintSummary: { noHintSummary: {
id: 'authoring.problemeditor.settings.hint.noHintSummary', id: 'authoring.problemeditor.settings.hint.noHintSummary',
defaultMessage: 'No Hints', defaultMessage: 'None',
description: 'Summary text for no hints', description: 'Summary text for no hints',
}, },
hintSummary: { hintSummary: {
@@ -104,10 +104,35 @@ export const messages = {
defaultMessage: 'Points', defaultMessage: 'Points',
description: 'Scoring weight input label', description: 'Scoring weight input label',
}, },
scoringSummary: { unlimitedAttemptsSummary: {
id: 'authoring.problemeditor.settings.scoring.summary', id: 'authoring.problemeditor.settings.scoring.unlimited',
defaultMessage: '{attempts, plural, =0 {Unlimited} other {#}} attempts - {weight, plural, =0 {Ungraded} other {# points}}', defaultMessage: 'Unlimited attempts',
description: 'Summary text for scoring settings', description: 'Summary text for unlimited attempts',
},
attemptsSummary: {
id: 'authoring.problemeditor.settings.scoring.attempts',
defaultMessage: '{attempts, plural, =1 {# attempt} other {# attempts}}',
description: 'Summary text for number of attempts',
},
weightSummary: {
id: 'authoring.problemeditor.settings.scoring.weight',
defaultMessage: '{weight, plural, =0 {Ungraded} other {# points}}',
description: 'Summary text for scoring weight',
},
scoringSettingsLabel: {
id: 'authoring.problemeditor.settings.scoring.label',
defaultMessage: 'Specify point weight and the number of answer attempts',
description: 'Descriptive text for scoring settings',
},
attemptsHint: {
id: 'authoring.problemeditor.settings.scoring.attempts.hint',
defaultMessage: 'If a value is not set, unlimited attempts are allowed',
description: 'Summary text for scoring weight',
},
weightHint: {
id: 'authoring.problemeditor.settings.scoring.weight.hint',
defaultMessage: 'If a value is not set, the problem is worth one point',
description: 'Summary text for scoring weight',
}, },
showAnswerSettingsTitle: { showAnswerSettingsTitle: {
id: 'authoring.problemeditor.settings.showAnswer.title', id: 'authoring.problemeditor.settings.showAnswer.title',

View File

@@ -29,7 +29,7 @@ export const HintsCard = ({
/> />
))} ))}
<Button <Button
className="my-3 ml-2" className="pl-0 text-primary-500"
iconBefore={Add} iconBefore={Add}
variant="tertiary" variant="tertiary"
onClick={handleAdd} onClick={handleAdd}

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Form } from '@edx/paragon'; import { Form } from '@edx/paragon';
import SettingsOption from '../SettingsOption'; import SettingsOption from '../SettingsOption';
import messages from '../messages'; import messages from '../messages';
@@ -14,12 +14,23 @@ export const ScoringCard = ({
}) => { }) => {
const { handleMaxAttemptChange, handleWeightChange } = scoringCardHooks(scoring, updateSettings); const { handleMaxAttemptChange, handleWeightChange } = scoringCardHooks(scoring, updateSettings);
const getScoringSummary = (attempts, unlimited, weight) => {
let summary = unlimited
? intl.formatMessage(messages.unlimitedAttemptsSummary)
: intl.formatMessage(messages.attemptsSummary, { attempts });
summary += ` ${String.fromCharCode(183)} `;
summary += intl.formatMessage(messages.weightSummary, { weight });
return summary;
};
return ( return (
<SettingsOption <SettingsOption
title={intl.formatMessage(messages.scoringSettingsTitle)} title={intl.formatMessage(messages.scoringSettingsTitle)}
summary={intl.formatMessage(messages.scoringSummary, summary={getScoringSummary(scoring.attempts.number, scoring.attempts.unlimited, scoring.weight)}
{ attempts: scoring.attempts.number, weight: scoring.weight })}
> >
<Form.Label className="mb-4">
<FormattedMessage {...messages.scoringSettingsLabel} />
</Form.Label>
<Form.Group> <Form.Group>
<Form.Control <Form.Control
type="number" type="number"
@@ -27,6 +38,9 @@ export const ScoringCard = ({
onChange={handleMaxAttemptChange} onChange={handleMaxAttemptChange}
floatingLabel={intl.formatMessage(messages.scoringAttemptsInputLabel)} floatingLabel={intl.formatMessage(messages.scoringAttemptsInputLabel)}
/> />
<Form.Control.Feedback>
<FormattedMessage {...messages.attemptsHint} />
</Form.Control.Feedback>
</Form.Group> </Form.Group>
<Form.Group> <Form.Group>
<Form.Control <Form.Control
@@ -35,6 +49,9 @@ export const ScoringCard = ({
onChange={handleWeightChange} onChange={handleWeightChange}
floatingLabel={intl.formatMessage(messages.scoringWeightInputLabel)} floatingLabel={intl.formatMessage(messages.scoringWeightInputLabel)}
/> />
<Form.Control.Feedback>
<FormattedMessage {...messages.weightHint} />
</Form.Control.Feedback>
</Form.Group> </Form.Group>
</SettingsOption> </SettingsOption>
); );

View File

@@ -15,7 +15,9 @@ export const TypeCard = ({
// inject // inject
intl, intl,
}) => { }) => {
const problemTypeKeysArray = Object.values(ProblemTypeKeys); const problemTypeKeysArray = Object.values(ProblemTypeKeys).filter(key => key !== ProblemTypeKeys.ADVANCED);
if (problemType === ProblemTypeKeys.ADVANCED) { return null; }
return ( return (
<SettingsOption <SettingsOption

View File

@@ -20,7 +20,7 @@ exports[`HintsCard snapshot snapshot: renders hints setting card multiple hints
value="" value=""
/> />
<Button <Button
className="my-3 ml-2" className="pl-0 text-primary-500"
onClick={[MockFunction hintsCardHooks.handleAdd]} onClick={[MockFunction hintsCardHooks.handleAdd]}
variant="tertiary" variant="tertiary"
> >
@@ -35,11 +35,11 @@ exports[`HintsCard snapshot snapshot: renders hints setting card multiple hints
exports[`HintsCard snapshot snapshot: renders hints setting card no hints 1`] = ` exports[`HintsCard snapshot snapshot: renders hints setting card no hints 1`] = `
<SettingsOption <SettingsOption
summary="No Hints" summary="None"
title="Hints" title="Hints"
> >
<Button <Button
className="my-3 ml-2" className="pl-0 text-primary-500"
onClick={[MockFunction hintsCardHooks.handleAdd]} onClick={[MockFunction hintsCardHooks.handleAdd]}
variant="tertiary" variant="tertiary"
> >
@@ -65,7 +65,7 @@ exports[`HintsCard snapshot snapshot: renders hints setting card one hint 1`] =
value="hint1" value="hint1"
/> />
<Button <Button
className="my-3 ml-2" className="pl-0 text-primary-500"
onClick={[MockFunction hintsCardHooks.handleAdd]} onClick={[MockFunction hintsCardHooks.handleAdd]}
variant="tertiary" variant="tertiary"
> >

View File

@@ -2,9 +2,18 @@
exports[`ScoringCard snapshot snapshot: scoring setting card 1`] = ` exports[`ScoringCard snapshot snapshot: scoring setting card 1`] = `
<SettingsOption <SettingsOption
summary="{attempts, plural, =0 {Unlimited} other {#}} attempts - {weight, plural, =0 {Ungraded} other {# points}}" summary="{attempts, plural, =1 {# attempt} other {# attempts}} · {weight, plural, =0 {Ungraded} other {# points}}"
title="Scoring" title="Scoring"
> >
<Form.Label
className="mb-4"
>
<FormattedMessage
defaultMessage="Specify point weight and the number of answer attempts"
description="Descriptive text for scoring settings"
id="authoring.problemeditor.settings.scoring.label"
/>
</Form.Label>
<Form.Group> <Form.Group>
<Form.Control <Form.Control
floatingLabel="Attempts" floatingLabel="Attempts"
@@ -12,6 +21,13 @@ exports[`ScoringCard snapshot snapshot: scoring setting card 1`] = `
type="number" type="number"
value={5} value={5}
/> />
<Form.Control.Feedback>
<FormattedMessage
defaultMessage="If a value is not set, unlimited attempts are allowed"
description="Summary text for scoring weight"
id="authoring.problemeditor.settings.scoring.attempts.hint"
/>
</Form.Control.Feedback>
</Form.Group> </Form.Group>
<Form.Group> <Form.Group>
<Form.Control <Form.Control
@@ -20,15 +36,31 @@ exports[`ScoringCard snapshot snapshot: scoring setting card 1`] = `
type="number" type="number"
value={1.5} value={1.5}
/> />
<Form.Control.Feedback>
<FormattedMessage
defaultMessage="If a value is not set, the problem is worth one point"
description="Summary text for scoring weight"
id="authoring.problemeditor.settings.scoring.weight.hint"
/>
</Form.Control.Feedback>
</Form.Group> </Form.Group>
</SettingsOption> </SettingsOption>
`; `;
exports[`ScoringCard snapshot snapshot: scoring setting card max attempts 1`] = ` exports[`ScoringCard snapshot snapshot: scoring setting card max attempts 1`] = `
<SettingsOption <SettingsOption
summary="{attempts, plural, =0 {Unlimited} other {#}} attempts - {weight, plural, =0 {Ungraded} other {# points}}" summary="Unlimited attempts · {weight, plural, =0 {Ungraded} other {# points}}"
title="Scoring" title="Scoring"
> >
<Form.Label
className="mb-4"
>
<FormattedMessage
defaultMessage="Specify point weight and the number of answer attempts"
description="Descriptive text for scoring settings"
id="authoring.problemeditor.settings.scoring.label"
/>
</Form.Label>
<Form.Group> <Form.Group>
<Form.Control <Form.Control
floatingLabel="Attempts" floatingLabel="Attempts"
@@ -36,6 +68,13 @@ exports[`ScoringCard snapshot snapshot: scoring setting card max attempts 1`] =
type="number" type="number"
value={0} value={0}
/> />
<Form.Control.Feedback>
<FormattedMessage
defaultMessage="If a value is not set, unlimited attempts are allowed"
description="Summary text for scoring weight"
id="authoring.problemeditor.settings.scoring.attempts.hint"
/>
</Form.Control.Feedback>
</Form.Group> </Form.Group>
<Form.Group> <Form.Group>
<Form.Control <Form.Control
@@ -44,15 +83,31 @@ exports[`ScoringCard snapshot snapshot: scoring setting card max attempts 1`] =
type="number" type="number"
value={1.5} value={1.5}
/> />
<Form.Control.Feedback>
<FormattedMessage
defaultMessage="If a value is not set, the problem is worth one point"
description="Summary text for scoring weight"
id="authoring.problemeditor.settings.scoring.weight.hint"
/>
</Form.Control.Feedback>
</Form.Group> </Form.Group>
</SettingsOption> </SettingsOption>
`; `;
exports[`ScoringCard snapshot snapshot: scoring setting card zero zero weight 1`] = ` exports[`ScoringCard snapshot snapshot: scoring setting card zero zero weight 1`] = `
<SettingsOption <SettingsOption
summary="{attempts, plural, =0 {Unlimited} other {#}} attempts - {weight, plural, =0 {Ungraded} other {# points}}" summary="{attempts, plural, =1 {# attempt} other {# attempts}} · {weight, plural, =0 {Ungraded} other {# points}}"
title="Scoring" title="Scoring"
> >
<Form.Label
className="mb-4"
>
<FormattedMessage
defaultMessage="Specify point weight and the number of answer attempts"
description="Descriptive text for scoring settings"
id="authoring.problemeditor.settings.scoring.label"
/>
</Form.Label>
<Form.Group> <Form.Group>
<Form.Control <Form.Control
floatingLabel="Attempts" floatingLabel="Attempts"
@@ -60,6 +115,13 @@ exports[`ScoringCard snapshot snapshot: scoring setting card zero zero weight 1`
type="number" type="number"
value={5} value={5}
/> />
<Form.Control.Feedback>
<FormattedMessage
defaultMessage="If a value is not set, unlimited attempts are allowed"
description="Summary text for scoring weight"
id="authoring.problemeditor.settings.scoring.attempts.hint"
/>
</Form.Control.Feedback>
</Form.Group> </Form.Group>
<Form.Group> <Form.Group>
<Form.Control <Form.Control
@@ -68,6 +130,13 @@ exports[`ScoringCard snapshot snapshot: scoring setting card zero zero weight 1`
type="number" type="number"
value={0} value={0}
/> />
<Form.Control.Feedback>
<FormattedMessage
defaultMessage="If a value is not set, the problem is worth one point"
description="Summary text for scoring weight"
id="authoring.problemeditor.settings.scoring.weight.hint"
/>
</Form.Control.Feedback>
</Form.Group> </Form.Group>
</SettingsOption> </SettingsOption>
`; `;

View File

@@ -54,22 +54,11 @@ exports[`TypeCard snapshot snapshot: renders type setting card 1`] = `
correctAnswerCount={0} correctAnswerCount={0}
key="stringresponse" key="stringresponse"
label="Text input" label="Text input"
lastRow={false} lastRow={true}
selected={false} selected={false}
typeKey="stringresponse" typeKey="stringresponse"
updateAnswer={[MockFunction args.updateAnswer]} updateAnswer={[MockFunction args.updateAnswer]}
updateField={[MockFunction args.updateField]} updateField={[MockFunction args.updateField]}
/> />
<TypeRow
answers={Array []}
correctAnswerCount={0}
key="advanced"
label="Advanced Problem"
lastRow={true}
selected={true}
typeKey="advanced"
updateAnswer={[MockFunction args.updateAnswer]}
updateField={[MockFunction args.updateField]}
/>
</SettingsOption> </SettingsOption>
`; `;

View File

@@ -16,10 +16,7 @@ export const parseScoringSettings = (metadata) => {
let attempts = popuplateItem({}, 'max_attempts', 'number', metadata); let attempts = popuplateItem({}, 'max_attempts', 'number', metadata);
if (!_.isEmpty(attempts)) { if (!_.isEmpty(attempts)) {
let unlimited = true; const unlimited = _.isNaN(attempts.number);
if (attempts.number > 0) {
unlimited = false;
}
attempts = { ...attempts, unlimited }; attempts = { ...attempts, unlimited };
scoring = { ...scoring, attempts }; scoring = { ...scoring, attempts };
} }

View File

@@ -4,7 +4,7 @@ import {
dropdownWithFeedbackHints, dropdownWithFeedbackHints,
numericWithHints, numericWithHints,
textInputWithHints, textInputWithHints,
sigleSelectWithHints, singleSelectWithHints,
} from './mockData/problemTestData'; } from './mockData/problemTestData';
describe('Test Settings to State Parser', () => { describe('Test Settings to State Parser', () => {
@@ -38,7 +38,7 @@ describe('Test Settings to State Parser', () => {
}); });
test('Test score settings missing', () => { test('Test score settings missing', () => {
const settings = parseSettings(sigleSelectWithHints.metadata); const settings = parseSettings(singleSelectWithHints.metadata);
expect(settings.scoring).toBeUndefined(); expect(settings.scoring).toBeUndefined();
}); });

View File

@@ -217,7 +217,7 @@ export const numericWithHints = {
scoring: { scoring: {
weight: 2.5, weight: 2.5,
attempts: { attempts: {
unlimited: true, unlimited: false,
number: 0, number: 0,
}, },
}, },
@@ -288,7 +288,7 @@ export const textInputWithHints = {
scoring: { scoring: {
weight: 2.5, weight: 2.5,
attempts: { attempts: {
unlimited: true, unlimited: false,
number: 0, number: 0,
}, },
}, },
@@ -315,7 +315,7 @@ not=optional incorrect answer such as a frequent misconception {{You can specify
}, },
}; };
export const sigleSelectWithHints = { export const singleSelectWithHints = {
state: { state: {
rawOLX: '<problem>\n<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for checkboxes with hints and feedback problems. Edit this component to replace this template with your own assessment.</p>\n\n<label>Add the question text, or prompt, here. This text is required.</label>\n<description>You can add an optional tip or note related to the prompt like this.</description>\n<multiplechoiceresponse>\n <choicegroup type="MultipleChoice">\n <choice correct="true">a correct answer <choicehint>selected: You can specify optional feedback that appears after the learner selects and submits this answer. }, { unselected: You can specify optional feedback that appears after the learner clears and submits this answer.</choicehint></choice>\n <choice correct="false">an incorrect answer</choice>\n <choice correct="false">an incorrect answer <choicehint>selected: You can specify optional feedback for none, all, or a subset of the answers. }, { unselected: You can specify optional feedback for selected answers, cleared answers, or both.</choicehint></choice>\n <choice correct="false">an incorrect answer again</choice>\n </choicegroup>\n</multiplechoiceresponse>\n<choiceresponse>\n <checkboxgroup>\n <compoundhint value="A B D">You can specify optional feedback for a combination of answers which appears after the specified set of answers is submitted.</compoundhint>\n <compoundhint value="A B C D">You can specify optional feedback for one, several, or all answer combinations.</compoundhint>\n </checkboxgroup>\n</choiceresponse>\n\n\n<demandhint>\n <hint>You can add an optional hint like this. Problems that have a hint include a hint button, and this text appears the first time learners select the button.</hint>\n <hint>If you add more than one hint, a different hint appears each time learners select the hint button.</hint>\n</demandhint>\n</problem>', rawOLX: '<problem>\n<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for checkboxes with hints and feedback problems. Edit this component to replace this template with your own assessment.</p>\n\n<label>Add the question text, or prompt, here. This text is required.</label>\n<description>You can add an optional tip or note related to the prompt like this.</description>\n<multiplechoiceresponse>\n <choicegroup type="MultipleChoice">\n <choice correct="true">a correct answer <choicehint>selected: You can specify optional feedback that appears after the learner selects and submits this answer. }, { unselected: You can specify optional feedback that appears after the learner clears and submits this answer.</choicehint></choice>\n <choice correct="false">an incorrect answer</choice>\n <choice correct="false">an incorrect answer <choicehint>selected: You can specify optional feedback for none, all, or a subset of the answers. }, { unselected: You can specify optional feedback for selected answers, cleared answers, or both.</choicehint></choice>\n <choice correct="false">an incorrect answer again</choice>\n </choicegroup>\n</multiplechoiceresponse>\n<choiceresponse>\n <checkboxgroup>\n <compoundhint value="A B D">You can specify optional feedback for a combination of answers which appears after the specified set of answers is submitted.</compoundhint>\n <compoundhint value="A B C D">You can specify optional feedback for one, several, or all answer combinations.</compoundhint>\n </checkboxgroup>\n</choiceresponse>\n\n\n<demandhint>\n <hint>You can add an optional hint like this. Problems that have a hint include a hint button, and this text appears the first time learners select the button.</hint>\n <hint>If you add more than one hint, a different hint appears each time learners select the hint button.</hint>\n</demandhint>\n</problem>',
problemType: 'SINGLESELECT', problemType: 'SINGLESELECT',
@@ -362,7 +362,7 @@ export const sigleSelectWithHints = {
weight: 0, weight: 0,
attempts: { attempts: {
unlimited: true, unlimited: true,
number: 0, number: null,
}, },
}, },
timeBetween: 0, timeBetween: 0,

View File

@@ -18,7 +18,7 @@ const initialState = {
weight: 0, weight: 0,
attempts: { attempts: {
unlimited: true, unlimited: true,
number: 0, number: null,
}, },
}, },
hints: [], hints: [],