Path: blob/master/src/packages/frontend/course/assignments/assignment-student-list.tsx
1503 views
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { useIntl } from "react-intl";67// CoCalc libraries8import { AppRedux, useMemo, useRedux } from "@cocalc/frontend/app-framework";9import ScrollableList from "@cocalc/frontend/components/scrollable-list";10import { search_match, search_split, trunc_middle } from "@cocalc/util/misc";11import { StudentAssignmentInfo, StudentAssignmentInfoHeader } from "../common";12import type {13AssignmentRecord,14CourseStore,15IsGradingMap,16NBgraderRunInfo,17SortDescription,18} from "../store";19import {20assignment_identifier,21parse_students,22pick_student_sorter,23} from "../util";2425interface StudentListForAssignmentProps {26frame_id?: string;27name: string;28redux: AppRedux;29assignment: AssignmentRecord;30students: any;31user_map: any;32active_feedback_edits: IsGradingMap;33nbgrader_run_info?: NBgraderRunInfo;34search: string;35}3637export function StudentListForAssignment({38frame_id,39name,40redux,41assignment,42students,43user_map,44active_feedback_edits,45nbgrader_run_info,46search,47}: StudentListForAssignmentProps) {48const intl = useIntl();4950const active_student_sort: SortDescription = useRedux(51name,52"active_student_sort",53);54const student_list: string[] = useMemo(() => {55const v0 = parse_students(students, user_map, redux, intl);56const store = get_store();5758// Remove deleted students or students not matching the search59const terms = search_split(search);60const v1: any[] = [];61for (const x of v0) {62if (x.deleted) continue;63if (64terms.length > 0 &&65!search_match(store.get_student_name(x.student_id).toLowerCase(), terms)66) {67continue;68}69v1.push(x);70}7172v1.sort(pick_student_sorter(active_student_sort.toJS()));7374return v1.map((x) => x.student_id);75}, [76students,77user_map,78active_student_sort,79active_feedback_edits,80nbgrader_run_info,81search,82]);8384function get_store(): CourseStore {85return redux.getStore(name) as any;86}8788function is_peer_graded(): boolean {89const peer_info = assignment.get("peer_grade");90return peer_info ? peer_info.get("enabled") : false;91}9293function render_student_info(student_id: string) {94const store = get_store();95const student = store.get_student(student_id);96if (student == null) return; // no such student97const key = assignment_identifier(98assignment.get("assignment_id"),99student_id,100);101const edited_feedback = active_feedback_edits.get(key);102return (103<StudentAssignmentInfo104key={student_id}105title={trunc_middle(store.get_student_name(student_id), 40)}106name={name}107student={student}108assignment={assignment}109grade={store.get_grade(assignment.get("assignment_id"), student_id)}110nbgrader_scores={store.get_nbgrader_scores(111assignment.get("assignment_id"),112student_id,113)}114nbgrader_score_ids={store.get_nbgrader_score_ids(115assignment.get("assignment_id"),116)}117comments={store.get_comments(118assignment.get("assignment_id"),119student_id,120)}121info={store.student_assignment_info(122student_id,123assignment.get("assignment_id"),124)}125is_editing={!!edited_feedback}126nbgrader_run_info={nbgrader_run_info}127/>128);129}130131function render_students() {132return (133<ScrollableList134virtualize135rowCount={student_list.length}136rowRenderer={({ key }) => render_student_info(key)}137rowKey={(index) => student_list[index]}138cacheId={`course-assignment-${assignment.get(139"assignment_id",140)}-${name}-${frame_id}`}141/>142);143}144145return (146<div style={{ height: "70vh", display: "flex", flexDirection: "column" }}>147<StudentAssignmentInfoHeader148key="header"149title="Student"150peer_grade={is_peer_graded()}151/>152{render_students()}153</div>154);155}156157158