more centralization

This commit is contained in:
2024-09-27 11:06:54 -06:00
parent ae8bd1297e
commit f990619e05
13 changed files with 205 additions and 225 deletions

129
nextjs/package-lock.json generated
View File

@@ -8,21 +8,13 @@
"name": "canvas-mangement",
"version": "0.1.0",
"dependencies": {
"@monaco-editor/react": "^4.6.0",
"@tanstack/react-query": "^5.54.1",
"axios": "^1.7.5",
"isomorphic-dompurify": "^2.15.0",
"katex": "^0.16.11",
"marked": "^14.1.2",
"marked-katex-extension": "^5.1.2",
"next": "^14.2.7",
"react": "^18",
"react-dom": "^18",
"react-error-boundary": "^4.0.13",
"react-hot-toast": "^2.4.1",
"yaml": "^2.5.0"
"react-dom": "^18"
},
"devDependencies": {
"@monaco-editor/react": "^4.6.0",
"@tanstack/react-query": "^5.54.1",
"@tanstack/react-query-devtools": "^5.54.1",
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.0.0",
@@ -30,12 +22,18 @@
"@types/react": "^18",
"@types/react-dom": "^18",
"@vitejs/plugin-react": "^4.3.1",
"axios": "^1.7.5",
"eslint-config-next": "^14.2.7",
"isomorphic-dompurify": "^2.15.0",
"jsdom": "^25.0.0",
"marked": "^14.1.2",
"postcss": "^8",
"react-error-boundary": "^4.0.13",
"react-hot-toast": "^2.4.1",
"tailwindcss": "^3.4.1",
"typescript": "^5",
"vitest": "^2.0.5"
"vitest": "^2.0.5",
"yaml": "^2.5.0"
}
},
"node_modules/@alloc/quick-lru": {
@@ -400,6 +398,7 @@
"version": "7.25.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz",
"integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"regenerator-runtime": "^0.14.0"
@@ -1087,6 +1086,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.4.0.tgz",
"integrity": "sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==",
"dev": true,
"license": "MIT",
"dependencies": {
"state-local": "^1.0.6"
@@ -1099,6 +1099,7 @@
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.6.0.tgz",
"integrity": "sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@monaco-editor/loader": "^1.4.0"
@@ -1579,6 +1580,7 @@
"version": "5.54.1",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.54.1.tgz",
"integrity": "sha512-hKS+WRpT5zBFip21pB6Jx1C0hranWQrbv5EJ7qPoiV5MYI3C8rTCqWC9DdBseiPT1JgQWh8Y55YthuYZNiw3Xw==",
"dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -1600,6 +1602,7 @@
"version": "5.54.1",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.54.1.tgz",
"integrity": "sha512-SuMi4JBYv49UtmiRyqjxY7XAnE1qwLht9nlkC8sioxFXz5Uzj30lepiKf2mYXuXfC7fHYjTrAPkNx+427pRHXA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@tanstack/query-core": "5.54.1"
@@ -1734,6 +1737,7 @@
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz",
"integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/trusted-types": "*"
@@ -1753,12 +1757,6 @@
"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",
@@ -1801,6 +1799,7 @@
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
"dev": true,
"license": "MIT"
},
"node_modules/@typescript-eslint/parser": {
@@ -2094,6 +2093,7 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
"integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
"dev": true,
"license": "MIT",
"dependencies": {
"debug": "^4.3.4"
@@ -2381,6 +2381,7 @@
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true,
"license": "MIT"
},
"node_modules/available-typed-arrays": {
@@ -2413,6 +2414,7 @@
"version": "1.7.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
@@ -2710,6 +2712,7 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
@@ -2774,6 +2777,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz",
"integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"rrweb-cssom": "^0.6.0"
@@ -2786,12 +2790,14 @@
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
"integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==",
"dev": true,
"license": "MIT"
},
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"dev": true,
"license": "MIT"
},
"node_modules/damerau-levenshtein": {
@@ -2805,6 +2811,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
"integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
"dev": true,
"license": "MIT",
"dependencies": {
"whatwg-mimetype": "^4.0.0",
@@ -2872,6 +2879,7 @@
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "2.1.2"
@@ -2889,6 +2897,7 @@
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
"integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
"dev": true,
"license": "MIT"
},
"node_modules/deep-eql": {
@@ -2982,6 +2991,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.4.0"
@@ -3049,6 +3059,7 @@
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz",
"integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==",
"dev": true,
"license": "(MPL-2.0 OR Apache-2.0)"
},
"node_modules/eastasianwidth": {
@@ -3090,6 +3101,7 @@
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
@@ -3977,6 +3989,7 @@
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"dev": true,
"funding": [
{
"type": "individual",
@@ -4024,6 +4037,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dev": true,
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
@@ -4294,6 +4308,7 @@
"version": "2.1.14",
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.14.tgz",
"integrity": "sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"csstype": "^3.0.10"
@@ -4418,6 +4433,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
"integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"whatwg-encoding": "^3.1.1"
@@ -4430,6 +4446,7 @@
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
"dev": true,
"license": "MIT",
"dependencies": {
"agent-base": "^7.1.0",
@@ -4443,6 +4460,7 @@
"version": "7.0.5",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
"integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
"dev": true,
"license": "MIT",
"dependencies": {
"agent-base": "^7.0.2",
@@ -4466,6 +4484,7 @@
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dev": true,
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
@@ -4855,6 +4874,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
"dev": true,
"license": "MIT"
},
"node_modules/is-regex": {
@@ -5025,6 +5045,7 @@
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-2.15.0.tgz",
"integrity": "sha512-RDHlyeVmwEDAPZuX1VaaBzSn9RrsfvswxH7faEQK9cTHC1dXeNuK6ElUeSr7locFyeLguut8ASfhQWxHB4Ttug==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/dompurify": "^3.0.5",
@@ -5102,6 +5123,7 @@
"version": "25.0.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.0.tgz",
"integrity": "sha512-OhoFVT59T7aEq75TVw9xxEfkXgacpqAhQaYgP9y/fDqWQCMB/b1H66RfmPm/MaeaAIU9nDwMOVTlPN51+ao6CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"cssstyle": "^4.0.1",
@@ -5204,31 +5226,6 @@
"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",
@@ -5373,6 +5370,7 @@
"version": "14.1.2",
"resolved": "https://registry.npmjs.org/marked/-/marked-14.1.2.tgz",
"integrity": "sha512-f3r0yqpz31VXiDB/wj9GaOB0a2PRLQl6vJmXiFrniNwjkKdvakqJRULhjFKJpxOchlCRiG5fcacoUZY5Xa6PEQ==",
"dev": true,
"license": "MIT",
"bin": {
"marked": "bin/marked.js"
@@ -5381,19 +5379,6 @@
"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",
@@ -5429,6 +5414,7 @@
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -5438,6 +5424,7 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
@@ -5496,6 +5483,7 @@
"version": "0.50.0",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.50.0.tgz",
"integrity": "sha512-8CclLCmrRRh+sul7C08BmPBP3P8wVWfBHomsTcndxg5NRCEPfu/mc2AGU8k37ajjDVXcXFc12ORAMUkmk+lkFA==",
"dev": true,
"license": "MIT",
"peer": true
},
@@ -5503,6 +5491,7 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true,
"license": "MIT"
},
"node_modules/mz": {
@@ -5671,6 +5660,7 @@
"version": "2.2.12",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz",
"integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==",
"dev": true,
"license": "MIT"
},
"node_modules/object-assign": {
@@ -5917,6 +5907,7 @@
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
"dev": true,
"license": "MIT",
"dependencies": {
"entities": "^4.4.0"
@@ -6289,18 +6280,21 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"dev": true,
"license": "MIT"
},
"node_modules/psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
"dev": true,
"license": "MIT"
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -6310,6 +6304,7 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
"dev": true,
"license": "MIT"
},
"node_modules/queue-microtask": {
@@ -6362,6 +6357,7 @@
"version": "4.0.13",
"resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz",
"integrity": "sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.5"
@@ -6374,6 +6370,7 @@
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz",
"integrity": "sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"goober": "^2.1.10"
@@ -6452,6 +6449,7 @@
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"dev": true,
"license": "MIT"
},
"node_modules/regexp.prototype.flags": {
@@ -6477,6 +6475,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"dev": true,
"license": "MIT"
},
"node_modules/resolve": {
@@ -6610,6 +6609,7 @@
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz",
"integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==",
"dev": true,
"license": "MIT"
},
"node_modules/run-parallel": {
@@ -6677,12 +6677,14 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"license": "MIT"
},
"node_modules/saxes": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
"integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
"dev": true,
"license": "ISC",
"dependencies": {
"xmlchars": "^2.2.0"
@@ -6861,6 +6863,7 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz",
"integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==",
"dev": true,
"license": "MIT"
},
"node_modules/std-env": {
@@ -7202,6 +7205,7 @@
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
"dev": true,
"license": "MIT"
},
"node_modules/tailwindcss": {
@@ -7377,6 +7381,7 @@
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"psl": "^1.1.33",
@@ -7392,6 +7397,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
"integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
"dev": true,
"license": "MIT",
"dependencies": {
"punycode": "^2.3.1"
@@ -7598,6 +7604,7 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 4.0.0"
@@ -7649,6 +7656,7 @@
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"querystringify": "^2.1.1",
@@ -7814,6 +7822,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
"integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
"dev": true,
"license": "MIT",
"dependencies": {
"xml-name-validator": "^5.0.0"
@@ -7826,6 +7835,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
@@ -7835,6 +7845,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
"integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"iconv-lite": "0.6.3"
@@ -7847,6 +7858,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
"integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
@@ -7856,6 +7868,7 @@
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
"integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
"dev": true,
"license": "MIT",
"dependencies": {
"tr46": "^5.0.0",
@@ -8105,6 +8118,7 @@
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10.0.0"
@@ -8126,6 +8140,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
"integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=18"
@@ -8135,6 +8150,7 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true,
"license": "MIT"
},
"node_modules/yallist": {
@@ -8148,6 +8164,7 @@
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz",
"integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==",
"dev": true,
"license": "ISC",
"bin": {
"yaml": "bin.mjs"

View File

@@ -6,7 +6,7 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"lint": "tsc && next lint",
"test": "vitest"
},
"dependencies": {

View File

@@ -8,9 +8,9 @@ export const GET = async (
}: { params: { courseName: string; moduleName: string } }
) =>
await withErrorHandling(async () => {
const settings = await fileStorageService.pages.getPageNames(
const pages = await fileStorageService.pages.getPages(
courseName,
moduleName
);
return Response.json(settings);
return Response.json(pages);
});

View File

@@ -8,9 +8,9 @@ export const GET = async (
}: { params: { courseName: string; moduleName: string } }
) =>
await withErrorHandling(async () => {
const settings = await fileStorageService.quizzes.getQuizNames(
const quizzes = await fileStorageService.quizzes.getQuizzes(
courseName,
moduleName
);
return Response.json(settings);
return Response.json(quizzes);
});

View File

@@ -1,13 +1,9 @@
"use client";
import { useAssignmentsQueries } from "@/hooks/localCourse/assignmentHooks";
import {
useAssignmentsQueries,
} from "@/hooks/localCourse/assignmentHooks";
import {
usePageNamesQuery,
usePagesQueries,
} from "@/hooks/localCourse/pageHooks";
import {
useQuizNamesQuery,
useQuizzesQueries,
} from "@/hooks/localCourse/quizHooks";
import { IModuleItem } from "@/models/local/IModuleItem";
@@ -33,15 +29,11 @@ export default function ExpandableModule({
}: {
moduleName: string;
}) {
const { data: quizNames } = useQuizNamesQuery(moduleName);
const { data: pageNames } = usePageNamesQuery(moduleName);
const { itemDropOnModule } = useDraggingContext();
const { data: assignments } = useAssignmentsQueries(
moduleName,
);
const { data: quizzes } = useQuizzesQueries(moduleName, quizNames);
const { data: pages } = usePagesQueries(moduleName, pageNames);
const { data: assignments } = useAssignmentsQueries(moduleName);
const { data: quizzes } = useQuizzesQueries(moduleName);
const { data: pages } = usePagesQueries(moduleName);
const [expanded, setExpanded] = useState(false);

View File

@@ -73,16 +73,16 @@ export const hydrateCanvasCourse = async (
};
const loadAllModuleData = async (courseName: string, moduleName: string) => {
const [assignmentNames, pageNames, quizNames] = await Promise.all([
const [assignmentNames, pages, quizzes] = await Promise.all([
await fileStorageService.assignments.getAssignmentNames(
courseName,
moduleName
),
await fileStorageService.pages.getPageNames(courseName, moduleName),
await fileStorageService.quizzes.getQuizNames(courseName, moduleName),
await fileStorageService.pages.getPages(courseName, moduleName),
await fileStorageService.quizzes.getQuizzes(courseName, moduleName),
]);
const [assignments, quizzes, pages] = await Promise.all([
const [assignments] = await Promise.all([
await Promise.all(
assignmentNames.map(async (assignmentName) => {
try {
@@ -97,33 +97,11 @@ const loadAllModuleData = async (courseName: string, moduleName: string) => {
}
})
),
await Promise.all(
quizNames.map(
async (quizName) =>
await fileStorageService.quizzes.getQuiz(
courseName,
moduleName,
quizName
)
)
),
await Promise.all(
pageNames.map(
async (pageName) =>
await fileStorageService.pages.getPage(
courseName,
moduleName,
pageName
)
)
),
]);
const assignmentsLoaded = assignments.filter(a => a !== null);
const assignmentsLoaded = assignments.filter((a) => a !== null);
return {
moduleName,
pageNames,
quizNames,
assignments: assignmentsLoaded,
quizzes,
pages,
@@ -133,15 +111,11 @@ const loadAllModuleData = async (courseName: string, moduleName: string) => {
const hydrateModuleData = async (
{
moduleName,
pageNames,
quizNames,
assignments,
quizzes,
pages,
}: {
moduleName: string;
pageNames: string[];
quizNames: string[];
assignments: LocalAssignment[];
quizzes: LocalQuiz[];
pages: LocalCoursePage[];
@@ -153,6 +127,14 @@ const hydrateModuleData = async (
queryKey: localCourseKeys.allAssignments(courseName, moduleName),
queryFn: () => assignments,
});
await queryClient.prefetchQuery({
queryKey: localCourseKeys.allQuizzes(courseName, moduleName),
queryFn: () => quizzes,
});
await queryClient.prefetchQuery({
queryKey: localCourseKeys.allPages(courseName, moduleName),
queryFn: () => pages,
});
await Promise.all(
assignments.map(
async (assignment) =>
@@ -166,10 +148,6 @@ const hydrateModuleData = async (
})
)
);
await queryClient.prefetchQuery({
queryKey: localCourseKeys.quizNames(courseName, moduleName),
queryFn: () => quizNames,
});
await Promise.all(
quizzes.map(
async (quiz) =>
@@ -179,10 +157,6 @@ const hydrateModuleData = async (
})
)
);
await queryClient.prefetchQuery({
queryKey: localCourseKeys.pageNames(courseName, moduleName),
queryFn: () => pageNames,
});
await Promise.all(
pages.map(
async (page) =>

View File

@@ -28,7 +28,7 @@ export const getAllAssignmentsQueryConfig = (
},
});
export const useAllAssignmentNamesQuery = (moduleName: string) => {
const useAllAssignmentsQuery = (moduleName: string) => {
const { courseName } = useCourseContext();
return useSuspenseQuery(getAllAssignmentsQueryConfig(courseName, moduleName));
};
@@ -70,7 +70,7 @@ export const useAssignmentQuery = (
};
export const useAssignmentsQueries = (moduleName: string) => {
const { data: allAssignments } = useAllAssignmentNamesQuery(moduleName);
const { data: allAssignments } = useAllAssignmentsQuery(moduleName);
const { courseName } = useCourseContext();
return useSuspenseQueries({
queries: allAssignments.map((assignment) =>

View File

@@ -19,23 +19,23 @@ export const localCourseKeys = {
"assignments",
{ type: "all assignments" },
] as const,
quizNames: (courseName: string, moduleName: string) =>
allQuizzes: (courseName: string, moduleName: string) =>
[
"course details",
courseName,
"modules",
moduleName,
"quizzes",
{ type: "names" },
{ type: "all quizzes" },
] as const,
pageNames: (courseName: string, moduleName: string) =>
allPages: (courseName: string, moduleName: string) =>
[
"course details",
courseName,
"modules",
moduleName,
"pages",
{ type: "names" },
{ type: "all pages" },
] as const,
assignment: (
courseName: string,

View File

@@ -11,8 +11,8 @@ import {
getAllAssignmentsQueryConfig,
getAssignmentQueryConfig,
} from "./assignmentHooks";
import { getPageNamesQueryConfig, getPageQueryConfig } from "./pageHooks";
import { getQuizNamesQueryConfig, getQuizQueryConfig } from "./quizHooks";
import { getAllPagesQueryConfig, getPageQueryConfig } from "./pageHooks";
import { getAllQuizzesQueryConfig, getQuizQueryConfig } from "./quizHooks";
export const useModuleNamesQuery = () => {
const { courseName } = useCourseContext();
@@ -92,57 +92,15 @@ export const useAllCourseDataQuery = () => {
}),
});
// const { data: assignmentsAndModules } = useSuspenseQueries({
// queries: assignmentsAndModules.map(
// ({ moduleName, assignment }, i) =>
// getAssignmentQueryConfig(courseName, moduleName, assignment)
// ),
// combine: (results) => ({
// data: results.flatMap((r, i) => ({
// moduleName: assignmentsAndModules[i].moduleName,
// assignment: r.data,
// })),
// pending: results.some((r) => r.isPending),
// }),
// });
const { data: quizNamesAndModules } = useSuspenseQueries({
queries: moduleNames.map((moduleName) =>
getQuizNamesQueryConfig(courseName, moduleName)
),
combine: (results) => ({
data: results.flatMap((r, i) =>
r.data.map((quizName) => ({
moduleName: moduleNames[i],
quizName: quizName,
}))
),
pending: results.some((r) => r.isPending),
}),
});
const { data: quizzesAndModules } = useSuspenseQueries({
queries: quizNamesAndModules.map(({ moduleName, quizName }, i) =>
getQuizQueryConfig(courseName, moduleName, quizName)
),
combine: (results) => ({
data: results.flatMap((r, i) => ({
moduleName: quizNamesAndModules[i].moduleName,
quiz: r.data,
})),
pending: results.some((r) => r.isPending),
}),
});
const { data: pageNamesAndModules } = useSuspenseQueries({
queries: moduleNames.map((moduleName) =>
getPageNamesQueryConfig(courseName, moduleName)
getAllQuizzesQueryConfig(courseName, moduleName)
),
combine: (results) => ({
data: results.flatMap((r, i) =>
r.data.map((pageName) => ({
r.data.map((quiz) => ({
moduleName: moduleNames[i],
pageName,
quiz,
}))
),
pending: results.some((r) => r.isPending),
@@ -150,14 +108,16 @@ export const useAllCourseDataQuery = () => {
});
const { data: pagesAndModules } = useSuspenseQueries({
queries: pageNamesAndModules.map(({ moduleName, pageName }, i) =>
getPageQueryConfig(courseName, moduleName, pageName)
queries: moduleNames.map((moduleName) =>
getAllPagesQueryConfig(courseName, moduleName)
),
combine: (results) => ({
data: results.flatMap((r, i) => ({
moduleName: pageNamesAndModules[i].moduleName,
page: r.data,
})),
data: results.flatMap((r, i) =>
r.data.map((page) => ({
moduleName: moduleNames[i],
page,
}))
),
pending: results.some((r) => r.isPending),
}),
});

View File

@@ -10,13 +10,10 @@ import { localCourseKeys } from "./localCourseKeys";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
import { axiosClient } from "@/services/axiosUtils";
export function getPageNamesQueryConfig(
courseName: string,
moduleName: string
) {
export function getAllPagesQueryConfig(courseName: string, moduleName: string) {
return {
queryKey: localCourseKeys.pageNames(courseName, moduleName),
queryFn: async (): Promise<string[]> => {
queryKey: localCourseKeys.allPages(courseName, moduleName),
queryFn: async (): Promise<LocalCoursePage[]> => {
const url =
"/api/courses/" +
encodeURIComponent(courseName) +
@@ -29,29 +26,6 @@ export function getPageNamesQueryConfig(
};
}
export const usePageNamesQuery = (moduleName: string) => {
const { courseName } = useCourseContext();
return useSuspenseQuery(getPageNamesQueryConfig(courseName, moduleName));
};
export const usePageQuery = (moduleName: string, pageName: string) => {
const { courseName } = useCourseContext();
return useSuspenseQuery(getPageQueryConfig(courseName, moduleName, pageName));
};
export const usePagesQueries = (moduleName: string, pageNames: string[]) => {
const { courseName } = useCourseContext();
return useSuspenseQueries({
queries: pageNames.map((name) =>
getPageQueryConfig(courseName, moduleName, name)
),
combine: (results) => ({
data: results.map((r) => r.data),
pending: results.some((r) => r.isPending),
}),
});
};
export function getPageQueryConfig(
courseName: string,
moduleName: string,
@@ -72,13 +46,37 @@ export function getPageQueryConfig(
return response.data;
} catch (e) {
console.log("error getting page", e, url);
debugger;
throw e;
}
},
};
}
export const usePageQuery = (moduleName: string, pageName: string) => {
const { courseName } = useCourseContext();
return useSuspenseQuery(getPageQueryConfig(courseName, moduleName, pageName));
};
const useAllPagesQuery = (moduleName: string) => {
const { courseName } = useCourseContext();
return useSuspenseQuery(getAllPagesQueryConfig(courseName, moduleName));
};
export const usePagesQueries = (moduleName: string) => {
const { courseName } = useCourseContext();
const { data: allPages } = useAllPagesQuery(moduleName);
return useSuspenseQueries({
queries: allPages.map((page) => ({
...getPageQueryConfig(courseName, moduleName, page.name),
queryFn: () => page,
})),
combine: (results) => ({
data: results.map((r) => r.data),
pending: results.some((r) => r.isPending),
}),
});
};
export const useUpdatePageMutation = () => {
const { courseName } = useCourseContext();
const queryClient = useQueryClient();
@@ -109,7 +107,7 @@ export const useUpdatePageMutation = () => {
),
});
queryClient.removeQueries({
queryKey: localCourseKeys.pageNames(courseName, moduleName),
queryKey: localCourseKeys.allPages(courseName, moduleName),
});
}
queryClient.setQueryData(
@@ -131,7 +129,7 @@ export const useUpdatePageMutation = () => {
},
onSuccess: async (_, { moduleName, pageName }) => {
await queryClient.invalidateQueries({
queryKey: localCourseKeys.pageNames(courseName, moduleName),
queryKey: localCourseKeys.allPages(courseName, moduleName),
});
await queryClient.invalidateQueries({
queryKey: localCourseKeys.page(courseName, moduleName, pageName),
@@ -171,7 +169,7 @@ export const useCreatePageMutation = () => {
queryKey: localCourseKeys.page(courseName, moduleName, pageName),
});
queryClient.invalidateQueries({
queryKey: localCourseKeys.pageNames(courseName, moduleName),
queryKey: localCourseKeys.allPages(courseName, moduleName),
});
},
});
@@ -192,7 +190,7 @@ export const useDeletePageMutation = () => {
queryKey: localCourseKeys.page(courseName, moduleName, pageName),
});
queryClient.removeQueries({
queryKey: localCourseKeys.pageNames(courseName, moduleName),
queryKey: localCourseKeys.allPages(courseName, moduleName),
});
const url =
"/api/courses/" +
@@ -202,11 +200,10 @@ export const useDeletePageMutation = () => {
"/pages/" +
encodeURIComponent(pageName);
await axiosClient.delete(url);
},
onSuccess: async (_, { moduleName, pageName }) => {
await queryClient.invalidateQueries({
queryKey: localCourseKeys.pageNames(courseName, moduleName),
queryKey: localCourseKeys.allPages(courseName, moduleName),
});
await queryClient.invalidateQueries({
queryKey: localCourseKeys.page(courseName, moduleName, pageName),

View File

@@ -10,13 +10,13 @@ import { localCourseKeys } from "./localCourseKeys";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
import { axiosClient } from "@/services/axiosUtils";
export function getQuizNamesQueryConfig(
export function getAllQuizzesQueryConfig(
courseName: string,
moduleName: string
) {
return {
queryKey: localCourseKeys.quizNames(courseName, moduleName),
queryFn: async (): Promise<string[]> => {
queryKey: localCourseKeys.allQuizzes(courseName, moduleName),
queryFn: async (): Promise<LocalQuiz[]> => {
const url =
"/api/courses/" +
encodeURIComponent(courseName) +
@@ -28,22 +28,24 @@ export function getQuizNamesQueryConfig(
},
};
}
export const useQuizNamesQuery = (moduleName: string) => {
const { courseName } = useCourseContext();
return useSuspenseQuery(getQuizNamesQueryConfig(courseName, moduleName));
};
export const useQuizQuery = (moduleName: string, quizName: string) => {
const { courseName } = useCourseContext();
return useSuspenseQuery(getQuizQueryConfig(courseName, moduleName, quizName));
};
export const useQuizzesQueries = (moduleName: string, quizNames: string[]) => {
const useAllQuizzesQuery = (moduleName: string) => {
const { courseName } = useCourseContext();
return useSuspenseQuery(getAllQuizzesQueryConfig(courseName, moduleName));
};
export const useQuizzesQueries = (moduleName: string) => {
const { courseName } = useCourseContext();
const { data: allQuizzes } = useAllQuizzesQuery(moduleName);
return useSuspenseQueries({
queries: quizNames.map((name) =>
getQuizQueryConfig(courseName, moduleName, name)
),
queries: allQuizzes.map((quiz) => ({
...getQuizQueryConfig(courseName, moduleName, quiz.name),
queryFn: () => quiz,
})),
combine: (results) => ({
data: results.map((r) => r.data),
pending: results.some((r) => r.isPending),
@@ -102,7 +104,7 @@ export const useUpdateQuizMutation = () => {
),
});
queryClient.removeQueries({
queryKey: localCourseKeys.quizNames(courseName, previousModuleName),
queryKey: localCourseKeys.allQuizzes(courseName, previousModuleName),
});
}
queryClient.setQueryData(
@@ -128,7 +130,7 @@ export const useUpdateQuizMutation = () => {
},
onSuccess: async (_, { moduleName, quizName }) => {
await queryClient.invalidateQueries({
queryKey: localCourseKeys.quizNames(courseName, moduleName),
queryKey: localCourseKeys.allQuizzes(courseName, moduleName),
});
await queryClient.invalidateQueries({
queryKey: localCourseKeys.quiz(courseName, moduleName, quizName),
@@ -165,7 +167,7 @@ export const useCreateQuizMutation = () => {
},
onSuccess: async (_, { moduleName, quizName }) => {
await queryClient.invalidateQueries({
queryKey: localCourseKeys.quizNames(courseName, moduleName),
queryKey: localCourseKeys.allQuizzes(courseName, moduleName),
});
await queryClient.invalidateQueries({
queryKey: localCourseKeys.quiz(courseName, moduleName, quizName),
@@ -194,12 +196,12 @@ export const useDeleteQuizMutation = () => {
encodeURIComponent(quizName);
await axiosClient.delete(url);
queryClient.removeQueries({
queryKey: localCourseKeys.quizNames(courseName, moduleName),
queryKey: localCourseKeys.allQuizzes(courseName, moduleName),
});
},
onSuccess: async (_, { moduleName, quizName }) => {
await queryClient.invalidateQueries({
queryKey: localCourseKeys.quizNames(courseName, moduleName),
queryKey: localCourseKeys.allQuizzes(courseName, moduleName),
});
await queryClient.invalidateQueries({
queryKey: localCourseKeys.quiz(courseName, moduleName, quizName),

View File

@@ -13,6 +13,8 @@ import {
LocalCoursePage,
localPageMarkdownUtils,
} from "@/models/local/page/localCoursePage";
import { assignmentMarkdownSerializer } from "@/models/local/assignment/utils/assignmentMarkdownSerializer";
import { quizMarkdownUtils } from "@/models/local/quiz/utils/quizMarkdownUtils";
const typeToFolder = {
Assignment: "assignments",
@@ -99,4 +101,41 @@ export const courseItemFileStorageService = {
).filter((a) => a !== null);
return items;
},
async updateOrCreateAssignment({
courseName,
moduleName,
name,
item,
type,
}: {
courseName: string;
moduleName: string;
name: string;
item: LocalAssignment | LocalQuiz | LocalCoursePage;
type: CourseItemType;
}) {
const typeFolder = typeToFolder[type];
const folder = path.join(basePath, courseName, moduleName, typeFolder);
await fs.mkdir(folder, { recursive: true });
const filePath = path.join(
basePath,
courseName,
moduleName,
typeFolder,
name + ".md"
);
const markdownDictionary: {
[key in CourseItemType]: () => string;
} = {
Assignment: () => assignmentMarkdownSerializer.toMarkdown(item as LocalAssignment),
Quiz: () => quizMarkdownUtils.toMarkdown(item as LocalQuiz),
Page: () => localPageMarkdownUtils.toMarkdown(item as LocalCoursePage),
};
const itemMarkdown = markdownDictionary[type]();
console.log(`Saving ${type} ${filePath}`);
await fs.writeFile(filePath, itemMarkdown);
},
};

View File

@@ -14,7 +14,6 @@ export const fileStorageService = {
quizzes: quizFileStorageService,
pages: pageFileStorageService,
async getEmptyDirectories(): Promise<string[]> {
if (!(await directoryOrFileExists(basePath))) {
throw new Error(
@@ -48,7 +47,7 @@ export const fileStorageService = {
await fs.mkdir(courseDirectory, { recursive: true });
},
async createModuleFolderForTesting(courseName: string, moduleName: string) {
const courseDirectory = path.join(basePath, courseName);
const courseDirectory = path.join(basePath, courseName, moduleName);
await fs.mkdir(courseDirectory, { recursive: true });
},