mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-26 07:38:33 -06:00
some papercuts
This commit is contained in:
@@ -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
|
quiz: updatedQuiz,
|
||||||
);
|
moduleName,
|
||||||
await updateQuizMutation
|
quizName: quizName,
|
||||||
.mutateAsync({
|
previousModuleName: moduleName,
|
||||||
quiz: updatedQuiz,
|
previousQuizName: quizName,
|
||||||
moduleName,
|
courseName,
|
||||||
quizName: quizName,
|
});
|
||||||
previousModuleName: moduleName,
|
|
||||||
previousQuizName: quizName,
|
|
||||||
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">
|
||||||
|
|||||||
@@ -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 />
|
||||||
|
|||||||
31
src/app/course/[courseName]/settings/GithubClassroomList.tsx
Normal file
31
src/app/course/[courseName]/settings/GithubClassroomList.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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),
|
||||||
|
});
|
||||||
|
|||||||
12
src/models/canvas/courses/canvasCourseStudentModel.ts
Normal file
12
src/models/canvas/courses/canvasCourseStudentModel.ts
Normal 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;
|
||||||
|
}
|
||||||
@@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user