-
Notifications
You must be signed in to change notification settings - Fork 350
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
Refactor LabelImage to separate out answers from userInput into scoringData #1965
base: main
Are you sure you want to change the base?
Changes from 14 commits
ee7ad47
f36f767
8a3db65
4164ebc
7fc9de8
e694b90
c2d75b2
6ae620f
e6e2d26
95467c8
d6870b8
b0d5329
96af0c4
883f9bc
c6f7d86
1579702
35c610b
b7955c2
7d8b0fe
fb52876
aae57e0
52e7d26
5fe1979
64e7d4b
c83fef5
0dd5f68
b0ccaf3
e5b0d26
78a37df
2925dc8
3569bc0
b7b84ff
a433df6
aa6842e
188b6f5
0dc8936
42a5dc3
9829693
a342a49
415f32a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"@khanacademy/perseus": minor | ||
"@khanacademy/perseus-editor": patch | ||
--- | ||
|
||
Refactor the LabelImage widget to separate out answers from userInput into scoringData |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
// TODO(FEI-4011): Use types generated by https://github.com/jaredly/generate-perseus-flowtypes | ||
|
||
import type {Coord} from "./interactive2/types"; | ||
import type {MarkerAnswers} from "./widgets/label-image/types"; | ||
import type {Interval, vec} from "mafs"; | ||
|
||
// Range is replaced within this file with Interval, but it is used elsewhere | ||
|
@@ -1050,7 +1051,7 @@ export type PerseusLabelImageWidgetOptions = { | |
// The width of the image | ||
imageWidth: number; | ||
// A list of markers to display on the image | ||
markers: ReadonlyArray<PerseusLabelImageMarker>; | ||
markers: ReadonlyArray<MarkerAnswers>; | ||
// Do not display answer choices in instructions | ||
hideChoicesFromInstructions: boolean; | ||
// Allow multiple answers per marker | ||
|
@@ -1059,17 +1060,6 @@ export type PerseusLabelImageWidgetOptions = { | |
static: boolean; | ||
}; | ||
|
||
export type PerseusLabelImageMarker = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm assuming you got rid of this type because it was a duplicate of what's in the widget? Could you instead, make this type the source of truth? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Further, because TypeScript types match if they are the same shape, I was thinking about ScoringData and ValidationData for each widget as a matching subset of the widget options in this file. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean use the types in this file (perseus-types.ts) to define the ScoringData and ValidationData types (in validation.types.ts)? Also, with Matthew's suggestion, I ended up modifying the types in the label-image/types.ts file. I'll review what I did and what was here to see if I can make them work together still. Or maybe I can just leave this file alone 😂 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jeremywiebe is particular when it comes to changing |
||
// A list of correct answers for this marker. Often only one but can have multiple | ||
answers: ReadonlyArray<string>; | ||
// Translatable Text; The text to show for the marker. Not displayed directly to the user | ||
label: string; | ||
// X Coordiate location of the marker on the image | ||
x: number; | ||
// Y Coordinate location of the marker on the image | ||
y: number; | ||
}; | ||
|
||
export type PerseusMatcherWidgetOptions = { | ||
// Translatable Text; Labels to adorn the headings for the columns. Only 2 values [left, right]. e.g. ["Concepts", "Things"] | ||
labels: ReadonlyArray<string>; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,7 +43,10 @@ import type { | |
PerseusRadioChoice, | ||
PerseusGraphCorrectType, | ||
} from "./perseus-types"; | ||
import type {InteractiveMarkerType} from "./widgets/label-image/types"; | ||
import type { | ||
InteractiveMarkerType, | ||
MarkerAnswers, | ||
} from "./widgets/label-image/types"; | ||
import type {Relationship} from "./widgets/number-line/number-line"; | ||
|
||
export type UserInputStatus = "correct" | "incorrect" | "incomplete"; | ||
|
@@ -138,12 +141,12 @@ export type PerseusInteractiveGraphRubric = { | |
|
||
export type PerseusInteractiveGraphUserInput = PerseusGraphType; | ||
|
||
/* TODO(LEMS-2440): Should be removed or refactored. Grading info may need | ||
to be moved to the rubric from userInput. */ | ||
export type PerseusLabelImageRubric = Empty; | ||
export type PerseusLabelImageScoringData = { | ||
markers: ReadonlyArray<MarkerAnswers>; | ||
}; | ||
|
||
export type PerseusLabelImageUserInput = { | ||
markers: ReadonlyArray<InteractiveMarkerType>; | ||
markers: ReadonlyArray<Omit<InteractiveMarkerType, "answers">>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are the main changes. Changed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a little higher-risk, but I think we should make this test case pass: // label-image.test.ts
describe("getUserInput", () => {
it("doesn't include answer in getUserInput", async () => {
// render component
const {renderer} = renderQuestion(textQuestion);
const userInput = renderer.getUserInputMap();
expect(userInput).toEqual({
"label-image 1": {
markers: [
{
label: "The fourth unlabeled bar line.",
x: 25,
y: 17.7,
},
{
label: "The third unlabeled bar line.",
x: 25,
y: 35.3,
},
{
label: "The second unlabeled bar line.",
x: 25,
y: 53,
},
{
label: "The first unlabeled bar line.",
x: 25,
y: 70.3,
},
],
},
});
});
}); I think there should be another set of tests too:
More than anything, I'm just surprised that this ticket ended up being more of a types change whereas I was thinking it would end up being more of a logic change. Not saying you're wrong, it just makes me worried we're missing something. |
||
}; | ||
|
||
export type PerseusMatcherRubric = PerseusMatcherWidgetOptions; | ||
|
@@ -247,7 +250,7 @@ export type Rubric = | |
| PerseusIFrameRubric | ||
| PerseusInputNumberRubric | ||
| PerseusInteractiveGraphRubric | ||
| PerseusLabelImageRubric | ||
| PerseusLabelImageScoringData | ||
| PerseusMatcherRubric | ||
| PerseusMatrixRubric | ||
| PerseusNumberLineScoringData | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,7 +33,7 @@ import type {ChangeableProps} from "../../mixins/changeable"; | |
import type {PerseusLabelImageWidgetOptions} from "../../perseus-types"; | ||
import type {APIOptions, Widget, WidgetExports} from "../../types"; | ||
import type { | ||
PerseusLabelImageRubric, | ||
PerseusLabelImageScoringData, | ||
PerseusLabelImageUserInput, | ||
} from "../../validation.types"; | ||
import type {LabelImagePromptJSON} from "../../widget-ai-utils/label-image/label-image-ai-utils"; | ||
|
@@ -72,8 +72,6 @@ type Point = { | |
|
||
type LabelImageProps = ChangeableProps & | ||
DependencyProps & | ||
// TODO: there's some weirdness in our types between | ||
// PerseusLabelImageMarker and InteractiveMarkerType | ||
Comment on lines
-75
to
-76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was able to resolve this by removing |
||
Omit<PerseusLabelImageWidgetOptions, "markers"> & { | ||
apiOptions: APIOptions; | ||
// The list of label markers on the question image. | ||
|
@@ -194,7 +192,7 @@ export class LabelImage | |
*/ | ||
static navigateToMarkerIndex( | ||
navigateDirection: Direction, | ||
markers: ReadonlyArray<InteractiveMarkerType>, | ||
markers: PerseusLabelImageUserInput["markers"], | ||
thisIndex: number, | ||
): number { | ||
const thisMarker = markers[thisIndex]; | ||
|
@@ -318,8 +316,11 @@ export class LabelImage | |
return _getPromptJSON(this.props, this.getUserInput()); | ||
} | ||
|
||
// TODO(LEMS-2544): Investigate impact on scoring; possibly pull out &/or remove rubric parameter. | ||
showRationalesForCurrentlySelectedChoices(rubric: PerseusLabelImageRubric) { | ||
// TODO(LEMS-2544): Investigate impact on scoring; possibly pull out &/or remove scoringData parameter. | ||
// Also consider how scoreMarker is being called as it seems to require the marker.answers property. | ||
showRationalesForCurrentlySelectedChoices( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bit of a problem as it requires scoringData on the client-side it seems like. Since this has a TODO associated with it, I left it for now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a known issue: https://khanacademy.atlassian.net/browse/LEMS-2544 Luckily AX won't use rationales so we can punt on this for now. |
||
scoringData: PerseusLabelImageScoringData, | ||
) { | ||
const {markers} = this.props; | ||
const {onChange} = this.props; | ||
|
||
|
@@ -342,7 +343,10 @@ export class LabelImage | |
onChange({markers: updatedMarkers}, null, true); | ||
} | ||
|
||
handleMarkerChange(index: number, marker: InteractiveMarkerType) { | ||
handleMarkerChange( | ||
index: number, | ||
marker: PerseusLabelImageUserInput["markers"][number], | ||
) { | ||
const {markers, onChange} = this.props; | ||
|
||
// Replace marker with a changed version at the specified index. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you changed PerseusTypes in a way that's not backwards compatible, I'd call this a major/breaking change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to major. Thanks for pointing this out!