Skip to content

Commit 6fa265d

Browse files
committed
Add paired block functionality to distractors in Parsons exercise
Enhance Parsons exercise functionality with grader and order mode options issue-829 Add Parsons options for adaptive behavior, numbering, and indentation
1 parent 0a84e5b commit 6fa265d

13 files changed

Lines changed: 1231 additions & 265 deletions

File tree

bases/rsptx/assignment_server_api/assignment_builder/src/components/routes/AssignmentBuilder/components/exercises/components/CreateExercise/components/ParsonsExercise/ParsonsExercise.tsx

Lines changed: 79 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ import { validateCommonFields } from "../../utils/validation";
1414

1515
import { ParsonsExerciseSettings } from "./ParsonsExerciseSettings";
1616
import { ParsonsPreview } from "./ParsonsPreview";
17-
import { ParsonsInstructions, ParsonsLanguageSelector, ParsonsBlocksManager } from "./components";
17+
import {
18+
ParsonsInstructions,
19+
ParsonsLanguageSelector,
20+
ParsonsBlocksManager,
21+
ParsonsOptions
22+
} from "./components";
1823

1924
const PARSONS_STEPS = [
2025
{ label: "Language" },
@@ -39,7 +44,13 @@ const getDefaultFormData = (): ParsonsData => ({
3944
question_type: "parsonsprob",
4045
language: "",
4146
instructions: "",
42-
blocks: [{ id: `block-${Date.now()}`, content: "", indent: 0 }]
47+
blocks: [{ id: `block-${Date.now()}`, content: "", indent: 0 }],
48+
adaptive: true,
49+
numbered: "left",
50+
noindent: false,
51+
grader: "line",
52+
orderMode: "random",
53+
customOrder: []
4354
});
4455

4556
const generatePreview = (data: ParsonsData): string => {
@@ -48,10 +59,13 @@ const generatePreview = (data: ParsonsData): string => {
4859
blocks: data.blocks || [],
4960
name: data.name || "parsons_exercise",
5061
language: data.language || "python",
51-
adaptive: true,
52-
numbered: "left",
53-
noindent: false,
54-
questionLabel: data.name
62+
adaptive: data.adaptive ?? true,
63+
numbered: data.numbered ?? "left",
64+
noindent: data.noindent ?? false,
65+
questionLabel: data.name,
66+
grader: data.grader ?? "line",
67+
orderMode: data.orderMode ?? "random",
68+
customOrder: data.customOrder
5569
});
5670
};
5771

@@ -61,10 +75,13 @@ const generateExerciseHtmlSrc = (data: ParsonsData): string => {
6175
instructions: data.instructions || "",
6276
blocks: data.blocks || [],
6377
language: data.language || "python",
64-
adaptive: true,
65-
numbered: "left",
66-
noindent: false,
67-
questionLabel: data.name
78+
adaptive: data.adaptive ?? true,
79+
numbered: data.numbered ?? "left",
80+
noindent: data.noindent ?? false,
81+
questionLabel: data.name,
82+
grader: data.grader ?? "line",
83+
orderMode: data.orderMode ?? "random",
84+
customOrder: data.customOrder
6885
});
6986
};
7087

