Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/course/configuration/nbgrader.tsx
5965 views
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { Card, InputNumber, Radio } from "antd";
7
8
import { Checkbox } from "@cocalc/frontend/antd-bootstrap";
9
import {
10
CSS,
11
redux,
12
useActions,
13
useRedux,
14
} from "@cocalc/frontend/app-framework";
15
import { A, Icon } from "@cocalc/frontend/components";
16
import { SelectProject } from "@cocalc/frontend/projects/select-project";
17
18
import { CourseActions } from "../actions";
19
import {
20
NBGRADER_CELL_TIMEOUT_MS,
21
NBGRADER_MAX_OUTPUT,
22
NBGRADER_MAX_OUTPUT_PER_CELL,
23
NBGRADER_TIMEOUT_MS,
24
} from "../assignments/consts";
25
26
const radioStyle: CSS = {
27
display: "block",
28
whiteSpace: "normal",
29
fontWeight: "inherit",
30
} as const;
31
32
interface Props {
33
name: string;
34
}
35
36
export function Nbgrader({ name }: Props) {
37
const settings = useRedux([name, "settings"]);
38
const course_project_id = useRedux([name, "course_project_id"]);
39
const actions: CourseActions = useActions({ name });
40
if (actions == null) {
41
throw Error("bug");
42
}
43
44
function render_grade_project(): React.JSX.Element {
45
const location = settings?.get("nbgrader_grade_project")
46
? "project"
47
: "student";
48
return (
49
<div
50
style={{
51
border: "1px solid lightgrey",
52
padding: "10px",
53
borderRadius: "5px",
54
}}
55
>
56
<h6>
57
Where to autograde assignments:{" "}
58
{location == "student"
59
? "in each student's project"
60
: "specific project"}
61
</h6>
62
<Radio.Group
63
onChange={(e) => {
64
if (e.target.value == "student") {
65
actions.configuration.set_nbgrader_grade_project("");
66
} else {
67
actions.configuration.set_nbgrader_grade_project(
68
course_project_id,
69
);
70
}
71
}}
72
value={location}
73
>
74
<Radio value={"student"} key={"student"} style={radioStyle}>
75
Grade assignments in each student's own project
76
</Radio>
77
<Radio value={"project"} key={"project"} style={radioStyle}>
78
Grade assignments in a project of your choice
79
</Radio>
80
</Radio.Group>
81
<br />
82
{location == "project" && (
83
<div>
84
<SelectProject
85
style={{ width: "100%", padding: "5px 25px" }}
86
onChange={actions.configuration.set_nbgrader_grade_project}
87
value={settings?.get("nbgrader_grade_project")}
88
/>
89
{settings?.get("nbgrader_grade_project") &&
90
settings?.get("nbgrader_grade_project") != course_project_id && (
91
<a
92
style={{ marginLeft: "25px" }}
93
onClick={() =>
94
redux.getActions("projects").open_project({
95
project_id: settings?.get("nbgrader_grade_project"),
96
switch_to: true,
97
})
98
}
99
>
100
Open grading project...
101
</a>
102
)}
103
</div>
104
)}
105
<hr />
106
<i>Where to grade:</i> choose the project in which to run autograding.
107
You can create a new project dedicated to running nbgrader, upgrade or
108
license it appropriately, and copy any files to it that student work
109
depends on. This new project will be shared will all collaborators of
110
this instructor project.
111
<br />
112
You can also grade all student work in the student's own project, which
113
is good because the code runs in the same environment as the student
114
work (and won't harm any files you have), but can be slower since each
115
student project has to start running.
116
</div>
117
);
118
}
119
120
function render_include_hidden_tests(): React.JSX.Element {
121
return (
122
<div
123
style={{
124
border: "1px solid lightgrey",
125
padding: "10px",
126
borderRadius: "5px",
127
}}
128
>
129
<h6>
130
nbgrader hidden tests:{" "}
131
{settings?.get("nbgrader_include_hidden_tests")
132
? "Included"
133
: "NOT included"}
134
</h6>
135
<Checkbox
136
checked={settings?.get("nbgrader_include_hidden_tests")}
137
onChange={(e) =>
138
actions.configuration.set_nbgrader_include_hidden_tests(
139
(e.target as any).checked,
140
)
141
}
142
>
143
<i>Include the hidden tests:</i> Select this if you want the notebook
144
to contain why answers failed your hidden tests. The drawback is that
145
if you return assignments to your students, then you will reveal all
146
the hidden tests to the students.
147
</Checkbox>
148
</div>
149
);
150
}
151
152
function render_timeouts(): React.JSX.Element {
153
const timeout = Math.round(
154
settings.get("nbgrader_timeout_ms", NBGRADER_TIMEOUT_MS) / 1000,
155
);
156
const cell_timeout = Math.round(
157
settings.get("nbgrader_cell_timeout_ms", NBGRADER_CELL_TIMEOUT_MS) / 1000,
158
);
159
return (
160
<div
161
style={{
162
border: "1px solid lightgrey",
163
padding: "10px",
164
borderRadius: "5px",
165
}}
166
>
167
<h6>nbgrader timeouts: {timeout} seconds</h6>
168
<i>Grading timeout in seconds:</i> if grading a student notebook takes
169
longer than <i>{timeout} seconds</i>, then it is terminated with a
170
timeout error.
171
<InputNumber
172
onChange={(n) =>
173
actions.configuration.set_nbgrader_timeout_ms(
174
n ? n * 1000 : undefined,
175
)
176
}
177
min={30}
178
max={3600}
179
value={timeout}
180
/>
181
<br />
182
<i>Cell grading timeout in seconds:</i> if grading a cell in a student
183
notebook takes longer than <i>{cell_timeout} seconds</i>, then that cell
184
is terminated with a timeout error.
185
<InputNumber
186
onChange={(n) =>
187
actions.configuration.set_nbgrader_cell_timeout_ms(
188
n ? Math.min(n * 1000, timeout * 1000) : undefined,
189
)
190
}
191
min={5}
192
max={3600}
193
value={cell_timeout}
194
/>
195
</div>
196
);
197
}
198
199
function render_limits(): React.JSX.Element {
200
const max_output = Math.round(
201
settings.get("nbgrader_max_output", NBGRADER_MAX_OUTPUT),
202
);
203
const max_output_per_cell = Math.round(
204
settings.get(
205
"nbgrader_max_output_per_cell",
206
NBGRADER_MAX_OUTPUT_PER_CELL,
207
),
208
);
209
return (
210
<div
211
style={{
212
border: "1px solid lightgrey",
213
padding: "10px",
214
borderRadius: "5px",
215
}}
216
>
217
<h6>nbgrader output limits: {Math.round(max_output / 1000)} KB</h6>
218
<i>Max output:</i> if total output from all cells exceeds{" "}
219
{Math.round(max_output / 1000)} KB, then further output is truncated.
220
<InputNumber
221
onChange={(n) =>
222
actions.configuration.set_nbgrader_max_output(
223
n ? n * 1000 : undefined,
224
)
225
}
226
min={1}
227
max={10000}
228
value={Math.round(max_output / 1000)}
229
/>
230
<br />
231
<i>Max output per cell:</i> if output from a cell exceeds{" "}
232
{Math.round(max_output_per_cell / 1000)} KB, then further output is
233
truncated.
234
<InputNumber
235
onChange={(n) =>
236
actions.configuration.set_nbgrader_max_output_per_cell(
237
n ? n * 1000 : undefined,
238
)
239
}
240
min={1}
241
max={10000}
242
value={Math.round(max_output_per_cell / 1000)}
243
/>
244
</div>
245
);
246
}
247
248
function render_parallel(): React.JSX.Element {
249
const parallel = Math.round(
250
settings.get("nbgrader_parallel") ??
251
actions.get_store().get_nbgrader_parallel(),
252
);
253
return (
254
<div
255
style={{
256
border: "1px solid lightgrey",
257
padding: "10px",
258
borderRadius: "5px",
259
}}
260
>
261
<h6>
262
nbgrader parallel limit:{" "}
263
{parallel > 1
264
? `grade ${parallel} students at once`
265
: "one student a time"}
266
</h6>
267
<i>Max number of students</i> to grade in parallel. What is optimal
268
could depend on where grading is happening (see "Where to autograde
269
assignments" above), and compute resources you or your students have
270
bought.
271
<InputNumber
272
onChange={(n) =>
273
actions.configuration.set_nbgrader_parallel(n ? n : undefined)
274
}
275
min={1}
276
max={50}
277
value={parallel}
278
/>
279
</div>
280
);
281
}
282
283
return (
284
<Card
285
title={
286
<>
287
<Icon name="graduation-cap" /> nbgrader (
288
<A href="https://doc.cocalc.com/teaching-nbgrader.html">Docs</A>)
289
</>
290
}
291
>
292
{render_grade_project()}
293
<br />
294
{render_include_hidden_tests()}
295
<br />
296
{render_timeouts()}
297
<br />
298
{render_limits()}
299
<br />
300
{render_parallel()}
301
</Card>
302
);
303
}
304
305