Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/course/configuration/actions-panel.tsx
5984 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 { Button, Card, Col, Row, Space } from "antd";
7
import { FormattedMessage, useIntl } from "react-intl";
8
9
import { useActions, useStore } from "@cocalc/frontend/app-framework";
10
import { Icon, Paragraph } from "@cocalc/frontend/components";
11
import { course } from "@cocalc/frontend/i18n";
12
import type { ProjectMap } from "@cocalc/frontend/todo-types";
13
import { RESEND_INVITE_INTERVAL_DAYS } from "@cocalc/util/consts/invites";
14
import { CourseActions } from "../actions";
15
import { CourseStore } from "../store";
16
import { DeleteAllStudentProjects } from "./delete-all-student-projects";
17
import { DeleteAllStudents } from "./delete-all-students";
18
import EmptyTrash from "./empty-trash";
19
import { StudentProjectsStartStopPanel } from "./start-stop-panel";
20
import { TerminalCommandPanel } from "./terminal-command";
21
22
interface Props {
23
name: string;
24
project_map: ProjectMap;
25
configuring_projects?: boolean;
26
reinviting_students?: boolean;
27
}
28
29
export function ActionsPanel({
30
name,
31
project_map,
32
configuring_projects,
33
reinviting_students,
34
}: Props) {
35
const actions = useActions<CourseActions>({ name });
36
37
return (
38
<div className="smc-vfill" style={{ overflowY: "scroll" }}>
39
<Row>
40
<Col md={12} style={{ padding: "15px 15px 15px 0" }}>
41
<StartAllProjects name={name} project_map={project_map} />
42
<br />
43
<ReconfigureAllProjects
44
configuring_projects={configuring_projects}
45
actions={actions}
46
/>
47
<br />
48
<TerminalCommandPanel name={name} />
49
<br />
50
<ExportGrades actions={actions} />
51
</Col>
52
<Col md={12} style={{ padding: "15px" }}>
53
<ResendInvites
54
actions={actions}
55
reinviting_students={reinviting_students}
56
/>
57
<br />
58
<CopyMissingHandoutsAndAssignments actions={actions} />
59
<br />
60
<EmptyTrash />
61
<br />
62
<DeleteAllStudentProjects actions={actions} />
63
<br />
64
<DeleteAllStudents actions={actions} />
65
</Col>
66
</Row>
67
</div>
68
);
69
}
70
71
export function StartAllProjects({ name, project_map }) {
72
const store = useStore<CourseStore>({ name });
73
const r = store.num_running_projects(project_map);
74
const n = store.num_students();
75
return (
76
<StudentProjectsStartStopPanel
77
name={name}
78
num_running_projects={r}
79
num_students={n}
80
/>
81
);
82
}
83
84
export function ExportGrades({ actions, close }: { actions; close? }) {
85
const intl = useIntl();
86
87
async function save_grades_to_csv() {
88
await actions.export.to_csv();
89
close?.();
90
}
91
92
async function save_grades_to_py() {
93
await actions.export.to_py();
94
close?.();
95
}
96
97
async function save_grades_to_json() {
98
await actions.export.to_json();
99
close?.();
100
}
101
102
return (
103
<Card
104
title={
105
<>
106
<Icon name="table" /> {intl.formatMessage(course.export_grades)}
107
</>
108
}
109
>
110
<Paragraph style={{ marginBottom: "10px" }}>
111
<FormattedMessage
112
id="course.actions-panel.export-grades.title"
113
defaultMessage="Save grades to..."
114
/>
115
</Paragraph>
116
<Space>
117
<Button onClick={save_grades_to_csv}>
118
<Icon name="csv" /> CSV file...
119
</Button>
120
<Button onClick={save_grades_to_json}>
121
<Icon name="file-code" /> JSON file...
122
</Button>
123
<Button onClick={save_grades_to_py}>
124
<Icon name="file-code" /> Python file...
125
</Button>
126
</Space>
127
<hr />
128
<Paragraph type="secondary">
129
<FormattedMessage
130
id="course.actions-panel.export-grades.info"
131
defaultMessage={`Export all the grades you have recorded for students in your course
132
to a CSV or Python file.
133
{br}
134
In Microsoft Excel, you can <A>import the CSV file</A>.`}
135
values={{
136
A: (c) => (
137
<a
138
target="_blank"
139
rel="noopener noreferrer"
140
href="https://support.microsoft.com/en-us/office/import-or-export-text-txt-or-csv-files-5250ac4c-663c-47ce-937b-339e391393ba?ui=en-us&rs=en-us&ad=us"
141
>
142
{c}
143
</a>
144
),
145
br: <br />,
146
}}
147
/>
148
</Paragraph>
149
</Card>
150
);
151
}
152
153
export function ReconfigureAllProjects({
154
actions,
155
configuring_projects,
156
}: {
157
actions;
158
configuring_projects?: boolean;
159
}) {
160
const intl = useIntl();
161
162
return (
163
<Card
164
title={
165
<>
166
<Icon name="envelope" />{" "}
167
{intl.formatMessage(course.reconfigure_all_projects)}
168
</>
169
}
170
>
171
<FormattedMessage
172
id="course.actions-panel.reconfigure-all-projects.info"
173
defaultMessage={`Ensure all projects have the correct students and TA's,
174
titles and descriptions set, etc.
175
This will also resend any outstanding email invitations.`}
176
/>
177
<hr />
178
<Button
179
disabled={configuring_projects}
180
onClick={() => {
181
actions.configuration.configure_all_projects();
182
}}
183
>
184
{configuring_projects ? <Icon name="cocalc-ring" spin /> : undefined}{" "}
185
{intl.formatMessage(course.reconfigure_all_projects)}
186
</Button>
187
</Card>
188
);
189
}
190
191
export function ResendInvites({
192
actions,
193
reinviting_students,
194
}: {
195
actions;
196
reinviting_students?;
197
}) {
198
const intl = useIntl();
199
200
return (
201
<Card
202
title={
203
<>
204
<Icon name="envelope" /> {intl.formatMessage(course.resend_invites)}
205
</>
206
}
207
>
208
<FormattedMessage
209
id="course.actions-panel.resend-invite.info"
210
defaultMessage={`Send another email to every student who didn't sign up yet.
211
This sends a maximum of one email every {days}
212
{days, plural, one {day} other {days}}.`}
213
values={{ days: RESEND_INVITE_INTERVAL_DAYS }}
214
/>
215
<hr />
216
<Button
217
disabled={reinviting_students}
218
onClick={() => {
219
actions.student_projects.reinvite_oustanding_students();
220
}}
221
>
222
{reinviting_students ? <Icon name="cocalc-ring" spin /> : undefined}{" "}
223
<FormattedMessage
224
id="course.actions-panel.resend-invite.button"
225
defaultMessage={"Reinvite students"}
226
description={"Resending email invitiatons to students in a course."}
227
/>
228
</Button>
229
</Card>
230
);
231
}
232
233
export function CopyMissingHandoutsAndAssignments({ actions }) {
234
const intl = useIntl();
235
return (
236
<Card
237
title={
238
<>
239
<Icon name="share-square" />{" "}
240
{intl.formatMessage(course.copy_missing_handouts_assignments)}
241
</>
242
}
243
>
244
<FormattedMessage
245
id="course.actions-panel.copy-missing-handouts-assignments"
246
defaultMessage={`If you <b>add new students</b> to your course,
247
you can click this button to ensure they have all the assignments and handouts
248
that you have already assigned to other students in the course.`}
249
/>
250
<hr />
251
<Button
252
onClick={() => {
253
actions.configuration.push_missing_handouts_and_assignments();
254
}}
255
>
256
<Icon name="share-square" />{" "}
257
{intl.formatMessage(course.copy_missing_handouts_assignments)}
258
</Button>
259
</Card>
260
);
261
}
262
263