@@ -144,6 +161,15 @@ export const ParsonsExercise: FC<ExerciseComponentProps> = ({
144161
[updateFormData, formData.language, formData.tags]
145162
);
146163

164+
const handleAddBlock = useCallback(() => {
165+
const newBlock: ParsonsBlock = {
166+
id: `block-${Date.now()}`,
167+
content: "",
168+
indent: 0
169+
};
170+
updateFormData("blocks", [...(formData.blocks || []), newBlock]);
171+
}, [updateFormData, formData.blocks]);
172+
147173
const renderStepContent = () => {
148174
switch (activeStep) {
149175
case 0:
@@ -164,11 +190,43 @@ export const ParsonsExercise: FC<ExerciseComponentProps> = ({
164190

165191
case 2:
166192
return (
167-
<ParsonsBlocksManager
168-
blocks={formData.blocks || []}
169-
onChange={(blocks: ParsonsBlock[]) => updateFormData("blocks", blocks)}
170-
language={formData.language || "python"}
171-
/>
193+
<div className="flex flex-column gap-4">
194+
<ParsonsOptions
195+
adaptive={formData.adaptive ?? true}
196+
numbered={formData.numbered ?? "left"}
197+
noindent={formData.noindent ?? false}
198+
grader={formData.grader ?? "line"}
199+
orderMode={formData.orderMode ?? "random"}
200+
onAdaptiveChange={(value: boolean) => updateFormData("adaptive", value)}
201+
onNumberedChange={(value: "left" | "right" | "none") =>
202+
updateFormData("numbered", value)
203+
}
204+
onNoindentChange={(value: boolean) => updateFormData("noindent", value)}
205+
onGraderChange={(value: "line" | "dag") => {
206+
updateFormData("grader", value);
207+
if (value === "dag") {
208+
updateFormData("adaptive", false);
209+
// Auto-assign tags to blocks that don't have them
210+
const updatedBlocks = (formData.blocks || []).map((block, idx) => {
211+
if (!block.tag && !block.isDistractor && !block.groupId) {
212+
return { ...block, tag: String(idx) };
213+
}
214+
return block;
215+
});
216+
updateFormData("blocks", updatedBlocks);
217+
}
218+
}}
219+
onOrderModeChange={(value: "random" | "custom") => updateFormData("orderMode", value)}
220+
onAddBlock={handleAddBlock}
221+
/>
222+
<ParsonsBlocksManager
223+
blocks={formData.blocks || []}
224+
onChange={(blocks: ParsonsBlock[]) => updateFormData("blocks", blocks)}
225+
language={formData.language || "python"}
226+
grader={formData.grader ?? "line"}
227+
orderMode={formData.orderMode ?? "random"}
228+
/>
229+
</div>
172230
);
173231

174232
case 3:
@@ -181,10 +239,13 @@ export const ParsonsExercise: FC<ExerciseComponentProps> = ({
181239
blocks={formData.blocks || []}
182240
language={formData.language || "python"}
183241
name={formData.name || ""}
184-
adaptive={true}
185-
numbered="left"
186-
noindent={false}
242+
adaptive={formData.adaptive ?? true}
243+
numbered={formData.numbered ?? "left"}
244+
noindent={formData.noindent ?? false}
187245
questionLabel={formData.name}
246+
grader={formData.grader ?? "line"}
247+
orderMode={formData.orderMode ?? "random"}
248+
customOrder={formData.customOrder}
188249
/>
189250
);
190251

bases/rsptx/assignment_server_api/assignment_builder/src/components/routes/AssignmentBuilder/components/exercises/components/CreateExercise/components/ParsonsExercise/ParsonsPreview.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ interface ParsonsPreviewProps {
1212
numbered?: "left" | "right" | "none";
1313
noindent?: boolean;
1414
questionLabel?: string;
15+
grader?: "line" | "dag";
16+
orderMode?: "random" | "custom";
17+
customOrder?: number[];
1518
}
1619

1720
export const ParsonsPreview: FC<ParsonsPreviewProps> = ({
@@ -22,7 +25,10 @@ export const ParsonsPreview: FC<ParsonsPreviewProps> = ({
2225
adaptive = true,
2326
numbered = "left",
2427
noindent = false,
25-
questionLabel
28+
questionLabel,
29+
grader = "line",
30+
orderMode = "random",
31+
customOrder
2632
}) => {
2733
return (
2834
<div style={{ display: "flex", alignItems: "start", justifyContent: "center" }}>
@@ -35,7 +41,10 @@ export const ParsonsPreview: FC<ParsonsPreviewProps> = ({
3541
adaptive,
3642
numbered,
3743
noindent,
38-
questionLabel: questionLabel || name
44+
questionLabel: questionLabel || name,
45+
grader,
46+
orderMode,
47+
customOrder
3948
})}
4049
/>
4150
</div>

0 commit comments

Comments
 (0)