From 395e9934e6025657fc2c03c2e0f2e226bc7e8359 Mon Sep 17 00:00:00 2001 From: Alex Mickelson Date: Wed, 18 Sep 2024 21:50:40 -0600 Subject: [PATCH] limited latex support --- nextjs/package-lock.json | 54 +++++++++++++++++-- nextjs/package.json | 4 +- nextjs/src/app/api/canvas/[...rest]/route.ts | 34 +++++++----- .../app/course/[courseName]/calendar/Day.tsx | 2 +- .../[assignmentName]/EditAssignment.tsx | 33 +++++++++--- .../[moduleName]/page/[pageName]/EditPage.tsx | 1 - nextjs/src/app/globals.css | 17 +++++- nextjs/src/app/layout.tsx | 2 +- .../src/hooks/canvas/canvasAssignmentHooks.ts | 36 +++++++++++-- nextjs/src/services/axiosUtils.ts | 22 +++++--- .../canvas/canvasAssignmentService.ts | 32 ++++++----- nextjs/src/services/htmlMarkdownUtils.ts | 8 +++ 12 files changed, 195 insertions(+), 50 deletions(-) diff --git a/nextjs/package-lock.json b/nextjs/package-lock.json index bfb057e..0cba1c3 100644 --- a/nextjs/package-lock.json +++ b/nextjs/package-lock.json @@ -12,7 +12,9 @@ "@tanstack/react-query": "^5.54.1", "axios": "^1.7.5", "isomorphic-dompurify": "^2.15.0", - "marked": "^14.1.0", + "katex": "^0.16.11", + "marked": "^14.1.2", + "marked-katex-extension": "^5.1.2", "next": "^14.2.7", "react": "^18", "react-dom": "^18", @@ -1751,6 +1753,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/katex": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz", + "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.5.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.2.tgz", @@ -5196,6 +5204,31 @@ "node": ">=4.0" } }, + "node_modules/katex": { + "version": "0.16.11", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", + "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -5337,9 +5370,9 @@ } }, "node_modules/marked": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-14.1.0.tgz", - "integrity": "sha512-P93GikH/Pde0hM5TAXEd8I4JAYi8IB03n8qzW8Bh1BIEFpEyBoYxi/XWZA53LSpTeLBiMQOoSMj0u5E/tiVYTA==", + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-14.1.2.tgz", + "integrity": "sha512-f3r0yqpz31VXiDB/wj9GaOB0a2PRLQl6vJmXiFrniNwjkKdvakqJRULhjFKJpxOchlCRiG5fcacoUZY5Xa6PEQ==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -5348,6 +5381,19 @@ "node": ">= 18" } }, + "node_modules/marked-katex-extension": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/marked-katex-extension/-/marked-katex-extension-5.1.2.tgz", + "integrity": "sha512-jRtacvDAPULKBWArDno0IGpzzpUw12yb8OaEsv3dTlvcIr21+mF9kD+Bxo2m/ErX/2ZIml6zFVMnpxCpqx3stw==", + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.7" + }, + "peerDependencies": { + "katex": ">=0.16 <0.17", + "marked": ">=4 <15" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", diff --git a/nextjs/package.json b/nextjs/package.json index c68d044..970c2ee 100644 --- a/nextjs/package.json +++ b/nextjs/package.json @@ -14,7 +14,9 @@ "@tanstack/react-query": "^5.54.1", "axios": "^1.7.5", "isomorphic-dompurify": "^2.15.0", - "marked": "^14.1.0", + "katex": "^0.16.11", + "marked": "^14.1.2", + "marked-katex-extension": "^5.1.2", "next": "^14.2.7", "react": "^18", "react-dom": "^18", diff --git a/nextjs/src/app/api/canvas/[...rest]/route.ts b/nextjs/src/app/api/canvas/[...rest]/route.ts index d30e48b..ae28baf 100644 --- a/nextjs/src/app/api/canvas/[...rest]/route.ts +++ b/nextjs/src/app/api/canvas/[...rest]/route.ts @@ -1,7 +1,11 @@ import { NextRequest, NextResponse } from "next/server"; import { axiosClient } from "@/services/axiosUtils"; import { withErrorHandling } from "@/services/withErrorHandling"; -import { AxiosResponseHeaders, RawAxiosResponseHeaders } from "axios"; +import { + AxiosResponseHeaders, + isAxiosError, + RawAxiosResponseHeaders, +} from "axios"; const getUrl = (params: { rest: string[] }) => { const { rest } = params; @@ -27,7 +31,9 @@ const getNextUrl = ( const nextLink = links.find((link) => link.includes('rel="next"')); if (!nextLink) { - console.log("could not find next url in link header, reached end of pagination"); + console.log( + "could not find next url in link header, reached end of pagination" + ); return undefined; } @@ -58,9 +64,8 @@ export async function GET( url.toString() ); - if(!Array.isArray(firstData)) - { - return NextResponse.json(firstData) + if (!Array.isArray(firstData)) { + return NextResponse.json(firstData); } var returnData = firstData; @@ -82,7 +87,6 @@ export async function GET( } return NextResponse.json(returnData); - } catch (error: any) { return new NextResponse( JSON.stringify({ error: error.message || "Canvas GET request failed" }), @@ -97,18 +101,24 @@ export async function POST( { params }: { params: { rest: string[] } } ) { return withErrorHandling(async () => { + const url = getUrl(params); + const body = await req.json(); + let response; try { - const url = getUrl(params); - const body = await req.json(); - const response = await axiosClient.post(url.toString(), body); + response = await axiosClient.post(url.toString(), body); const headers = proxyResponseHeaders(response); return new NextResponse(JSON.stringify(response.data), { headers }); } catch (error: any) { - return new NextResponse( - JSON.stringify({ + if (isAxiosError(error)) { + console.log(url.toString(), body); + console.log("response data", JSON.stringify( error.response?.data)); + console.log("is axios error"); + } + return NextResponse.json( + { error: error.message || "Canvas POST request failed", - }), + }, { status: error.response?.status || 500 } ); } diff --git a/nextjs/src/app/course/[courseName]/calendar/Day.tsx b/nextjs/src/app/course/[courseName]/calendar/Day.tsx index 25d28fe..87d66a6 100644 --- a/nextjs/src/app/course/[courseName]/calendar/Day.tsx +++ b/nextjs/src/app/course/[courseName]/calendar/Day.tsx @@ -135,7 +135,7 @@ function DraggableListItem({ href={getModuleItemUrl(courseName, moduleName, type, item.name)} shallow={true} className={ - " border rounded-sm px-1 mx-1 break-all " + + " border rounded-sm px-1 mx-1 break-all mb-1 " + " border-slate-600 bg-slate-800 " + " block " } diff --git a/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx b/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx index 3017c04..eec6780 100644 --- a/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx +++ b/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx @@ -15,9 +15,11 @@ import { useAddAssignmentToCanvasMutation, useCanvasAssignmentsQuery, useDeleteAssignmentFromCanvasMutation, + useUpdateAssignmentInCanvasMutation, } from "@/hooks/canvas/canvasAssignmentHooks"; import { Spinner } from "@/components/Spinner"; import { baseCanvasUrl } from "@/services/canvas/canvasServiceUtils"; +import ClientOnly from "@/components/ClientOnly"; export default function EditAssignment({ moduleName, @@ -79,10 +81,12 @@ export default function EditAssignment({ - + + + ); } @@ -100,13 +104,16 @@ function AssignmentButtons({ const { data: assignment } = useAssignmentQuery(moduleName, assignmentName); const addToCanvas = useAddAssignmentToCanvasMutation(); const deleteFromCanvas = useDeleteAssignmentFromCanvasMutation(); + const updateAssignment = useUpdateAssignmentInCanvasMutation(); const assignmentInCanvas = canvasAssignments.find( (a) => a.name === assignmentName ); return (
- {(addToCanvas.isPending || deleteFromCanvas.isPending) && } + {(addToCanvas.isPending || + deleteFromCanvas.isPending || + updateAssignment.isPending) && } {assignmentInCanvas && !assignmentInCanvas.published && (
Not Published
)} @@ -115,7 +122,7 @@ function AssignmentButtons({ disabled={addToCanvas.isPending} onClick={() => addToCanvas.mutate(assignment)} > - Add to canvas.... + Add to canvas )} {assignmentInCanvas && ( @@ -127,6 +134,20 @@ function AssignmentButtons({ View in Canvas )} + {assignmentInCanvas && ( + + )} {assignmentInCanvas && (