Skip to content

Conversation

@nishasy
Copy link
Contributor

@nishasy nishasy commented Oct 17, 2025

Summary:

(Proof of concept)

Foundation for a new utility that can be called to check a PerseusItem for all save warnings.

The intention is to evetually remove all the ref.getSaveWarnings() everywhere.

Issue: https://khanacademy.atlassian.net/browse/LEMS-3643

Test plan:

pnpm jest packages/perseus/src/util/get-save-warnings-for-item.test.ts

Storybook
/?path=/story/editors-editorpage--with-save-warnings-new-util

Proof it's working

Screen.Recording.2025-10-16.at.6.21.29.PM.mov

@nishasy nishasy self-assigned this Oct 17, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Oct 17, 2025

🗄️ Schema Change: No Changes ✅

@github-actions
Copy link
Contributor

github-actions bot commented Oct 17, 2025

🛠️ Item Splitting: No Changes ✅

@github-actions
Copy link
Contributor

github-actions bot commented Oct 17, 2025

Size Change: +656 B (+0.13%)

Total Size: 498 kB

Filename Size Change
packages/perseus-core/dist/es/index.js 23.1 kB +656 B (+2.93%)
ℹ️ View Unchanged
Filename Size
packages/kas/dist/es/index.js 20.8 kB
packages/keypad-context/dist/es/index.js 1 kB
packages/kmath/dist/es/index.js 5.98 kB
packages/math-input/dist/es/index.js 99.2 kB
packages/math-input/dist/es/strings.js 1.61 kB
packages/perseus-core/dist/es/index.item-splitting.js 13.1 kB
packages/perseus-editor/dist/es/index.js 96.6 kB
packages/perseus-linter/dist/es/index.js 7.21 kB
packages/perseus-score/dist/es/index.js 9.2 kB
packages/perseus-utils/dist/es/index.js 403 B
packages/perseus/dist/es/index.js 204 kB
packages/perseus/dist/es/strings.js 7.71 kB
packages/pure-markdown/dist/es/index.js 1.39 kB
packages/simple-markdown/dist/es/index.js 6.71 kB

compressed-size-action

@github-actions
Copy link
Contributor

github-actions bot commented Oct 17, 2025

npm Snapshot: Published

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

Example:

pnpm add @khanacademy/perseus@PR2969

If you are working in Khan Academy's frontend, you can run the below command.

./dev/tools/bump_perseus_version.ts -t PR2969

If you are working in Khan Academy's webapp, you can run the below command.

./dev/tools/bump_perseus_version.js -t PR2969

@nishasy nishasy marked this pull request as ready for review October 24, 2025 17:32
@nishasy nishasy requested review from a team, anniegallagher and jeremywiebe October 24, 2025 17:32

// Only check widgets that are actually referenced in the content
// (widgets can remain in the widgets object after being deleted from content)
for (const [widgetId, widget] of Object.entries(widgets)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we should use the traverse() helper function to go through an item, because we could have complex widgets (like graded-group) which contain other widgets. I think we want to validate widgets inside those also, right?

See:

export const traverse = function (

// Only check widgets that are actually referenced in the content
// (widgets can remain in the widgets object after being deleted from content)
for (const [widgetId, widget] of Object.entries(widgets)) {
if (!content.includes(widgetId)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

For safety sake, let's use the addWidget() (poorly named as it simply builds a widget placeholder string) when checking if the widget ID is in the content.

export function addWidget(id: string): string {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If my other PR is valid, then I don't think this will be a concern anymore.

#2989

Comment on lines 28 to 29
switch (widget.type) {
case "radio":
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we just create a dictionary of widget type to validator function here? I kinda feel like the pattern we should use is to create a new function on the WidgetLogic type and then look it up the way we do the various options defined there (such as getCurrentVersion() does).

- Radio (already done)
*/

function getSaveWarningsForRadioWidget(widget: RadioWidget): Array<string> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it'd make sense to co-locate this with each widget's logic in perseus-core. What do you think?

React.useEffect(() => {
const warnings = getSaveWarningsForItem({
question: question ?? {content: "", widgets: {}, images: {}},
hints: [...(hints ?? [])],
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we need to spread the result here? If there's a reason, can you adda comment why? Tbh, if I saw this, I'd try to change it to hints: hints ?? [],

Comment on lines 62 to 68
let hasCorrectChoice = false;
for (const choice of widget.options.choices) {
if (choice.correct) {
hasCorrectChoice = true;
break;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

suggestion: You could use a higher-order function from the Array type to shorten this. Whether it's clearer, I'll leave up to you! 😁

Suggested change
let hasCorrectChoice = false;
for (const choice of widget.options.choices) {
if (choice.correct) {
hasCorrectChoice = true;
break;
}
}
const hasCorrectChoice = widget.options.choices.filter(c => c.correct).length > 0;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like I can also use some

@nishasy nishasy requested a review from jeremywiebe October 28, 2025 00:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants