Skip to content

Commit 0549462

Browse files
committed
feature-1081
1 parent 3a41ecc commit 0549462

6 files changed

Lines changed: 164 additions & 7 deletions

File tree

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@ const getDefaultFormData = (): Partial<CreateExerciseFormType> => ({
5656
instructions: "",
5757
language: "",
5858
stdin: "",
59-
selectedExistingDataFiles: []
59+
selectedExistingDataFiles: [],
60+
// CodeTailor support
61+
enableCodeTailor: false,
62+
parsonspersonalize: "",
63+
parsonsexample: ""
6064
});
6165

6266
export const ActiveCodeExercise: FC<ExerciseComponentProps> = ({
@@ -90,7 +94,12 @@ export const ActiveCodeExercise: FC<ExerciseComponentProps> = ({
9094
data.suffix_code || "",
9195
data.name || "",
9296
data.stdin || "",
93-
selectedDatafilesInfo
97+
selectedDatafilesInfo,
98+
{
99+
enableCodeTailor: data.enableCodeTailor,
100+
parsonspersonalize: data.parsonspersonalize,
101+
parsonsexample: data.parsonsexample
102+
}
94103
);
95104
},
96105
[allDatafiles]

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

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import { Dropdown } from "primereact/dropdown";
2+
import { InputSwitch } from "primereact/inputswitch";
3+
import { InputText } from "primereact/inputtext";
4+
import { Tooltip } from "primereact/tooltip";
15
import { FC } from "react";
26

37
import { CreateExerciseFormType } from "@/types/exercises";
@@ -6,20 +10,99 @@ import {
610
BaseExerciseSettings,
711
BaseExerciseSettingsContent
812
} from "../../shared/BaseExerciseSettingsContent";
13+
import styles from "../../shared/styles/CreateExerciseSettings.module.css";
914

1015
interface ActiveCodeExerciseSettingsProps {
1116
formData: Partial<CreateExerciseFormType>;
1217
onChange: (settings: Partial<CreateExerciseFormType>) => void;
1318
}
1419

20+
const PERSONALIZATION_LEVELS = [
21+
{ label: "Solution", value: "solution-level" },
22+
{ label: "Solution & Block", value: "block-and-solution" }
23+
];
24+
1525
export const ActiveCodeExerciseSettings: FC<ActiveCodeExerciseSettingsProps> = ({
1626
formData,
1727
onChange
1828
}) => {
29+
const handleCodeTailorToggle = (enabled: boolean) => {
30+
onChange({
31+
enableCodeTailor: enabled,
32+
// Reset personalization level when disabling
33+
parsonspersonalize: enabled ? "solution-level" : "",
34+
// Reset parsons example when disabling
35+
parsonsexample: enabled ? formData.parsonsexample : ""
36+
});
37+
};
38+
39+
const handlePersonalizationChange = (value: "solution-level" | "block-and-solution") => {
40+
onChange({ parsonspersonalize: value });
41+
};
42+
43+
const handleParsonsExampleChange = (value: string) => {
44+
onChange({ parsonsexample: value });
45+
};
46+
47+
const codeTailorFields = (
48+
<div className={styles.codeTailorSection}>
49+
<div className={styles.formField}>
50+
<div className="flex align-items-center gap-2">
51+
<InputSwitch
52+
id="enableCodeTailor"
53+
checked={formData.enableCodeTailor ?? false}
54+
onChange={(e) => handleCodeTailorToggle(e.value)}
55+
/>
56+
<label htmlFor="enableCodeTailor" className="font-medium">
57+
Personalized Parsons Support (CodeTailor)
58+
</label>
59+
<i
60+
className="pi pi-info-circle codetailor-info-icon"
61+
data-pr-tooltip="CodeTailor provides personalized Parsons puzzles as adaptive support for students struggling with coding exercises."
62+
data-pr-position="right"
63+
/>
64+
<Tooltip target=".codetailor-info-icon" />
65+
</div>
66+
</div>
67+
68+
{formData.enableCodeTailor && (
69+
<div className={styles.codeTailorOptions}>
70+
<div className={styles.formField}>
71+
<span className="p-float-label">
72+
<Dropdown
73+
id="parsonspersonalize"
74+
value={formData.parsonspersonalize || "solution-level"}
75+
options={PERSONALIZATION_LEVELS}
76+
optionLabel="label"
77+
className="w-full"
78+
onChange={(e) => handlePersonalizationChange(e.value)}
79+
/>
80+
<label htmlFor="parsonspersonalize">Personalization Level</label>
81+
</span>
82+
</div>
83+
84+
<div className={styles.formField}>
85+
<span className="p-float-label">
86+
<InputText
87+
id="parsonsexample"
88+
value={formData.parsonsexample || ""}
89+
className="w-full"
90+
onChange={(e) => handleParsonsExampleChange(e.target.value)}
91+
placeholder="Enter a ParsonProb Question id(optional)"
92+
/>
93+
<label htmlFor="parsonsexample">Backup Example Solution</label>
94+
</span>
95+
</div>
96+
</div>
97+
)}
98+
</div>
99+
);
100+
19101
return (
20102
<BaseExerciseSettingsContent<BaseExerciseSettings>
21103
initialData={formData}
22104
onSettingsChange={onChange}
105+
additionalFields={codeTailorFields}
23106
/>
24107
);
25108
};

bases/rsptx/assignment_server_api/assignment_builder/src/components/routes/AssignmentBuilder/components/exercises/components/CreateExercise/shared/styles/CreateExerciseSettings.module.css

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,3 +242,34 @@
242242
gap: 0.75rem;
243243
}
244244
}
245+
246+
/* CodeTailor Section Styles */
247+
.codeTailorSection {
248+
padding-top: 1.5rem;
249+
border-top: 1px solid #e2e8f0;
250+
}
251+
252+
.codeTailorOptions {
253+
margin-top: 1rem;
254+
padding: 1rem;
255+
padding-top: 1.5rem;
256+
background: #f8fafc;
257+
border-radius: 8px;
258+
border: 1px solid #e2e8f0;
259+
display: grid;
260+
grid-template-columns: 1fr 1fr;
261+
gap: 1.5rem;
262+
}
263+
264+
.fieldHint {
265+
font-size: 0.75rem;
266+
color: #64748b;
267+
margin-top: 0.25rem;
268+
}
269+
270+
@media screen and (max-width: 768px) {
271+
.codeTailorOptions {
272+
grid-template-columns: 1fr;
273+
}
274+
}
275+

