From a494e315d24e47c06f6859a4fc742b56844ebffa Mon Sep 17 00:00:00 2001 From: Alex Mickelson Date: Mon, 6 Jan 2025 15:52:28 -0700 Subject: [PATCH] some papercuts --- .../[moduleName]/quiz/[quizName]/EditQuiz.tsx | 36 ++++++++++--------- .../[courseName]/settings/AllSettings.tsx | 4 ++- .../settings/GithubClassroomList.tsx | 31 ++++++++++++++++ src/hooks/canvas/canvasCourseHooks.ts | 15 ++++---- .../courses/canvasCourseStudentModel.ts | 12 +++++++ src/services/canvas/canvasService.ts | 6 ++-- 6 files changed, 78 insertions(+), 26 deletions(-) create mode 100644 src/app/course/[courseName]/settings/GithubClassroomList.tsx create mode 100644 src/models/canvas/courses/canvasCourseStudentModel.ts diff --git a/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuiz.tsx b/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuiz.tsx index 8b64dd1..6e562f3 100644 --- a/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuiz.tsx +++ b/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuiz.tsx @@ -7,7 +7,6 @@ import { QuizButtons } from "./QuizButton"; import ClientOnly from "@/components/ClientOnly"; import { SuspenseAndErrorHandling } from "@/components/SuspenseAndErrorHandling"; import { useRouter } from "next/navigation"; -import { getModuleItemUrl } from "@/services/urlUtils"; import { useCourseContext } from "@/app/course/[courseName]/context/courseContext"; import { useQuizQuery, @@ -16,8 +15,15 @@ import { import { useAuthoritativeUpdates } from "../../../../utils/useAuthoritativeUpdates"; import { extractLabelValue } from "@/models/local/assignment/utils/markdownUtils"; import EditQuizHeader from "./EditQuizHeader"; +import { LocalCourseSettings } from "@/models/local/localCourseSettings"; +import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks"; -const helpString = `QUESTION REFERENCE +const helpString = (settings: LocalCourseSettings) => { + const groupNames = settings.assignmentGroups.map((g) => g.name).join("\n- "); + return `Assignment Group Names: +- ${groupNames} + +QUESTION REFERENCE --- Points: 2 this is a question? @@ -57,6 +63,7 @@ short answer this is a matching question ^ left answer - right dropdown ^ other thing - another option`; +}; export default function EditQuiz({ moduleName, @@ -66,6 +73,7 @@ export default function EditQuiz({ moduleName: string; }) { const router = useRouter(); + const [settings] = useLocalCourseSettingsQuery(); const { courseName } = useCourseContext(); const [quiz, { dataUpdatedAt: serverDataUpdatedAt, isFetching }] = useQuizQuery(moduleName, quizName); @@ -95,19 +103,15 @@ export default function EditQuiz({ ) ) { if (clientIsAuthoritative) { - const updatedQuiz = quizMarkdownUtils.parseMarkdown( - text, - quizName - ); - await updateQuizMutation - .mutateAsync({ - quiz: updatedQuiz, - moduleName, - quizName: quizName, - previousModuleName: moduleName, - previousQuizName: quizName, - courseName, - }) + const updatedQuiz = quizMarkdownUtils.parseMarkdown(text, quizName); + await updateQuizMutation.mutateAsync({ + quiz: updatedQuiz, + moduleName, + quizName: quizName, + previousModuleName: moduleName, + previousQuizName: quizName, + courseName, + }); } else { console.log( "client not authoritative, updating client with server quiz" @@ -143,7 +147,7 @@ export default function EditQuiz({
{showHelp && (
-            {helpString}
+            {helpString(settings)}
           
)}
diff --git a/src/app/course/[courseName]/settings/AllSettings.tsx b/src/app/course/[courseName]/settings/AllSettings.tsx index c2e3caf..f063c3f 100644 --- a/src/app/course/[courseName]/settings/AllSettings.tsx +++ b/src/app/course/[courseName]/settings/AllSettings.tsx @@ -1,9 +1,10 @@ -"use client" +"use client"; import AssignmentGroupManagement from "./AssignmentGroupManagement"; import DaysOfWeekSettings from "./DaysOfWeekSettings"; import DefaultDueTime from "./DefaultDueTime"; import DefaultFileUploadTypes from "./DefaultFileUploadTypes"; +import GithubClassroomList from "./GithubClassroomList"; import HolidayConfig from "./HolidayConfig"; import SettingsHeader from "./SettingsHeader"; import StartAndEndDate from "./StartAndEndDate"; @@ -15,6 +16,7 @@ export default function AllSettings() { + diff --git a/src/app/course/[courseName]/settings/GithubClassroomList.tsx b/src/app/course/[courseName]/settings/GithubClassroomList.tsx new file mode 100644 index 0000000..86aeec5 --- /dev/null +++ b/src/app/course/[courseName]/settings/GithubClassroomList.tsx @@ -0,0 +1,31 @@ +"use client"; +import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks"; +import { settingsBox } from "./sharedSettings"; +import { useCourseStudentsQuery } from "@/hooks/canvas/canvasCourseHooks"; +import { Spinner } from "@/components/Spinner"; + +export default function GithubClassroomList() { + const [settings] = useLocalCourseSettingsQuery(); + const enrollmentsQuery = useCourseStudentsQuery(settings.canvasId); + + if (enrollmentsQuery.isLoading) + return ( +
+ +
+ ); + return ( +
+
Github Classroom Friendly Roster
+

+ Copy and paste this into github classroom to import students +

+ +
+        
+          {enrollmentsQuery.data?.map((student) => student.email + "\n")}
+        
+      
+
+ ); +} diff --git a/src/hooks/canvas/canvasCourseHooks.ts b/src/hooks/canvas/canvasCourseHooks.ts index 0dc96ca..6e58303 100644 --- a/src/hooks/canvas/canvasCourseHooks.ts +++ b/src/hooks/canvas/canvasCourseHooks.ts @@ -1,16 +1,11 @@ import { CanvasAssignmentGroup } from "@/models/canvas/assignments/canvasAssignmentGroup"; import { CanvasCourseModel } from "@/models/canvas/courses/canvasCourseModel"; import { LocalAssignmentGroup } from "@/models/local/assignment/localAssignmentGroup"; -import { - LocalCourseSettings, - zodLocalCourseSettings, -} from "@/models/local/localCourseSettings"; +import { LocalCourseSettings } from "@/models/local/localCourseSettings"; import { canvasAssignmentGroupService } from "@/services/canvas/canvasAssignmentGroupService"; import { canvasService } from "@/services/canvas/canvasService"; -import { trpc } from "@/services/serverFunctions/trpcClient"; import { useMutation, useQuery } from "@tanstack/react-query"; import { useUpdateLocalCourseSettingsMutation } from "../localCourse/localCoursesHooks"; -import { useCourseContext } from "@/app/course/[courseName]/context/courseContext"; export const canvasCourseKeys = { courseDetails: (canavasId: number) => @@ -19,6 +14,8 @@ export const canvasCourseKeys = { ["canvas", canavasId, "assignment groups"] as const, courseListInTerm: (canvasTermId: number | undefined) => ["canvas courses in term", canvasTermId] as const, + students: (canvasId: number) => + ["students in canvas course", canvasId] as const, }; export const useCourseListInTermQuery = (canvasTermId: number | undefined) => @@ -101,3 +98,9 @@ export const useAssignmentGroupsQuery = (canvasId: number) => { await canvasAssignmentGroupService.getAll(canvasId), }); }; + +export const useCourseStudentsQuery = (canvasId: number) => + useQuery({ + queryKey: canvasCourseKeys.students(canvasId), + queryFn: async () => await canvasService.getEnrolledStudents(canvasId), + }); diff --git a/src/models/canvas/courses/canvasCourseStudentModel.ts b/src/models/canvas/courses/canvasCourseStudentModel.ts new file mode 100644 index 0000000..a93dbe8 --- /dev/null +++ b/src/models/canvas/courses/canvasCourseStudentModel.ts @@ -0,0 +1,12 @@ +export interface CanvasCourseStudentModel { + id: number; + name: string; + created_at: string; // ISO 8601 date string + sortable_name: string; + short_name: string; + sis_user_id: string; + integration_id?: string; + root_account: string; + login_id: string; + email: string; +} \ No newline at end of file diff --git a/src/services/canvas/canvasService.ts b/src/services/canvas/canvasService.ts index 4a19d45..5cbf7fc 100644 --- a/src/services/canvas/canvasService.ts +++ b/src/services/canvas/canvasService.ts @@ -1,8 +1,8 @@ import { CanvasEnrollmentTermModel } from "@/models/canvas/enrollmentTerms/canvasEnrollmentTermModel"; import { canvasApi, paginatedRequest } from "./canvasServiceUtils"; import { CanvasCourseModel } from "@/models/canvas/courses/canvasCourseModel"; -import { CanvasEnrollmentModel } from "@/models/canvas/enrollments/canvasEnrollmentModel"; import { axiosClient } from "../axiosUtils"; +import { CanvasCourseStudentModel } from "@/models/canvas/courses/canvasCourseStudentModel"; const getAllTerms = async () => { const url = `${canvasApi}/accounts/10/terms?per_page=100`; @@ -54,8 +54,8 @@ export const canvasService = { async getEnrolledStudents(canvasCourseId: number) { console.log(`Getting students for course ${canvasCourseId}`); - const url = `${canvasApi}/courses/${canvasCourseId}/enrollments?enrollment_type=student`; - const { data } = await axiosClient.get(url); + const url = `${canvasApi}/courses/${canvasCourseId}/users?enrollment_type=student`; + const data = await paginatedRequest({url}); if (!data) throw new Error(