some papercuts

This commit is contained in:
2025-01-06 15:52:28 -07:00
parent ad4b059a17
commit a494e315d2
6 changed files with 78 additions and 26 deletions

View File

@@ -7,7 +7,6 @@ import { QuizButtons } from "./QuizButton";
import ClientOnly from "@/components/ClientOnly"; import ClientOnly from "@/components/ClientOnly";
import { SuspenseAndErrorHandling } from "@/components/SuspenseAndErrorHandling"; import { SuspenseAndErrorHandling } from "@/components/SuspenseAndErrorHandling";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { getModuleItemUrl } from "@/services/urlUtils";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext"; import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
import { import {
useQuizQuery, useQuizQuery,
@@ -16,8 +15,15 @@ import {
import { useAuthoritativeUpdates } from "../../../../utils/useAuthoritativeUpdates"; import { useAuthoritativeUpdates } from "../../../../utils/useAuthoritativeUpdates";
import { extractLabelValue } from "@/models/local/assignment/utils/markdownUtils"; import { extractLabelValue } from "@/models/local/assignment/utils/markdownUtils";
import EditQuizHeader from "./EditQuizHeader"; 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 Points: 2
this is a question? this is a question?
@@ -57,6 +63,7 @@ short answer
this is a matching question this is a matching question
^ left answer - right dropdown ^ left answer - right dropdown
^ other thing - another option`; ^ other thing - another option`;
};
export default function EditQuiz({ export default function EditQuiz({
moduleName, moduleName,
@@ -66,6 +73,7 @@ export default function EditQuiz({
moduleName: string; moduleName: string;
}) { }) {
const router = useRouter(); const router = useRouter();
const [settings] = useLocalCourseSettingsQuery();
const { courseName } = useCourseContext(); const { courseName } = useCourseContext();
const [quiz, { dataUpdatedAt: serverDataUpdatedAt, isFetching }] = const [quiz, { dataUpdatedAt: serverDataUpdatedAt, isFetching }] =
useQuizQuery(moduleName, quizName); useQuizQuery(moduleName, quizName);
@@ -95,19 +103,15 @@ export default function EditQuiz({
) )
) { ) {
if (clientIsAuthoritative) { if (clientIsAuthoritative) {
const updatedQuiz = quizMarkdownUtils.parseMarkdown( const updatedQuiz = quizMarkdownUtils.parseMarkdown(text, quizName);
text, await updateQuizMutation.mutateAsync({
quizName
);
await updateQuizMutation
.mutateAsync({
quiz: updatedQuiz, quiz: updatedQuiz,
moduleName, moduleName,
quizName: quizName, quizName: quizName,
previousModuleName: moduleName, previousModuleName: moduleName,
previousQuizName: quizName, previousQuizName: quizName,
courseName, courseName,
}) });
} else { } else {
console.log( console.log(
"client not authoritative, updating client with server quiz" "client not authoritative, updating client with server quiz"
@@ -143,7 +147,7 @@ export default function EditQuiz({
<div className={"min-h-96 h-full flex flex-row w-full"}> <div className={"min-h-96 h-full flex flex-row w-full"}>
{showHelp && ( {showHelp && (
<pre className=" max-w-96"> <pre className=" max-w-96">
<code>{helpString}</code> <code>{helpString(settings)}</code>
</pre> </pre>
)} )}
<div className="flex-1 h-full"> <div className="flex-1 h-full">

View File

@@ -1,9 +1,10 @@
"use client" "use client";
import AssignmentGroupManagement from "./AssignmentGroupManagement"; import AssignmentGroupManagement from "./AssignmentGroupManagement";
import DaysOfWeekSettings from "./DaysOfWeekSettings"; import DaysOfWeekSettings from "./DaysOfWeekSettings";
import DefaultDueTime from "./DefaultDueTime"; import DefaultDueTime from "./DefaultDueTime";
import DefaultFileUploadTypes from "./DefaultFileUploadTypes"; import DefaultFileUploadTypes from "./DefaultFileUploadTypes";
import GithubClassroomList from "./GithubClassroomList";
import HolidayConfig from "./HolidayConfig"; import HolidayConfig from "./HolidayConfig";
import SettingsHeader from "./SettingsHeader"; import SettingsHeader from "./SettingsHeader";
import StartAndEndDate from "./StartAndEndDate"; import StartAndEndDate from "./StartAndEndDate";
@@ -15,6 +16,7 @@ export default function AllSettings() {
<SettingsHeader /> <SettingsHeader />
<DaysOfWeekSettings /> <DaysOfWeekSettings />
<StartAndEndDate /> <StartAndEndDate />
<GithubClassroomList />
<SubmissionDefaults /> <SubmissionDefaults />
<DefaultFileUploadTypes /> <DefaultFileUploadTypes />
<DefaultDueTime /> <DefaultDueTime />

View File

@@ -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 (
<div className={settingsBox}>
<Spinner />
</div>
);
return (
<div className={settingsBox}>
<h5 className="text-center">Github Classroom Friendly Roster</h5>
<p className="text-center text-slate-500">
Copy and paste this into github classroom to import students
</p>
<pre>
<code>
{enrollmentsQuery.data?.map((student) => student.email + "\n")}
</code>
</pre>
</div>
);
}

View File

@@ -1,16 +1,11 @@
import { CanvasAssignmentGroup } from "@/models/canvas/assignments/canvasAssignmentGroup"; import { CanvasAssignmentGroup } from "@/models/canvas/assignments/canvasAssignmentGroup";
import { CanvasCourseModel } from "@/models/canvas/courses/canvasCourseModel"; import { CanvasCourseModel } from "@/models/canvas/courses/canvasCourseModel";
import { LocalAssignmentGroup } from "@/models/local/assignment/localAssignmentGroup"; import { LocalAssignmentGroup } from "@/models/local/assignment/localAssignmentGroup";
import { import { LocalCourseSettings } from "@/models/local/localCourseSettings";
LocalCourseSettings,
zodLocalCourseSettings,
} from "@/models/local/localCourseSettings";
import { canvasAssignmentGroupService } from "@/services/canvas/canvasAssignmentGroupService"; import { canvasAssignmentGroupService } from "@/services/canvas/canvasAssignmentGroupService";
import { canvasService } from "@/services/canvas/canvasService"; import { canvasService } from "@/services/canvas/canvasService";
import { trpc } from "@/services/serverFunctions/trpcClient";
import { useMutation, useQuery } from "@tanstack/react-query"; import { useMutation, useQuery } from "@tanstack/react-query";
import { useUpdateLocalCourseSettingsMutation } from "../localCourse/localCoursesHooks"; import { useUpdateLocalCourseSettingsMutation } from "../localCourse/localCoursesHooks";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
export const canvasCourseKeys = { export const canvasCourseKeys = {
courseDetails: (canavasId: number) => courseDetails: (canavasId: number) =>
@@ -19,6 +14,8 @@ export const canvasCourseKeys = {
["canvas", canavasId, "assignment groups"] as const, ["canvas", canavasId, "assignment groups"] as const,
courseListInTerm: (canvasTermId: number | undefined) => courseListInTerm: (canvasTermId: number | undefined) =>
["canvas courses in term", canvasTermId] as const, ["canvas courses in term", canvasTermId] as const,
students: (canvasId: number) =>
["students in canvas course", canvasId] as const,
}; };
export const useCourseListInTermQuery = (canvasTermId: number | undefined) => export const useCourseListInTermQuery = (canvasTermId: number | undefined) =>
@@ -101,3 +98,9 @@ export const useAssignmentGroupsQuery = (canvasId: number) => {
await canvasAssignmentGroupService.getAll(canvasId), await canvasAssignmentGroupService.getAll(canvasId),
}); });
}; };
export const useCourseStudentsQuery = (canvasId: number) =>
useQuery({
queryKey: canvasCourseKeys.students(canvasId),
queryFn: async () => await canvasService.getEnrolledStudents(canvasId),
});

View File

@@ -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;
}

View File

@@ -1,8 +1,8 @@
import { CanvasEnrollmentTermModel } from "@/models/canvas/enrollmentTerms/canvasEnrollmentTermModel"; import { CanvasEnrollmentTermModel } from "@/models/canvas/enrollmentTerms/canvasEnrollmentTermModel";
import { canvasApi, paginatedRequest } from "./canvasServiceUtils"; import { canvasApi, paginatedRequest } from "./canvasServiceUtils";
import { CanvasCourseModel } from "@/models/canvas/courses/canvasCourseModel"; import { CanvasCourseModel } from "@/models/canvas/courses/canvasCourseModel";
import { CanvasEnrollmentModel } from "@/models/canvas/enrollments/canvasEnrollmentModel";
import { axiosClient } from "../axiosUtils"; import { axiosClient } from "../axiosUtils";
import { CanvasCourseStudentModel } from "@/models/canvas/courses/canvasCourseStudentModel";
const getAllTerms = async () => { const getAllTerms = async () => {
const url = `${canvasApi}/accounts/10/terms?per_page=100`; const url = `${canvasApi}/accounts/10/terms?per_page=100`;
@@ -54,8 +54,8 @@ export const canvasService = {
async getEnrolledStudents(canvasCourseId: number) { async getEnrolledStudents(canvasCourseId: number) {
console.log(`Getting students for course ${canvasCourseId}`); console.log(`Getting students for course ${canvasCourseId}`);
const url = `${canvasApi}/courses/${canvasCourseId}/enrollments?enrollment_type=student`; const url = `${canvasApi}/courses/${canvasCourseId}/users?enrollment_type=student`;
const { data } = await axiosClient.get<CanvasEnrollmentModel[]>(url); const data = await paginatedRequest<CanvasCourseStudentModel[]>({url});
if (!data) if (!data)
throw new Error( throw new Error(