Skip to content

Commit 3a41ecc

Browse files
committed
feature-872 Add Data Files management to ActiveCode exercises
1 parent f954d92 commit 3a41ecc

File tree

18 files changed

+1479
-41
lines changed

18 files changed

+1479
-41
lines changed

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

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { ExerciseComponentProps } from "@components/routes/AssignmentBuilder/components/exercises/components/CreateExercise/types/ExerciseTypes";
2-
import { FC } from "react";
2+
import { FC, useCallback } from "react";
33

4+
import { useFetchDatafilesQuery } from "@/store/datafile/datafile.logic.api";
5+
import { ExistingDataFile, SelectedDataFile } from "@/types/datafile";
46
import { CreateExerciseFormType } from "@/types/exercises";
57
import { createExerciseId } from "@/utils/exercise";
68
import { generateActiveCodePreview } from "@/utils/preview/activeCode";
@@ -14,6 +16,7 @@ import { validateCommonFields } from "../../utils/validation";
1416

1517
import { ActiveCodeExerciseSettings } from "./ActiveCodeExerciseSettings";
1618
import { ActiveCodePreview } from "./ActiveCodePreview";
19+
import { DataFilesEditor } from "./components/DataFilesEditor";
1720
import { InstructionsEditor } from "./components/InstructionsEditor";
1821
import { LanguageSelector } from "./components/LanguageSelector";
1922
import { PrefixCodeEditor } from "./components/PrefixCodeEditor";
@@ -24,6 +27,7 @@ import { SuffixCodeEditor } from "./components/SuffixCodeEditor";
2427
// Define the steps for ActiveCode exercise
2528
const ACTIVE_CODE_STEPS = [
2629
{ label: "Language" },
30+
{ label: "Data Files" },
2731
{ label: "Instructions" },
2832
{ label: "Hidden Prefix" },
2933
{ label: "Starter Code" },
@@ -51,22 +55,10 @@ const getDefaultFormData = (): Partial<CreateExerciseFormType> => ({
5155
suffix_code: "",
5256
instructions: "",
5357
language: "",
54-
stdin: ""
58+
stdin: "",
59+
selectedExistingDataFiles: []
5560
});
5661

57-
// Create a wrapper for generateActiveCodePreview to match the expected type
58-
const generatePreview = (data: Partial<CreateExerciseFormType>): string => {
59-
return generateActiveCodePreview(
60-
data.instructions || "",
61-
data.language || "python",
62-
data.prefix_code || "",
63-
data.starter_code || "",
64-
data.suffix_code || "",
65-
data.name || "",
66-
data.stdin || ""
67-
);
68-
};
69-
7062
export const ActiveCodeExercise: FC<ExerciseComponentProps> = ({
7163
initialData,
7264
onSave,
@@ -75,6 +67,35 @@ export const ActiveCodeExercise: FC<ExerciseComponentProps> = ({
7567
onFormReset,
7668
isEdit = false
7769
}) => {
70+
const { data: allDatafiles = [] } = useFetchDatafilesQuery();
71+
72+
const generatePreview = useCallback(
73+
(data: Partial<CreateExerciseFormType>): string => {
74+
const selectedFileAcids: SelectedDataFile[] = data.selectedExistingDataFiles || [];
75+
const selectedDatafilesInfo = selectedFileAcids
76+
.map((acid) => {
77+
const existingFile = allDatafiles.find((df: ExistingDataFile) => df.acid === acid);
78+
return {
79+
acid,
80+
filename: existingFile?.filename
81+
};
82+
})
83+
.filter((df) => df.acid);
84+
85+
return generateActiveCodePreview(
86+
data.instructions || "",
87+
data.language || "python",
88+
data.prefix_code || "",
89+
data.starter_code || "",
90+
data.suffix_code || "",
91+
data.name || "",
92+
data.stdin || "",
93+
selectedDatafilesInfo
94+
);
95+
},
96+
[allDatafiles]
97+
);
98+
7899
const {
79100
formData,
80101
activeStep,
@@ -135,15 +156,25 @@ export const ActiveCodeExercise: FC<ExerciseComponentProps> = ({
135156
<LanguageSelector language={formData.language || ""} onChange={handleLanguageChange} />
136157
);
137158

138-
case 1: // Instructions
159+
case 1: // Data Files
160+
return (
161+
<DataFilesEditor
162+
selectedDataFiles={formData.selectedExistingDataFiles || []}
163+
onSelectedDataFilesChange={(files) =>
164+
updateFormData("selectedExistingDataFiles", files)
165+
}
166+
/>
167+
);
168+
169+
case 2: // Instructions
139170
return (
140171
<InstructionsEditor
141172
instructions={formData.instructions || ""}
142173
onChange={(instructions: string) => updateFormData("instructions", instructions)}
143174
/>
144175
);
145176

146-
case 2: // Hidden Prefix Code
177+
case 3: // Hidden Prefix Code
147178
return (
148179
<PrefixCodeEditor
149180
prefixCode={formData.prefix_code || ""}
@@ -152,7 +183,7 @@ export const ActiveCodeExercise: FC<ExerciseComponentProps> = ({
152183
/>
153184
);
154185

155-
case 3: // Starter Code
186+
case 4: // Starter Code
156187
return (
157188
<StarterCodeEditor
158189
starterCode={formData.starter_code || ""}
@@ -161,7 +192,7 @@ export const ActiveCodeExercise: FC<ExerciseComponentProps> = ({
161192
/>
162193
);
163194

164-
case 4: // Hidden Suffix Code
195+
case 5: // Hidden Suffix Code
165196
return (
166197
<SuffixCodeEditor
167198
suffixCode={formData.suffix_code || ""}
@@ -170,18 +201,18 @@ export const ActiveCodeExercise: FC<ExerciseComponentProps> = ({
170201
/>
171202
);
172203

173-
case 5: // Standard Input
204+
case 6: // Standard Input
174205
return (
175206
<StdinEditor
176207
stdin={formData.stdin || ""}
177208
onChange={(stdin: string) => updateFormData("stdin", stdin)}
178209
/>
179210
);
180211

181-
case 6: // Settings
212+
case 7: // Settings
182213
return <ActiveCodeExerciseSettings formData={formData} onChange={handleSettingsChange} />;
183214

184-
case 7: // Preview
215+
case 8: // Preview
185216
return (
186217
<ActiveCodePreview
187218
instructions={formData.instructions || ""}
@@ -191,6 +222,7 @@ export const ActiveCodeExercise: FC<ExerciseComponentProps> = ({
191222
suffix_code={formData.suffix_code || ""}
192223
name={formData.name || ""}
193224
stdin={formData.stdin || ""}
225+
selectedExistingDataFiles={formData.selectedExistingDataFiles || []}
194226
/>
195227
);
196228

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { ExercisePreview } from "@components/routes/AssignmentBuilder/components/exercises/components/ExercisePreview/ExercisePreview";
22
import { FC } from "react";
33

4+
import { useFetchDatafilesQuery } from "@/store/datafile/datafile.logic.api";
5+
import { ExistingDataFile, SelectedDataFile } from "@/types/datafile";
46
import { generateActiveCodePreview } from "@/utils/preview/activeCode";
57

68
interface ActiveCodePreviewProps {
@@ -11,6 +13,7 @@ interface ActiveCodePreviewProps {
1113
suffix_code: string;
1214
name: string;
1315
stdin?: string;
16+
selectedExistingDataFiles?: SelectedDataFile[];
1417
}
1518

1619
export const ActiveCodePreview: FC<ActiveCodePreviewProps> = ({
@@ -20,8 +23,23 @@ export const ActiveCodePreview: FC<ActiveCodePreviewProps> = ({
2023
starter_code,
2124
suffix_code,
2225
name,
23-
stdin
26+
stdin,
27+
selectedExistingDataFiles = []
2428
}) => {
29+
// Fetch datafiles list to get filenames for selected acids
30+
const { data: allDatafiles = [] } = useFetchDatafilesQuery();
31+
32+
// Map selected files with existing file info
33+
const selectedDatafilesInfo = selectedExistingDataFiles
34+
.map((acid) => {
35+
const existingFile = allDatafiles.find((df: ExistingDataFile) => df.acid === acid);
36+
return {
37+
acid,
38+
filename: existingFile?.filename
39+
};
40+
})
41+
.filter((df) => df.acid);
42+
2543
return (
2644
<div style={{ display: "flex", alignItems: "start", justifyContent: "center" }}>
2745
<ExercisePreview
@@ -32,7 +50,8 @@ export const ActiveCodePreview: FC<ActiveCodePreviewProps> = ({
3250
starter_code,
3351
suffix_code,
3452
name,
35-
stdin
53+
stdin,
54+
selectedDatafilesInfo
3655
)}
3756
/>
3857
</div>

0 commit comments

Comments
 (0)