Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LEMS-2851] Answerless NumericInput #2249

Conversation

handeyeco
Copy link
Contributor

@handeyeco handeyeco commented Feb 18, 2025

Summary:

🚨🚨🚨 Will likely be closed in favor of: #2261


NumericInput needed to be adjusted for answerless rendering because it was using answers.answerforms to generate a set of answer forms it could use when generating text for a tooltip that's displayed pre-scoring (see the ticket for more information).

This PR adds PerseusNumericInputWidgetOptions.fullAnswerForms (PerseusNumericInputWidgetOptions.answerForms was already taken although it's deprecated), a new NumericInput widget version, and upgrade functionality to derive fullAnswerForms from answers.answerforms. I am totally willing to rename fullAnswerForms, it's just a placeholder as I work. In case you're confused:

  • PerseusNumericInputWidgetOptions.answerForms: deprecated but might still exist for old data (though I don't think it's used)
  • PerseusNumericInputAnswer.answerForms: current way we derive answerForms data
  • PerseusNumericInputWidgetOptions.fullAnswerForms: what I add in this PR so we can get answerForms without answers

If you're still confused, I'm happy to do a tour.

Issue: LEMS-2851

Test plan:

  • Go to a NumericInput widget that is known to show the tooltip that starts with "Your answer should be..."
  • That tooltip should continue to be visible
  • NumericInput should be renderable, interactive, and answerable.

@handeyeco handeyeco self-assigned this Feb 18, 2025
@handeyeco handeyeco changed the title [LEMS-2851/answerless-numeric-input] add some additional tests for NI transform [LEMS-2851] Answerless NumericInput Feb 18, 2025
Copy link
Contributor

github-actions bot commented Feb 18, 2025

npm Snapshot: Published

Good news!! We've packaged up the latest commit from this PR (d60dfba) and published it to npm. You
can install it using the tag PR2249.

Example:

yarn add @khanacademy/perseus@PR2249

If you are working in Khan Academy's webapp, you can run:

./dev/tools/bump_perseus_version.sh -t PR2249

Copy link
Contributor

github-actions bot commented Feb 18, 2025

Size Change: +471 B (+0.03%)

Total Size: 1.48 MB

Filename Size Change
packages/perseus-core/dist/es/index.js 47.2 kB +811 B (+1.75%)
packages/perseus/dist/es/index.js 377 kB -340 B (-0.09%)
ℹ️ View Unchanged
Filename Size
packages/kas/dist/es/index.js 39 kB
packages/keypad-context/dist/es/index.js 760 B
packages/kmath/dist/es/index.js 86.9 kB
packages/math-input/dist/es/index.js 77.7 kB
packages/math-input/dist/es/strings.js 1.79 kB
packages/perseus-editor/dist/es/index.js 688 kB
packages/perseus-linter/dist/es/index.js 22.2 kB
packages/perseus-score/dist/es/index.js 115 kB
packages/perseus/dist/es/strings.js 6.06 kB
packages/pure-markdown/dist/es/index.js 3.66 kB
packages/simple-markdown/dist/es/index.js 12.5 kB

compressed-size-action

@@ -1205,6 +1205,7 @@ export type PerseusNumericInputWidgetOptions = {
// Used by examples, maybe not used and should be removed in the future
// see TODO in numeric-input
answerForms?: ReadonlyArray<PerseusNumericInputAnswerForm>;
fullAnswerForms?: ReadonlyArray<PerseusNumericInputAnswerForm>;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm expecting that this will change (or something will need to change). Here's what I think happened:

  1. Originally NumericInput used PerseusNumericInputWidgetOptions.answerForms
  2. Then NumericInput was updated to use PerseusNumericInputAnswer.answerForms and PerseusNumericInputWidgetOptions.answerForms was deprecated (see: "maybe not used and should be removed in the future")

Now PerseusNumericInputWidgetOptions.answers is being removed and I think we need something like PerseusNumericInputWidgetOptions.answerForms again but PerseusNumericInputWidgetOptions.answerForms might exist on old data so I called the new thing fullAnswerForms pending more research.

};
}

export const parseNumericInputWidget: Parser<NumericInputWidget> =
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upgrader in Ben's parser


export const currentVersion = {major: 1, minor: 0};

export const widgetOptionsUpgrades = {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upgrader using the widgetOptionsUpgrades API (which will likely be replaced by Ben's parser)

return rendererProps;
return {
...rendererProps,
answerForms: fullAnswerForms,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like I said, we might not keep it named fullAnswerForms so for now I'm just renaming it to answerForms so I don't have to update the widget code which I'd be fine doing once we have an established name.

});
});

it("only uses answer forms from correct answers", () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This got moved to tests for deriveAnswerForms

@@ -42,8 +46,16 @@ export const generateExamples = (
// Generate a list of the unique answer forms.
const uniqueForms = getUniqueAnswerForms(answerForms);

// Sort them by the order they appear in the `formExamples` list.
const formExampleKeys = Object.keys(NumericExampleStrings);
const sortedForms = uniqueForms.sort((a, b) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So originally we were sorting answerForms when deriving the data, but:

  1. I think that's a UI concern, not a data concern
  2. I didn't want to have to move NumericExampleStrings into perseus-core

So I moved the sorting logic and added a test.

* answer forms. This is useful for ensuring that we don't show duplicate examples
* to the user.
*/
const getUniqueAnswerForms = function (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were moved to perseus-core because I needed them for deriving answer forms.

expect(score).toHaveBeenAnsweredCorrectly();
});

it("is interactive with answerless widget options", async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the important test. We:

  • Render the widget with the stripped data
  • Assert that UI that previously required answers still renders
  • Answer and score the widget

}
// Otherwise, add it to the set and return true.
foundForms.add(form.name);
return true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correct to not take simplify into account when de-duplicating answer forms? E.g. if we have

const answerForms = [
  {name: "proper", simplify: "required"},
  {name: "proper", simplify: "optional"},
];

Only {name: "proper", simplify: "required"} will be present in the output. Whether simplify is "required" or "optional" in the output depends on the order in which the answers were originally listed, which is awkward, since I don't think the order is otherwise important.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed there's a very similar function, unionAnswerForms, in numeric-input.tsx. I think yours is better (better-typed, easier to read, possibly faster) but the two functions should probably be combined if they represent the same concept.

// so that we can generate the examples for the widget.
(options.answers || [])
.filter((answer) => answer.status === "correct")
.map((answer) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we used flatMap here I don't think we'd need the call to flat() in unionAnswerForms. unionAnswerForms would then be a trivial wrapper around getUniqueAnswerForms, so it could be removed.

Suggested change
.map((answer) => {
.flatMap((answer) => {


import {parseNumericInputWidget} from "./numeric-input-widget";

describe("parseExpressionWidget", () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy pasta mistake

@handeyeco handeyeco closed this Feb 20, 2025
@handeyeco handeyeco deleted the LEMS-2851/answerless-numeric-input branch February 20, 2025 22:19
handeyeco added a commit that referenced this pull request Feb 24, 2025
## Summary:
Alternative to #2249

Instead of doing a widget upgrade (the old PR), just split `answers` more selectively so that the data we need for rendering pre-scoring is still available.

Issue: LEMS-2851

## Test plan:

- Go to a NumericInput widget that is known to show the tooltip that starts with "Your answer should be..."
- That tooltip should continue to be visible
- NumericInput should be renderable, interactive, and answerable.

Author: handeyeco

Reviewers: benchristel, Myranae, handeyeco, jeremywiebe

Required Reviewers:

Approved By: benchristel

Checks: ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x)

Pull Request URL: #2261
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants