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

SSS: Hook emptyWidgets() up to validation functions #2000

Merged
merged 7 commits into from
Dec 14, 2024

Conversation

jeremywiebe
Copy link
Collaborator

Summary:

This PR begins connecting the validation functions that have been built to the existing emptyWidgets() function that already exists on the Renderer (as well as emptyWidgesFunctional()). This function powers the APIOptions.answerableCallback which is what the exercise chrome using Perseus uses to detect if a question is at a point where it can be scored.

Note that some widget's "emptiness" checks depend on scoring data and so those checks are not included in the empty checking now.

Issue: LEMS-2561

Test plan:

yarn test
yarn typecheck

@jeremywiebe jeremywiebe self-assigned this Dec 13, 2024
Copy link
Contributor

github-actions bot commented Dec 13, 2024

npm Snapshot: Published

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

Example:

yarn add @khanacademy/perseus@PR2000

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

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

Copy link
Contributor

github-actions bot commented Dec 13, 2024

Size Change: +366 B (+0.03%)

Total Size: 1.27 MB

Filename Size Change
packages/perseus/dist/es/index.js 416 kB +366 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 4.27 kB
packages/math-input/dist/es/index.js 77.9 kB
packages/math-input/dist/es/strings.js 1.79 kB
packages/perseus-core/dist/es/index.js 1.48 kB
packages/perseus-editor/dist/es/index.js 688 kB
packages/perseus-linter/dist/es/index.js 22.2 kB
packages/perseus/dist/es/strings.js 4.12 kB
packages/pure-markdown/dist/es/index.js 3.66 kB
packages/simple-markdown/dist/es/index.js 12.5 kB

compressed-size-action

@@ -15,6 +15,7 @@ import {
definitionItem,
mockedRandomItem,
mockedShuffledRadioProps,
question3,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The changes in this file were needed because:

  • the input-number widget is deprecated
  • the numeric-input widget does not have any validation it can do that does not require scoring data, so it can't be used for empty widget tests.

const widget = upgradedWidgets[id];
if (!widget || widget.static) {
const widget = widgets[id];
if (!widget || widget.static === true) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This use of static here means that both our frontend data and scoring data will need to have the static field kept. Just observing this. I'm working through this in an upcoming type PR

@@ -578,6 +578,13 @@ export type WidgetTransform = (

export type ValidationResult = Extract<PerseusScore, {type: "invalid"}> | null;

export type WidgetValidatorFunction = (
userInput: any, // STOPSHIP
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Future PR

@@ -286,3 +287,60 @@ export type UserInputMap = {[widgetId: string]: UserInput | UserInputMap};
export type UserInputArray = ReadonlyArray<
UserInputArray | UserInput | null | undefined
>;
export interface ValidationDataTypes {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This uses the same construct as the new PerseusWidgetTypes does. However, the fact that not all widgets have validation data concerns me because it means that this interface won't have an entry for all widgets. 🤔 I'm not sure how to tackle that yet.

Copy link
Contributor

Choose a reason for hiding this comment

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

What are the potential issues with the interface not having an entry for all widgets?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Today I'm not totally sure yet. At least, it would give us an inaccurate view of what the different types of validation data we support (we might have a type defined, but not in this "master list"). Ideally in future PRs we can derive some extra checks to ensure these interface type registries stay accurate. 🤞

@@ -328,4 +329,7 @@ export default {
// TODO(LEMS-2656): remove TS suppression
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusCSProgramUserInput'.
scorer: scoreCategorizer,
// TODO(LEMS-2656): remove TS suppression
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusCSProgramUserInput'.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is the same issue as with the scorer entry. Each of our validation functions accepts the specific user input and validation data type for the widget, but our function definition for it on WidgetExports takes a type union of any widget's user input and validation data type.

The solution, I think, is to introduce more generic types on WidgetExports but that gets out of hand quickly each time I try. I'm going to leave this here for now and come back to it after this PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

Might be a fun "wind down" task next week. Might not. idk, I'm fine with error suppression for now.

strings: PerseusStrings,
locale: string,
): ValidationResult {
const emptyWidgets = emptyWidgetsFunctional(
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

A group is basically a Renderer inside a widget, so group validation is just checking if all widgets inside it are valid (ie. non-empty).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Also, the nice thing about how it's implemented is that we don't care what widgets inside are empty, just that any are.

@jeremywiebe jeremywiebe marked this pull request as ready for review December 13, 2024 01:13
@jeremywiebe jeremywiebe requested review from handeyeco, Myranae and a team December 13, 2024 01:14
strings: PerseusStrings,
locale: string,
): ValidationResult {
const emptyWidgets = emptyWidgetsFunctional(
Copy link
Contributor

Choose a reason for hiding this comment

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

This makes me happy that we're able to reuse the functional helpers like this rather than having to access methods on components.

@@ -0,0 +1,5 @@
---
"@khanacademy/perseus": minor
Copy link
Contributor

Choose a reason for hiding this comment

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

Overall, I think this is right. Some of the TS is a little "big-brain" for me to understand and it looks like you might still be tidying up a little bit, but I think it's mostly good to go.

My concern/observation: this does change the behavior of emptyWidgets. Before we only enabled the "Check" button after a deep validation check (including the validation that requires the answers). Now we'll enable the "Check" button after a shallow validation check (only checking if the answer is scorable).

This is inevitable and baked into the project. It just occurs to me that we haven't really shared this with content and support advocates. I think it'll hardly be noticeable, but what do I know.

@@ -159,32 +159,24 @@ export const simpleGroupQuestion: PerseusRenderer = {
"group 1": {
graded: true,
options: {
content: "[[☃ numeric-input 1]]",
content: "[[☃ expression 1]]",
Copy link
Contributor

Choose a reason for hiding this comment

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

It's weird to me that test data for renderer.test.ts is in group.test.ts. Not your fault, maybe even likely that I did that. It's just weird.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The interactive-graph project ended up creating a builder pattern for ig options. That'd be amazing to have for all Perseus widget options. But instead I think we sometimes cheated and used renderer configs from the Renderer tests.

@@ -328,4 +329,7 @@ export default {
// TODO(LEMS-2656): remove TS suppression
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusCSProgramUserInput'.
scorer: scoreCategorizer,
// TODO(LEMS-2656): remove TS suppression
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusCSProgramUserInput'.
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be a fun "wind down" task next week. Might not. idk, I'm fine with error suppression for now.

// "input-number": PerseusInputNumberValidationData;
// interaction: PerseusInteractionValidationData;
// "interactive-graph": PerseusInteractiveGraphValidationData;
// "label-image": PerseusLabelImageValidationData;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm guessing you're going to do something with this commented code right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, just not sure what.

#2000 (comment)

@jeremywiebe jeremywiebe force-pushed the jer/client-validation-2 branch from 7497676 to f4887c9 Compare December 13, 2024 21:09
Copy link
Contributor

@Myranae Myranae left a comment

Choose a reason for hiding this comment

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

Excited to have this set up :) Just added some comments and questions.

},
});
await userEvent.type(screen.getAllByRole("textbox")[0], "150");
act(() => jest.runOnlyPendingTimers());
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: What makes these lines necessary? (there's another one at L1683)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is because we are now using the expression widget. I couldn't figure out why the userEvent.type() call above wasn't working. In other places of Perseus where we test expression we also do this. I think the reason is that it takes a render cycle for the typing to show up in the expression widget. expression is based on MathInput which uses MathQuill under the hood. Probably related to that.

Comment on lines +44 to +48
/**
* Checks the given user input to see if any answerable widgets have not been
* "filled in" (ie. if they're empty). Another way to think about this
* function is that its a check to see if we can score the provided input.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Praise: Thanks for this! 🤩

@@ -286,3 +287,60 @@ export type UserInputMap = {[widgetId: string]: UserInput | UserInputMap};
export type UserInputArray = ReadonlyArray<
UserInputArray | UserInput | null | undefined
>;
export interface ValidationDataTypes {
Copy link
Contributor

Choose a reason for hiding this comment

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

What are the potential issues with the interface not having an entry for all widgets?

@@ -278,11 +280,73 @@ export type UserInput =
| PerseusSorterUserInput
| PerseusTableUserInput;

export type UserInputMap = {[widgetId: string]: UserInput | UserInputMap};
Copy link
Contributor

Choose a reason for hiding this comment

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

Wasn't this here because some of the utility functions were recursive and might have nesting going on? Is that not the case anymore? May not have understood how it was used originally, so just checking :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The only widget that did that was the group. I added a proper type for the group's user input (which is export type PerseusGroupUserInput = UserInputMap;). So it makes this type a bit more accurate and the code that uses the UserInput easier to work with. I have a future PR almost ready where this type will be further improved.

// This is a port of old code, I'm not sure why
// we need widgetIds vs the keys of the widgets object
widgetIds: Array<string>,
userInputMap: UserInputMap,
strings: PerseusStrings,
locale: string,
): ReadonlyArray<string> {
const upgradedWidgets = getUpgradedWidgetOptions(widgets);
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: What makes this line no longer necessary? I looked through the PR, but not sure what's related

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is not needed because this empty widgets call can (should?) only ever be called in a situation where the widget options have already been upgraded. When we are on the client, this data will be widget options from the Renderer which have already been upgraded. When we are scoring on the server, it will be scoring data that is already upgraded. Basically, I don't think this function should be exported outside of Perseus.

Base automatically changed from jer/client-validation-2 to feature/client-validation December 13, 2024 23:03
@jeremywiebe jeremywiebe force-pushed the jer/client-validation-3 branch from 91dd867 to c619dd8 Compare December 13, 2024 23:24
@jeremywiebe jeremywiebe merged commit 0db68d2 into feature/client-validation Dec 14, 2024
8 checks passed
@jeremywiebe jeremywiebe deleted the jer/client-validation-3 branch December 14, 2024 01:40
jeremywiebe added a commit that referenced this pull request Jan 23, 2025
## Summary:
This PR includes the following commits:
- Swap out deprecated input-number with numeric-input in some tests (#1995)
- SSS: Hook emptyWidgets() up to validation functions (#2000)
- Add test to document empty expression can be a correct answer (#2003)
- Remove unused rubric type for CS Program (#1997)
- Remove unused rubric type for iFrame (#1996)
- Refactor LabelImage to separate out answers from userInput into scoringData (#1965)
- Label-image: Extract validation out of scoring (#2016)
- Rename usages of rubric to scoringData (#2006)
- SSS: Improve types for validation (#2002)

## Test plan:
- Confirm all checks pass
- Manual test widgets to confirm they act as expected by creating a webapp testing branch/PR
- Confirm widgets all grade as expected

Author: Myranae

Reviewers: jeremywiebe, handeyeco

Required Reviewers:

Approved By: jeremywiebe

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

Pull Request URL: #2031
catandthemachines added a commit that referenced this pull request Jan 27, 2025
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @khanacademy/[email protected]

### Major Changes

- [#1965](#1965)
[`0f2bec314`](0f2bec3)
Thanks [@Myranae](https://github.com/Myranae)! - Refactor the LabelImage
widget to separate out answers from userInput into scoringData


- [#2134](#2134)
[`117e78d03`](117e78d)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move widget ID
utils to perseus-core


- [#2153](#2153)
[`29a1c656e`](29a1c65)
Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Rename all
instances of the term "ScoringData" back to "Rubric"


- [#2135](#2135)
[`7a984eba6`](7a984eb)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Expression
WidgetOptions logic to core

### Minor Changes

- [#2002](#2002)
[`a1e22a4e3`](a1e22a4)
Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Add and improve
types for scoring and validation


- [#2155](#2155)
[`0df0b1940`](0df0b19)
Thanks [@benchristel](https://github.com/benchristel)! - Move
`parsePerseusItem`, `parseAndMigratePerseusItem`,
    `parseAndMigratePerseusArticle`, `isSuccess`, and `isFailure` to the
`perseus-core` package, and deprecate the equivalent exports from the
`perseus`
    package.


- [#2032](#2032)
[`22d108fdc`](22d108f)
Thanks [@anakaren-rojas](https://github.com/anakaren-rojas)! - adds aria
labels to line segment


- [#2038](#2038)
[`e6f7cc91e`](e6f7cc9)
Thanks [@Myranae](https://github.com/Myranae)! - Fix some naming
discrepancies related to validation and simplify Matcher ScoringData
type


- [#2083](#2083)
[`4c10af109`](4c10af1)
Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Use empty
widgets check in scoring function


- [#2000](#2000)
[`0db68d222`](0db68d2)
Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Change empty
widgets check in Renderer to depend only on data available (and not on
scoring data)


- [#2137](#2137)
[`b4b3a3dbb`](b4b3a3d)
Thanks [@Myranae](https://github.com/Myranae)! - Implement a widget
export function to filter out rubric data from widget options for the
orderer widget


- [#2006](#2006)
[`879d2a501`](879d2a5)
Thanks [@Myranae](https://github.com/Myranae)! - Rename usages of rubric
to scoringData


- [#2139](#2139)
[`32cc4a45b`](32cc4a4)
Thanks [@Myranae](https://github.com/Myranae)! - Implement a widget
export function to filter out rubric data from widget options for the
Expression widget


- [#2016](#2016)
[`55ad836c6`](55ad836)
Thanks [@Myranae](https://github.com/Myranae)! - Introduces a validation
function for the label-image widget (extracted from label-image scoring
function).

### Patch Changes

- [#2142](#2142)
[`d7bcb14c3`](d7bcb14)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Radio upgrade
logic to Perseus Core


- [#2122](#2122)
[`1a75ca628`](1a75ca6)
Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Type and test
fixes for new MockWidget (isolating to be seen only in tests)


- [#2143](#2143)
[`459c25074`](459c250)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Passage
widgets upgrade logic to Perseus Core


- [#1997](#1997)
[`0464a760f`](0464a76)
Thanks [@Myranae](https://github.com/Myranae)! - Remove unused CS
Program rubric type


- [#2110](#2110)
[`e2f2cee9f`](e2f2cee)
Thanks [@nishasy](https://github.com/nishasy)! - [SR] Linear - Add the
interactive elements linear description to the whole graph container


- [#2136](#2136)
[`ffaa3904a`](ffaa390)
Thanks [@nishasy](https://github.com/nishasy)! - [SR] Quadratic - add
screen reader support for Quadratic interactive graph


- [#1996](#1996)
[`b6623bb56`](b6623bb)
Thanks [@Myranae](https://github.com/Myranae)! - Remove unused iframe
rubric type


- [#2124](#2124)
[`bdbdafe5d`](bdbdafe)
Thanks [@dependabot](https://github.com/apps/dependabot)! - Updating
wonder-blocks dependences.


- [#2152](#2152)
[`f8c9d3574`](f8c9d35)
Thanks [@Myranae](https://github.com/Myranae)! - Move the categorizer,
orderer, and expression public widget options functions from perseus
package to their widget folders in perseus-core


- [#1995](#1995)
[`99cd254de`](99cd254)
Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - TESTS: swap
input-number out of renderer tests as it is deprecated


- [#2141](#2141)
[`1355d6cfc`](1355d6c)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Measurer
upgrade logic to Perseus Core

- Updated dependencies
\[[`8f8955718`](8f89557),
[`d7bcb14c3`](d7bcb14),
[`685774f2e`](685774f),
[`8a489600e`](8a48960),
[`1a75ca628`](1a75ca6),
[`459c25074`](459c250),
[`0df0b1940`](0df0b19),
[`dc8118aa1`](dc8118a),
[`82fa90299`](82fa902),
[`b4b3a3dbb`](b4b3a3d),
[`117e78d03`](117e78d),
[`29a1c656e`](29a1c65),
[`7a984eba6`](7a984eb),
[`f8c9d3574`](f8c9d35),
[`1355d6cfc`](1355d6c),
[`75f43a8f4`](75f43a8),
[`32cc4a45b`](32cc4a4),
[`ebf3695b6`](ebf3695)]:
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]

## @khanacademy/[email protected]

### Major Changes

- [#2153](#2153)
[`29a1c656e`](29a1c65)
Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Rename all
instances of the term "ScoringData" back to "Rubric"

### Patch Changes

- Updated dependencies
\[[`8f8955718`](8f89557),
[`d7bcb14c3`](d7bcb14),
[`685774f2e`](685774f),
[`8a489600e`](8a48960),
[`1a75ca628`](1a75ca6),
[`459c25074`](459c250),
[`0df0b1940`](0df0b19),
[`dc8118aa1`](dc8118a),
[`82fa90299`](82fa902),
[`b4b3a3dbb`](b4b3a3d),
[`117e78d03`](117e78d),
[`7a984eba6`](7a984eb),
[`f8c9d3574`](f8c9d35),
[`1355d6cfc`](1355d6c),
[`75f43a8f4`](75f43a8),
[`32cc4a45b`](32cc4a4),
[`ebf3695b6`](ebf3695)]:
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]

## @khanacademy/[email protected]

### Minor Changes

- [#2158](#2158)
[`8f8955718`](8f89557)
Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Re-export
widget id support function: addWidget


- [#2142](#2142)
[`d7bcb14c3`](d7bcb14)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Radio upgrade
logic to Perseus Core


- [#2148](#2148)
[`685774f2e`](685774f)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Matcher
upgrade logic to Perseus Core


- [#2145](#2145)
[`8a489600e`](8a48960)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move simple widget
upgrade logic to Perseus Core (pt 2)


- [#2143](#2143)
[`459c25074`](459c250)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Passage
widgets upgrade logic to Perseus Core


- [#2155](#2155)
[`0df0b1940`](0df0b19)
Thanks [@benchristel](https://github.com/benchristel)! - Move
`parsePerseusItem`, `parseAndMigratePerseusItem`,
    `parseAndMigratePerseusArticle`, `isSuccess`, and `isFailure` to the
`perseus-core` package, and deprecate the equivalent exports from the
`perseus`
    package.


- [#2144](#2144)
[`dc8118aa1`](dc8118a)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move simple widget
upgrade logic to Perseus Core (pt 1)


- [#2150](#2150)
[`82fa90299`](82fa902)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move
InteractiveGraph widget upgrade to Perseus Core


- [#2134](#2134)
[`117e78d03`](117e78d)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move widget ID
utils to perseus-core


- [#2135](#2135)
[`7a984eba6`](7a984eb)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Expression
WidgetOptions logic to core


- [#2141](#2141)
[`1355d6cfc`](1355d6c)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Measurer
upgrade logic to Perseus Core


- [#2149](#2149)
[`75f43a8f4`](75f43a8)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Table upgrade
logic to Perseus Core


- [#2147](#2147)
[`ebf3695b6`](ebf3695)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move upgrade logic
for NumberLine to Perseus Core

### Patch Changes

- [#2122](#2122)
[`1a75ca628`](1a75ca6)
Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Type and test
fixes for new MockWidget (isolating to be seen only in tests)


- [#2137](#2137)
[`b4b3a3dbb`](b4b3a3d)
Thanks [@Myranae](https://github.com/Myranae)! - Move util files out of
widget folder in perseus package to utils folder in perseus-core


- [#2152](#2152)
[`f8c9d3574`](f8c9d35)
Thanks [@Myranae](https://github.com/Myranae)! - Move the categorizer,
orderer, and expression public widget options functions from perseus
package to their widget folders in perseus-core


- [#2139](#2139)
[`32cc4a45b`](32cc4a4)
Thanks [@Myranae](https://github.com/Myranae)! - Move util files out of
widget folder in perseus package to utils folder in perseus-core

## @khanacademy/[email protected]

### Minor Changes

- [#2015](#2015)
[`46623c8f1`](46623c8)
Thanks [@mark-fitzgerald](https://github.com/mark-fitzgerald)! -
[Numeric Input] Re-organize editor and improve its UI


- [#2015](#2015)
[`46623c8f1`](46623c8)
Thanks [@mark-fitzgerald](https://github.com/mark-fitzgerald)! -
[Numeric Input] - Adjust editor to organize settings more logically

### Patch Changes

- [#2142](#2142)
[`d7bcb14c3`](d7bcb14)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Radio upgrade
logic to Perseus Core


- [#2148](#2148)
[`685774f2e`](685774f)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Matcher
upgrade logic to Perseus Core


- [#2145](#2145)
[`8a489600e`](8a48960)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move simple widget
upgrade logic to Perseus Core (pt 2)


- [#2122](#2122)
[`1a75ca628`](1a75ca6)
Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Type and test
fixes for new MockWidget (isolating to be seen only in tests)


- [#2143](#2143)
[`459c25074`](459c250)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Passage
widgets upgrade logic to Perseus Core


- [#2144](#2144)
[`dc8118aa1`](dc8118a)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move simple widget
upgrade logic to Perseus Core (pt 1)


- [#2150](#2150)
[`82fa90299`](82fa902)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move
InteractiveGraph widget upgrade to Perseus Core


- [#1965](#1965)
[`0f2bec314`](0f2bec3)
Thanks [@Myranae](https://github.com/Myranae)! - Refactor the LabelImage
widget to separate out answers from userInput into scoringData


- [#2124](#2124)
[`bdbdafe5d`](bdbdafe)
Thanks [@dependabot](https://github.com/apps/dependabot)! - Updating
wonder-blocks dependences.


- [#2135](#2135)
[`7a984eba6`](7a984eb)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Expression
WidgetOptions logic to core


- [#2141](#2141)
[`1355d6cfc`](1355d6c)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Measurer
upgrade logic to Perseus Core


- [#2149](#2149)
[`75f43a8f4`](75f43a8)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move Table upgrade
logic to Perseus Core


- [#2147](#2147)
[`ebf3695b6`](ebf3695)
Thanks [@handeyeco](https://github.com/handeyeco)! - Move upgrade logic
for NumberLine to Perseus Core

- Updated dependencies
\[[`8f8955718`](8f89557),
[`d7bcb14c3`](d7bcb14),
[`685774f2e`](685774f),
[`8a489600e`](8a48960),
[`1a75ca628`](1a75ca6),
[`459c25074`](459c250),
[`a1e22a4e3`](a1e22a4),
[`0464a760f`](0464a76),
[`0df0b1940`](0df0b19),
[`22d108fdc`](22d108f),
[`dc8118aa1`](dc8118a),
[`82fa90299`](82fa902),
[`e2f2cee9f`](e2f2cee),
[`ffaa3904a`](ffaa390),
[`0f2bec314`](0f2bec3),
[`b4b3a3dbb`](b4b3a3d),
[`e6f7cc91e`](e6f7cc9),
[`4c10af109`](4c10af1),
[`b6623bb56`](b6623bb),
[`0db68d222`](0db68d2),
[`bdbdafe5d`](bdbdafe),
[`117e78d03`](117e78d),
[`b4b3a3dbb`](b4b3a3d),
[`29a1c656e`](29a1c65),
[`7a984eba6`](7a984eb),
[`f8c9d3574`](f8c9d35),
[`879d2a501`](879d2a5),
[`32cc4a45b`](32cc4a4),
[`99cd254de`](99cd254),
[`1355d6cfc`](1355d6c),
[`75f43a8f4`](75f43a8),
[`32cc4a45b`](32cc4a4),
[`55ad836c6`](55ad836),
[`ebf3695b6`](ebf3695)]:
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]

## @khanacademy/[email protected]

### Patch Changes

- Updated dependencies
\[[`8f8955718`](8f89557),
[`d7bcb14c3`](d7bcb14),
[`685774f2e`](685774f),
[`8a489600e`](8a48960),
[`1a75ca628`](1a75ca6),
[`459c25074`](459c250),
[`0df0b1940`](0df0b19),
[`dc8118aa1`](dc8118a),
[`82fa90299`](82fa902),
[`b4b3a3dbb`](b4b3a3d),
[`117e78d03`](117e78d),
[`7a984eba6`](7a984eb),
[`f8c9d3574`](f8c9d35),
[`1355d6cfc`](1355d6c),
[`75f43a8f4`](75f43a8),
[`32cc4a45b`](32cc4a4),
[`ebf3695b6`](ebf3695)]:
    -   @khanacademy/[email protected]

## @khanacademy/[email protected]

### Patch Changes

- Updated dependencies
\[[`8f8955718`](8f89557),
[`d7bcb14c3`](d7bcb14),
[`685774f2e`](685774f),
[`8a489600e`](8a48960),
[`1a75ca628`](1a75ca6),
[`459c25074`](459c250),
[`0df0b1940`](0df0b19),
[`dc8118aa1`](dc8118a),
[`82fa90299`](82fa902),
[`b4b3a3dbb`](b4b3a3d),
[`117e78d03`](117e78d),
[`7a984eba6`](7a984eb),
[`f8c9d3574`](f8c9d35),
[`1355d6cfc`](1355d6c),
[`75f43a8f4`](75f43a8),
[`32cc4a45b`](32cc4a4),
[`ebf3695b6`](ebf3695)]:
    -   @khanacademy/[email protected]

## @khanacademy/[email protected]

### Patch Changes

- Updated dependencies
\[[`8f8955718`](8f89557),
[`d7bcb14c3`](d7bcb14),
[`685774f2e`](685774f),
[`8a489600e`](8a48960),
[`1a75ca628`](1a75ca6),
[`459c25074`](459c250),
[`0df0b1940`](0df0b19),
[`dc8118aa1`](dc8118a),
[`82fa90299`](82fa902),
[`b4b3a3dbb`](b4b3a3d),
[`117e78d03`](117e78d),
[`7a984eba6`](7a984eb),
[`f8c9d3574`](f8c9d35),
[`1355d6cfc`](1355d6c),
[`75f43a8f4`](75f43a8),
[`32cc4a45b`](32cc4a4),
[`ebf3695b6`](ebf3695)]:
    -   @khanacademy/[email protected]

## @khanacademy/[email protected]

### Patch Changes

- Updated dependencies
\[[`8f8955718`](8f89557),
[`d7bcb14c3`](d7bcb14),
[`685774f2e`](685774f),
[`8a489600e`](8a48960),
[`1a75ca628`](1a75ca6),
[`459c25074`](459c250),
[`0df0b1940`](0df0b19),
[`dc8118aa1`](dc8118a),
[`82fa90299`](82fa902),
[`b4b3a3dbb`](b4b3a3d),
[`117e78d03`](117e78d),
[`7a984eba6`](7a984eb),
[`f8c9d3574`](f8c9d35),
[`1355d6cfc`](1355d6c),
[`75f43a8f4`](75f43a8),
[`32cc4a45b`](32cc4a4),
[`ebf3695b6`](ebf3695)]:
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]

## @khanacademy/[email protected]

### Patch Changes

- Updated dependencies
\[[`8f8955718`](8f89557),
[`d7bcb14c3`](d7bcb14),
[`685774f2e`](685774f),
[`8a489600e`](8a48960),
[`1a75ca628`](1a75ca6),
[`459c25074`](459c250),
[`0df0b1940`](0df0b19),
[`dc8118aa1`](dc8118a),
[`82fa90299`](82fa902),
[`b4b3a3dbb`](b4b3a3d),
[`117e78d03`](117e78d),
[`7a984eba6`](7a984eb),
[`f8c9d3574`](f8c9d35),
[`1355d6cfc`](1355d6c),
[`75f43a8f4`](75f43a8),
[`32cc4a45b`](32cc4a4),
[`ebf3695b6`](ebf3695)]:
    -   @khanacademy/[email protected]

## @khanacademy/[email protected]

### Patch Changes

- Updated dependencies
\[[`8f8955718`](8f89557),
[`d7bcb14c3`](d7bcb14),
[`685774f2e`](685774f),
[`8a489600e`](8a48960),
[`1a75ca628`](1a75ca6),
[`459c25074`](459c250),
[`0df0b1940`](0df0b19),
[`dc8118aa1`](dc8118a),
[`82fa90299`](82fa902),
[`b4b3a3dbb`](b4b3a3d),
[`117e78d03`](117e78d),
[`7a984eba6`](7a984eb),
[`f8c9d3574`](f8c9d35),
[`1355d6cfc`](1355d6c),
[`75f43a8f4`](75f43a8),
[`32cc4a45b`](32cc4a4),
[`ebf3695b6`](ebf3695)]:
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]

## @khanacademy/[email protected]

### Patch Changes

- Updated dependencies
\[[`8f8955718`](8f89557),
[`d7bcb14c3`](d7bcb14),
[`685774f2e`](685774f),
[`8a489600e`](8a48960),
[`1a75ca628`](1a75ca6),
[`459c25074`](459c250),
[`0df0b1940`](0df0b19),
[`dc8118aa1`](dc8118a),
[`82fa90299`](82fa902),
[`b4b3a3dbb`](b4b3a3d),
[`117e78d03`](117e78d),
[`7a984eba6`](7a984eb),
[`f8c9d3574`](f8c9d35),
[`1355d6cfc`](1355d6c),
[`75f43a8f4`](75f43a8),
[`32cc4a45b`](32cc4a4),
[`ebf3695b6`](ebf3695)]:
    -   @khanacademy/[email protected]

## @khanacademy/[email protected]

### Patch Changes

- [#2124](#2124)
[`bdbdafe5d`](bdbdafe)
Thanks [@dependabot](https://github.com/apps/dependabot)! - Updating
wonder-blocks dependences.

- Updated dependencies
\[[`8f8955718`](8f89557),
[`d7bcb14c3`](d7bcb14),
[`685774f2e`](685774f),
[`8a489600e`](8a48960),
[`1a75ca628`](1a75ca6),
[`459c25074`](459c250),
[`0df0b1940`](0df0b19),
[`dc8118aa1`](dc8118a),
[`82fa90299`](82fa902),
[`b4b3a3dbb`](b4b3a3d),
[`117e78d03`](117e78d),
[`7a984eba6`](7a984eb),
[`f8c9d3574`](f8c9d35),
[`1355d6cfc`](1355d6c),
[`75f43a8f4`](75f43a8),
[`32cc4a45b`](32cc4a4),
[`ebf3695b6`](ebf3695)]:
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
    -   @khanacademy/[email protected]
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.

3 participants