diff --git a/.env b/.env deleted file mode 100644 index a2801f4359..0000000000 --- a/.env +++ /dev/null @@ -1 +0,0 @@ -COMPOSE_PROJECT_NAME=doenet \ No newline at end of file diff --git a/client/package-lock.json b/client/package-lock.json index ffea519239..3b237ae9c0 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -14,13 +14,14 @@ "@fontsource/jost": "^5.0.18", "@fortawesome/free-solid-svg-icons": "^6.6.0", "@fortawesome/react-fontawesome": "^0.2.2", - "axios": "^1.7.2", + "axios": "^1.7.3", "better-react-mathjax": "^2.0.3", "browser-image-resizer": "^2.4.1", "copy-to-clipboard": "^3.3.3", "cssesc": "^3.0.0", + "hi-base32": "^0.5.1", "js-cookie": "^3.0.5", - "luxon": "^3.4.4", + "luxon": "^3.5.0", "math-expressions": "^2.0.0-alpha64", "nanoid": "^5.0.7", "papaparse": "^5.4.1", @@ -30,8 +31,9 @@ "react-dropzone": "^14.2.3", "react-icons": "4.8.0", "react-qrcode-logo": "^3.0.0", - "react-router": "^6.25.1", - "react-router-dom": "^6.25.1", + "react-router": "^6.26.0", + "react-router-dom": "^6.26.0", + "react-select": "^5.8.0", "recharts": "^2.12.7", "styled-components": "5.3.11", "swiper": "^9.4.1" @@ -64,7 +66,7 @@ "rollup": "^2.71.1", "rollup-plugin-polyfill-node": "^0.13.0", "rollup-plugin-terser": "^7.0.2", - "vite": "^5.3.5", + "vite": "^5.4.0", "vite-plugin-mpa": "^1.2.0", "vite-plugin-static-copy": "^1.0.6" }, @@ -1851,7 +1853,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", - "peer": true, "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", @@ -1869,14 +1870,12 @@ "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "peer": true + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "node_modules/@emotion/cache": { "version": "11.13.0", "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.0.tgz", "integrity": "sha512-hPV345J/tH0Cwk2wnU/3PBzORQ9HeX+kQSbwI+jslzpRCHE6fSGTohswksA/Ensr8znPzwfzKZCmAM9Lmlhp7g==", - "peer": true, "dependencies": { "@emotion/memoize": "^0.9.0", "@emotion/sheet": "^1.4.0", @@ -1888,8 +1887,7 @@ "node_modules/@emotion/hash": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", - "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", - "peer": true + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" }, "node_modules/@emotion/is-prop-valid": { "version": "1.3.0", @@ -1908,7 +1906,6 @@ "version": "11.13.0", "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.0.tgz", "integrity": "sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ==", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.12.0", @@ -1932,7 +1929,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz", "integrity": "sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==", - "peer": true, "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", @@ -1944,8 +1940,7 @@ "node_modules/@emotion/sheet": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", - "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", - "peer": true + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" }, "node_modules/@emotion/styled": { "version": "11.13.0", @@ -1978,14 +1973,12 @@ "node_modules/@emotion/unitless": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz", - "integrity": "sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==", - "peer": true + "integrity": "sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", - "peer": true, "peerDependencies": { "react": ">=16.8.0" } @@ -1993,14 +1986,12 @@ "node_modules/@emotion/utils": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", - "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==", - "peer": true + "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" }, "node_modules/@emotion/weak-memoize": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", - "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", - "peer": true + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" }, "node_modules/@esbuild-plugins/node-globals-polyfill": { "version": "0.2.3", @@ -2486,6 +2477,28 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.5.tgz", + "integrity": "sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA==", + "dependencies": { + "@floating-ui/utils": "^0.2.5" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.8.tgz", + "integrity": "sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.5" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.5.tgz", + "integrity": "sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==" + }, "node_modules/@fontsource/jost": { "version": "5.0.18", "resolved": "https://registry.npmjs.org/@fontsource/jost/-/jost-5.0.18.tgz", @@ -2870,9 +2883,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.18.0.tgz", - "integrity": "sha512-L3jkqmqoSVBVKHfpGZmLrex0lxR5SucGA0sUfFzGctehw+S/ggL9L/0NnC5mw6P8HUWpFZ3nQw3cRApjjWx9Sw==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.0.tgz", + "integrity": "sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA==", "engines": { "node": ">=14.0.0" } @@ -3674,8 +3687,7 @@ "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "peer": true + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" }, "node_modules/@types/parse5": { "version": "6.0.3", @@ -3686,8 +3698,7 @@ "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "devOptional": true + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/qs": { "version": "6.9.15", @@ -3705,7 +3716,6 @@ "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "devOptional": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -3720,6 +3730,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -4993,9 +5011,9 @@ } }, "node_modules/axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.3.tgz", + "integrity": "sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -5021,7 +5039,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "peer": true, "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -6430,7 +6447,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "peer": true, "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -9164,8 +9180,7 @@ "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "peer": true + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" }, "node_modules/find-up": { "version": "5.0.0", @@ -9861,6 +9876,11 @@ "he": "bin/he" } }, + "node_modules/hi-base32": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz", + "integrity": "sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==" + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -11560,9 +11580,9 @@ } }, "node_modules/luxon": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", - "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", + "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==", "engines": { "node": ">=12" } @@ -11693,6 +11713,11 @@ "node": ">= 0.6" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -12758,9 +12783,9 @@ } }, "node_modules/postcss": { - "version": "8.4.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", - "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "dev": true, "funding": [ { @@ -13310,11 +13335,11 @@ } }, "node_modules/react-router": { - "version": "6.25.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.25.1.tgz", - "integrity": "sha512-u8ELFr5Z6g02nUtpPAggP73Jigj1mRePSwhS/2nkTrlPU5yEkH1vYzWNyvSnSzeeE2DNqWdH+P8OhIh9wuXhTw==", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.0.tgz", + "integrity": "sha512-wVQq0/iFYd3iZ9H2l3N3k4PL8EEHcb0XlU2Na8nEwmiXgIUElEH6gaJDtUQxJ+JFzmIXaQjfdpcGWaM6IoQGxg==", "dependencies": { - "@remix-run/router": "1.18.0" + "@remix-run/router": "1.19.0" }, "engines": { "node": ">=14.0.0" @@ -13324,12 +13349,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.25.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.25.1.tgz", - "integrity": "sha512-0tUDpbFvk35iv+N89dWNrJp+afLgd+y4VtorJZuOCXK0kkCWjEvb3vTJM++SYvMEpbVwXKf3FjeVveVEb6JpDQ==", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.0.tgz", + "integrity": "sha512-RRGUIiDtLrkX3uYcFiCIxKFWMcWQGMojpYZfcstc63A1+sSnVgILGIm9gNUA6na3Fm1QuPGSBQH2EMbAZOnMsQ==", "dependencies": { - "@remix-run/router": "1.18.0", - "react-router": "6.25.1" + "@remix-run/router": "1.19.0", + "react-router": "6.26.0" }, "engines": { "node": ">=14.0.0" @@ -13339,6 +13364,26 @@ "react-dom": ">=16.8" } }, + "node_modules/react-select": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", + "integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-smooth": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", @@ -14803,8 +14848,7 @@ "node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", - "peer": true + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, "node_modules/supports-color": { "version": "5.5.0", @@ -15480,6 +15524,19 @@ } } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sidecar": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", @@ -15578,13 +15635,13 @@ } }, "node_modules/vite": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.5.tgz", - "integrity": "sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz", + "integrity": "sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==", "dev": true, "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.39", + "postcss": "^8.4.40", "rollup": "^4.13.0" }, "bin": { @@ -15604,6 +15661,7 @@ "less": "*", "lightningcss": "^1.21.0", "sass": "*", + "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -15621,6 +15679,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, @@ -16219,7 +16280,6 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "peer": true, "engines": { "node": ">= 6" } diff --git a/client/package.json b/client/package.json index 5ef0b34c5c..f3e9efdff7 100644 --- a/client/package.json +++ b/client/package.json @@ -35,13 +35,14 @@ "@fontsource/jost": "^5.0.18", "@fortawesome/free-solid-svg-icons": "^6.6.0", "@fortawesome/react-fontawesome": "^0.2.2", - "axios": "^1.7.2", + "axios": "^1.7.3", "better-react-mathjax": "^2.0.3", "browser-image-resizer": "^2.4.1", "copy-to-clipboard": "^3.3.3", "cssesc": "^3.0.0", + "hi-base32": "^0.5.1", "js-cookie": "^3.0.5", - "luxon": "^3.4.4", + "luxon": "^3.5.0", "math-expressions": "^2.0.0-alpha64", "nanoid": "^5.0.7", "papaparse": "^5.4.1", @@ -51,8 +52,9 @@ "react-dropzone": "^14.2.3", "react-icons": "4.8.0", "react-qrcode-logo": "^3.0.0", - "react-router": "^6.25.1", - "react-router-dom": "^6.25.1", + "react-router": "^6.26.0", + "react-router-dom": "^6.26.0", + "react-select": "^5.8.0", "recharts": "^2.12.7", "styled-components": "5.3.11", "swiper": "^9.4.1" @@ -85,7 +87,7 @@ "rollup": "^2.71.1", "rollup-plugin-polyfill-node": "^0.13.0", "rollup-plugin-terser": "^7.0.2", - "vite": "^5.3.5", + "vite": "^5.4.0", "vite-plugin-mpa": "^1.2.0", "vite-plugin-static-copy": "^1.0.6" }, diff --git a/client/src/Tools/_framework/Paths/Activities.tsx b/client/src/Tools/_framework/Paths/Activities.tsx index 4bbdc94a00..6354d378f4 100644 --- a/client/src/Tools/_framework/Paths/Activities.tsx +++ b/client/src/Tools/_framework/Paths/Activities.tsx @@ -16,6 +16,8 @@ import { Input, Spacer, Show, + Hide, + Spinner, } from "@chakra-ui/react"; import React, { useEffect, useRef, useState } from "react"; import { @@ -28,20 +30,30 @@ import { } from "react-router-dom"; import { RiEmotionSadLine } from "react-icons/ri"; -import ContentCard from "../../../Widgets/ContentCard"; +import ContentCard, { contentCardActions } from "../../../Widgets/ContentCard"; import axios from "axios"; -import MoveContentToFolder from "../ToolPanels/MoveContentToFolder"; -import { ContentSettingsDrawer } from "../ToolPanels/ContentSettingsDrawer"; +import MoveContentToFolder, { + moveContentActions, +} from "../ToolPanels/MoveContentToFolder"; +import { + contentSettingsActions, + ContentSettingsDrawer, +} from "../ToolPanels/ContentSettingsDrawer"; +import { + assignmentSettingsActions, + AssignmentSettingsDrawer, +} from "../ToolPanels/AssignmentSettingsDrawer"; import { AssignmentStatus, ContentStructure, DoenetmlVersion, License, LicenseCode, + UserInfo, } from "./ActivityEditor"; import { DateTime } from "luxon"; import { MdClose, MdOutlineSearch } from "react-icons/md"; -import { AssignmentSettingsDrawer } from "../ToolPanels/AssignmentSettingsDrawer"; +import { ShareDrawer, shareDrawerActions } from "../ToolPanels/ShareDrawer"; // what is a better solution than this? let folderJustCreated = -1; // if a folder was just created, set autoFocusName true for the card with the matching id @@ -50,35 +62,31 @@ export async function action({ request, params }) { const formData = await request.formData(); let formObj = Object.fromEntries(formData); - if (formObj._action == "update general") { - //Don't let name be blank - let name = formObj?.name?.trim(); - if (name == "") { - name = "Untitled"; - } + let resultCS = await contentSettingsActions({ formObj }); + if (resultCS) { + return resultCS; + } - let learningOutcomes; - if (formObj.learningOutcomes) { - learningOutcomes = JSON.parse(formObj.learningOutcomes); - } + let resultSD = await shareDrawerActions({ formObj }); + if (resultSD) { + return resultSD; + } + let resultAS = await assignmentSettingsActions({ formObj }); + if (resultAS) { + return resultAS; + } - await axios.post("/api/updateContentSettings", { - name, - imagePath: formObj.imagePath, - id: formObj.id, - learningOutcomes, - }); + let resultCC = await contentCardActions({ formObj }); + if (resultCC) { + return resultCC; + } - if (formObj.doenetmlVersionId) { - // TODO: handle other updates to just a document - await axios.post("/api/updateDocumentSettings", { - docId: formObj.docId, - doenetmlVersionId: formObj.doenetmlVersionId, - }); - } + let resultMC = await moveContentActions({ formObj }); + if (resultMC) { + return resultMC; + } - return true; - } else if (formObj?._action == "Add Activity") { + if (formObj?._action == "Add Activity") { //Create an activity and redirect to the editor for it let { data } = await axios.post( `/api/createActivity/${params.folderId ?? ""}`, @@ -120,80 +128,6 @@ export async function action({ request, params }) { desiredPosition: formObj.desiredPosition, }); return true; - } else if (formObj._action == "update title") { - //Don't let name be blank - let name = formObj?.cardTitle?.trim(); - if (name == "") { - name = "Untitled " + (formObj.isFolder ? "Folder" : "Activity"); - } - await axios.post(`/api/updateContentName`, { - id: Number(formObj.id), - name, - }); - return true; - } else if (formObj._action == "open assignment") { - let closeAt: DateTime; - if (formObj.duration === "custom") { - closeAt = DateTime.fromISO(formObj.customCloseAt); - } else { - closeAt = DateTime.fromSeconds( - Math.round(DateTime.now().toSeconds() / 60) * 60, - ).plus(JSON.parse(formObj.duration)); - } - await axios.post("/api/openAssignmentWithCode", { - activityId: Number(formObj.activityId), - closeAt, - }); - return true; - } else if (formObj._action == "update assignment close time") { - const closeAt = DateTime.fromISO(formObj.closeAt); - await axios.post("/api/updateAssignmentSettings", { - activityId: Number(formObj.activityId), - closeAt, - }); - return true; - } else if (formObj._action == "close assignment") { - await axios.post("/api/closeAssignmentWithCode", { - activityId: Number(formObj.activityId), - }); - return true; - } else if (formObj._action == "unassign activity") { - try { - await axios.post("/api/unassignActivity", { - activityId: Number(formObj.activityId), - }); - } catch (e) { - alert("Unable to unassign activity"); - } - return true; - } else if (formObj._action == "make content public") { - if (formObj.isFolder === "true") { - await axios.post("/api/makeFolderPublic", { - id: Number(formObj.id), - licenseCode: formObj.licenseCode, - }); - } else { - await axios.post("/api/makeActivityPublic", { - id: Number(formObj.id), - licenseCode: formObj.licenseCode, - }); - } - return true; - } else if (formObj._action == "make content private") { - if (formObj.isFolder === "true") { - await axios.post("/api/makeFolderPrivate", { - id: Number(formObj.id), - }); - } else { - await axios.post("/api/makeActivityPrivate", { - id: Number(formObj.id), - }); - } - return true; - } else if (formObj._action == "go to data") { - return redirect(`/assignmentData/${formObj.activityId}`); - } else if (formObj?._action == "noop") { - return true; } throw Error(`Action "${formObj?._action}" not defined or not handled.`); @@ -217,7 +151,7 @@ export async function loader({ params, request }) { if (data.notMe) { return redirect( - `/publicActivities/${params.userId}${params.folderId ? "/" + params.folderId : ""}`, + `/sharedActivities/${params.userId}${params.folderId ? "/" + params.folderId : ""}`, ); } } @@ -260,6 +194,12 @@ export function Activities() { onClose: settingsOnClose, } = useDisclosure(); + const { + isOpen: sharingIsOpen, + onOpen: sharingOnOpen, + onClose: sharingOnClose, + } = useDisclosure(); + const { isOpen: assignmentSettingsAreOpen, onOpen: assignmentSettingsOnOpen, @@ -270,6 +210,8 @@ export function Activities() { const folderSettingsRef = useRef(null); const finalFocusRef = useRef(null); + const [haveContentSpinner, setHaveContentSpinner] = useState(false); + const [searchOpen, setSearchOpen] = useState(false); const [searchString, setSearchString] = useState(query ?? ""); const searchRef = useRef(null); @@ -282,13 +224,25 @@ export function Activities() { } }, [searchOpen]); + useEffect(() => { + setHaveContentSpinner(false); + }, [content]); + const navigate = useNavigate(); const [moveToFolderContent, setMoveToFolderContent] = useState<{ id: number; isPublic: boolean; + isShared: boolean; + sharedWith: UserInfo[]; licenseCode: LicenseCode | null; - }>({ id: -1, isPublic: false, licenseCode: null }); + }>({ + id: -1, + isPublic: false, + isShared: false, + sharedWith: [], + licenseCode: null, + }); const { isOpen: moveToFolderIsOpen, @@ -296,9 +250,8 @@ export function Activities() { onClose: moveToFolderOnClose, } = useDisclosure(); - const [displaySettingsTab, setSettingsDisplayTab] = useState< - "general" | "share" - >("general"); + const [displaySettingsTab, setSettingsDisplayTab] = + useState<"general">("general"); useEffect(() => { document.title = `Activities - Doenet`; @@ -313,6 +266,8 @@ export function Activities() { assignmentStatus, isFolder, isPublic, + isShared, + sharedWith, licenseCode, parentFolderId, }: { @@ -322,6 +277,8 @@ export function Activities() { assignmentStatus: AssignmentStatus; isFolder?: boolean; isPublic: boolean; + isShared: boolean; + sharedWith: UserInfo[]; licenseCode: LicenseCode | null; parentFolderId: number | null; }) { @@ -382,7 +339,13 @@ export function Activities() { { - setMoveToFolderContent({ id, isPublic, licenseCode }); + setMoveToFolderContent({ + id, + isPublic, + isShared, + sharedWith, + licenseCode, + }); moveToFolderOnOpen(); }} > @@ -417,8 +380,7 @@ export function Activities() { data-test="Share Menu Item" onClick={() => { setSettingsContentId(id); - setSettingsDisplayTab("share"); - settingsOnOpen(); + sharingOnOpen(); }} > Share @@ -481,12 +443,23 @@ export function Activities() { id={settingsContentId} contentData={contentData} allDoenetmlVersions={allDoenetmlVersions} - allLicenses={allLicenses} finalFocusRef={finalFocusRef} fetcher={fetcher} displayTab={displaySettingsTab} /> ) : null; + + let shareDrawer = + contentData && settingsContentId ? ( + + ) : null; let assignmentDrawer = contentData && settingsContentId ? ( {settingsDrawer} + {shareDrawer} {assignmentDrawer}