Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/course/assignments/assignment-student-list.tsx
5961 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 { useIntl } from "react-intl";
7
8
// CoCalc libraries
9
import { AppRedux, useMemo, useRedux } from "@cocalc/frontend/app-framework";
10
import ScrollableList from "@cocalc/frontend/components/scrollable-list";
11
import { search_match, search_split, trunc_middle } from "@cocalc/util/misc";
12
import { StudentAssignmentInfo } from "../common";
13
import type {
14
AssignmentRecord,
15
CourseStore,
16
IsGradingMap,
17
NBgraderRunInfo,
18
SortDescription,
19
} from "../store";
20
import {
21
assignment_identifier,
22
parse_students,
23
pick_student_sorter,
24
} from "../util";
25
26
interface StudentListForAssignmentProps {
27
frame_id?: string;
28
name: string;
29
redux: AppRedux;
30
assignment: AssignmentRecord;
31
students: any;
32
user_map: any;
33
active_feedback_edits: IsGradingMap;
34
nbgrader_run_info?: NBgraderRunInfo;
35
search: string;
36
}
37
38
export function StudentListForAssignment({
39
frame_id,
40
name,
41
redux,
42
assignment,
43
students,
44
user_map,
45
active_feedback_edits,
46
nbgrader_run_info,
47
search,
48
}: StudentListForAssignmentProps) {
49
const intl = useIntl();
50
51
const active_student_sort: SortDescription = useRedux(
52
name,
53
"active_student_sort",
54
);
55
const student_list: string[] = useMemo(() => {
56
const v0 = parse_students(students, user_map, redux, intl);
57
const store = get_store();
58
59
// Remove deleted students or students not matching the search
60
const terms = search_split(search);
61
const v1: any[] = [];
62
for (const x of v0) {
63
if (x.deleted) continue;
64
if (
65
terms.length > 0 &&
66
!search_match(store.get_student_name(x.student_id).toLowerCase(), terms)
67
) {
68
continue;
69
}
70
v1.push(x);
71
}
72
73
v1.sort(pick_student_sorter(active_student_sort.toJS()));
74
75
return v1.map((x) => x.student_id);
76
}, [
77
students,
78
user_map,
79
active_student_sort,
80
active_feedback_edits,
81
nbgrader_run_info,
82
search,
83
]);
84
85
function get_store(): CourseStore {
86
return redux.getStore(name) as any;
87
}
88
89
function render_student_info(student_id: string) {
90
const store = get_store();
91
const student = store.get_student(student_id);
92
if (student == null) return; // no such student
93
const key = assignment_identifier(
94
assignment.get("assignment_id"),
95
student_id,
96
);
97
const edited_feedback = active_feedback_edits.get(key);
98
return (
99
<StudentAssignmentInfo
100
key={student_id}
101
title={trunc_middle(store.get_student_name(student_id), 40)}
102
name={name}
103
student={student}
104
assignment={assignment}
105
grade={store.get_grade(assignment.get("assignment_id"), student_id)}
106
nbgrader_scores={store.get_nbgrader_scores(
107
assignment.get("assignment_id"),
108
student_id,
109
)}
110
nbgrader_score_ids={store.get_nbgrader_score_ids(
111
assignment.get("assignment_id"),
112
)}
113
comments={store.get_comments(
114
assignment.get("assignment_id"),
115
student_id,
116
)}
117
info={store.student_assignment_info(
118
student_id,
119
assignment.get("assignment_id"),
120
)}
121
is_editing={!!edited_feedback}
122
nbgrader_run_info={nbgrader_run_info}
123
/>
124
);
125
}
126
127
function render_students() {
128
return (
129
<ScrollableList
130
virtualize
131
rowCount={student_list.length}
132
rowRenderer={({ key }) => render_student_info(key)}
133
rowKey={(index) => student_list[index]}
134
cacheId={`course-assignment-${assignment.get(
135
"assignment_id",
136
)}-${name}-${frame_id}`}
137
/>
138
);
139
}
140
141
return (
142
<div style={{ height: "70vh", display: "flex", flexDirection: "column" }}>
143
{render_students()}
144
</div>
145
);
146
}
147
148