bases/rsptx/assignment_server_api/assignment_builder/src/types/exercises.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ export type QuestionJSON = Partial<{
101101
dataLimitBasecourse: boolean;
102102
stdin: string;
103103
selectedExistingDataFiles: SelectedDataFile[];
104+
// CodeTailor support
105+
enableCodeTailor: boolean;
106+
parsonspersonalize: "solution-level" | "block-and-solution" | "";
107+
parsonsexample: string;
104108
}>;
105109

106110
export type CreateExerciseFormType = Omit<Exercise, "question_json"> & QuestionJSON;

bases/rsptx/assignment_server_api/assignment_builder/src/utils/preview/activeCode.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ export interface DataFileInfo {
55
filename?: string;
66
}
77

8+
export interface CodeTailorOptions {
9+
enableCodeTailor?: boolean;
10+
parsonspersonalize?: "solution-level" | "block-and-solution" | "";
11+
parsonsexample?: string;
12+
}
13+
814
export const generateActiveCodePreview = (
915
instructions: string,
1016
language: string,
@@ -13,7 +19,8 @@ export const generateActiveCodePreview = (
1319
suffix_code: string,
1420
name: string,
1521
stdin?: string,
16-
selectedDataFiles?: DataFileInfo[]
22+
selectedDataFiles?: DataFileInfo[],
23+
codeTailorOptions?: CodeTailorOptions
1724
): string => {
1825
const safeId = sanitizeId(name);
1926

@@ -24,6 +31,15 @@ export const generateActiveCodePreview = (
2431
selectedDataFiles && selectedDataFiles.length > 0 ? selectedDataFiles.map((df) => df.acid) : [];
2532
const datafileAttr = filenames.length > 0 ? ` data-datafile="${filenames.join(",")}"` : "";
2633

34+
// CodeTailor attributes
35+
let codeTailorAttrs = "";
36+
if (codeTailorOptions?.enableCodeTailor && codeTailorOptions?.parsonspersonalize) {
37+
codeTailorAttrs += ` data-parsonspersonalize="${codeTailorOptions.parsonspersonalize}"`;
38+
// If parsonsexample is provided, use it; otherwise default to LLM-example
39+
const parsonsExampleValue = codeTailorOptions.parsonsexample?.trim() || "LLM-example";
40+
codeTailorAttrs += ` data-parsonsexample="${parsonsExampleValue}"`;
41+
}
42+
2743
return `
2844
<div class="runestone explainer ac_section ">
2945
<div data-component="activecode" id="${safeId}" data-question_label="${name}">
@@ -36,7 +52,7 @@ export const generateActiveCodePreview = (
3652
data-timelimit=25000 data-codelens="true"
3753
data-audio=''
3854
data-wasm=/_static
39-
${stdinAttr}${datafileAttr}
55+
${stdinAttr}${datafileAttr}${codeTailorAttrs}
4056
style="visibility: hidden;">
4157
${prefix_code}
4258
^^^^

bases/rsptx/assignment_server_api/assignment_builder/src/utils/questionJson.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ export const buildQuestionJson = (data: CreateExerciseFormType) => {
1111
instructions: data.instructions,
1212
language: data.language,
1313
stdin: data.stdin,
14-
selectedExistingDataFiles: data.selectedExistingDataFiles
14+
selectedExistingDataFiles: data.selectedExistingDataFiles,
15+
// CodeTailor support
16+
enableCodeTailor: data.enableCodeTailor,
17+
parsonspersonalize: data.parsonspersonalize,
18+
parsonsexample: data.parsonsexample
1519
}),
1620
...(data.question_type === "shortanswer" && {
1721
attachment: data.attachment,
@@ -82,7 +86,11 @@ export const getDefaultQuestionJson = (languageOptions: TableDropdownOption[]) =
8286
right: [{ id: "x", label: "" }],
8387
correctAnswers: [["a", "x"]],
8488
feedback: "Incorrect. Please try again.",
85-
blocks: [{ id: `block-${Date.now()}`, content: "", indent: 0 }]
89+
blocks: [{ id: `block-${Date.now()}`, content: "", indent: 0 }],
90+
// CodeTailor support
91+
enableCodeTailor: false,
92+
parsonspersonalize: "",
93+
parsonsexample: ""
8694
});
8795

8896
export const mergeQuestionJsonWithDefaults = (
@@ -103,6 +111,12 @@ export const mergeQuestionJsonWithDefaults = (
103111
blocks: questionJson?.blocks ?? defaultQuestionJson.blocks,
104112
language: questionJson?.language ?? defaultQuestionJson.language,
105113
instructions: questionJson?.instructions ?? defaultQuestionJson.instructions,
106-
stdin: questionJson?.stdin ?? defaultQuestionJson.stdin
114+
stdin: questionJson?.stdin ?? defaultQuestionJson.stdin,
115+
// CodeTailor support
116+
enableCodeTailor: questionJson?.enableCodeTailor ?? defaultQuestionJson.enableCodeTailor,
117+
parsonspersonalize:
118+
questionJson?.parsonspersonalize ??
119+
(defaultQuestionJson.parsonspersonalize as "" | "solution-level" | "block-and-solution"),
120+
parsonsexample: questionJson?.parsonsexample ?? defaultQuestionJson.parsonsexample
107121
};
108122
};

0 commit comments

Comments
 (0)