diff --git a/package-lock.json b/package-lock.json index d8f3037e8b..08970a8957 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,10 @@ "version": "0.1.0", "license": "AGPL-3.0", "dependencies": { + "@dnd-kit/core": "^6.1.0", "@dnd-kit/modifiers": "^7.0.0", "@dnd-kit/sortable": "^8.0.0", + "@dnd-kit/utilities": "^3.2.2", "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", "@edx/frontend-component-ai-translations": "^2.0.0", "@edx/frontend-component-footer": "^13.0.2", @@ -34,6 +36,7 @@ "@openedx-plugins/course-app-teams": "file:plugins/course-apps/teams", "@openedx-plugins/course-app-wiki": "file:plugins/course-apps/wiki", "@openedx-plugins/course-app-xpert_unit_summary": "file:plugins/course-apps/xpert_unit_summary", + "@openedx/paragon": "^21.5.7", "@reduxjs/toolkit": "1.9.7", "@tanstack/react-query": "4.36.1", "broadcast-channel": "^7.0.0", @@ -1998,7 +2001,6 @@ "version": "7.23.9", "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.23.9.tgz", "integrity": "sha512-oeOFTrYWdWXCvXGB5orvMTJ6gCZ9I6FBjR+M38iKNXCsPxr4xT0RTdg5uz1H7QP8pp74IzPtwritEr+JscqHXQ==", - "peer": true, "dependencies": { "core-js-pure": "^3.30.2", "regenerator-runtime": "^0.14.0" @@ -2010,8 +2012,7 @@ "node_modules/@babel/runtime-corejs3/node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "peer": true + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/@babel/runtime/node_modules/regenerator-runtime": { "version": "0.14.1", @@ -4915,7 +4916,6 @@ "version": "21.13.1", "resolved": "https://registry.npmjs.org/@openedx/paragon/-/paragon-21.13.1.tgz", "integrity": "sha512-sLL+Z3ZWIRM6x+OrKZV0S7/SQpEcSeRcDm7E3FzhsnAWudsJCTELvSW+84uy/8dwV7mJhttsBPqQEtNafbCyYA==", - "peer": true, "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/react-fontawesome": "^0.1.18", @@ -4961,7 +4961,6 @@ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz", "integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==", "hasInstallScript": true, - "peer": true, "engines": { "node": ">=6" } @@ -4971,7 +4970,6 @@ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz", "integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==", "hasInstallScript": true, - "peer": true, "dependencies": { "@fortawesome/fontawesome-common-types": "6.5.1" }, @@ -4983,7 +4981,6 @@ "version": "0.1.19", "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.19.tgz", "integrity": "sha512-Hyb+lB8T18cvLNX0S3llz7PcSOAJMLwiVKBuuzwM/nI5uoBw+gQjnf9il0fR1C3DKOI5Kc79pkJ4/xB0Uw9aFQ==", - "peer": true, "dependencies": { "prop-types": "^15.8.1" }, @@ -4996,7 +4993,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -5004,14 +5000,12 @@ "node_modules/@openedx/paragon/node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", - "peer": true + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" }, "node_modules/@openedx/paragon/node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -5030,7 +5024,6 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "peer": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -5042,7 +5035,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "peer": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -5053,7 +5045,6 @@ "version": "8.2.0", "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.2.0.tgz", "integrity": "sha512-iagCqVrw4QSjhxKp3I/YK6+ODkWY6G+YPElvdYKiUUbywwh9Ds0M7r26Fj2/7dWFFbOpcGnJE6uE7aMck8j5Qg==", - "peer": true, "dependencies": { "hyphenate-style-name": "^1.0.0", "matchmediaquery": "^0.3.0", @@ -5075,7 +5066,6 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], - "peer": true, "bin": { "uuid": "dist/bin/uuid" } @@ -5186,7 +5176,6 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz", "integrity": "sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q==", - "peer": true, "peerDependencies": { "react": ">=16.3.2" } @@ -5195,7 +5184,6 @@ "version": "0.4.15", "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.15.tgz", "integrity": "sha512-cZFXYTxbpzYcieq/mBwSyXgqnGMHoBVh3J7MU0CCoIB4NRZxV9/TuwTBAaLMqpNhC3zTPMCgkQ5Ey07L02Xmcw==", - "peer": true, "dependencies": { "dequal": "^2.0.3" }, @@ -5851,8 +5839,7 @@ "node_modules/@types/invariant": { "version": "2.2.37", "resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.37.tgz", - "integrity": "sha512-IwpIMieE55oGWiXkQPSBY1nw1nFs6bsKXTFskNY8sdS17K24vyEBRQZEwlRS7ZmXCWnJcQtbxWzly+cODWGs2A==", - "peer": true + "integrity": "sha512-IwpIMieE55oGWiXkQPSBY1nw1nFs6bsKXTFskNY8sdS17K24vyEBRQZEwlRS7ZmXCWnJcQtbxWzly+cODWGs2A==" }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", @@ -6028,7 +6015,6 @@ "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==", - "peer": true, "dependencies": { "@types/react": "*" } @@ -6095,8 +6081,7 @@ "node_modules/@types/warning": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", - "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", - "peer": true + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==" }, "node_modules/@types/ws": { "version": "8.5.10", @@ -6600,7 +6585,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.3.tgz", "integrity": "sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==", - "peer": true, "dependencies": { "tslib": "^2.0.0" }, @@ -6799,8 +6783,7 @@ "node_modules/assert-ok": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-ok/-/assert-ok-1.0.0.tgz", - "integrity": "sha512-lCvYmCpMl8c1tp9ynExhoDEk0gGW43SVVC3RE1VYrrVKhNMy8GHfdiwZdoIM6a605s56bUAbENQxtOC0uZp3wg==", - "peer": true + "integrity": "sha512-lCvYmCpMl8c1tp9ynExhoDEk0gGW43SVVC3RE1VYrrVKhNMy8GHfdiwZdoIM6a605s56bUAbENQxtOC0uZp3wg==" }, "node_modules/assign-symbols": { "version": "1.0.0", @@ -7323,8 +7306,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "peer": true + ] }, "node_modules/batch": { "version": "0.6.1", @@ -7351,7 +7333,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "peer": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -7362,7 +7343,6 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -7436,7 +7416,6 @@ "url": "https://opencollective.com/bootstrap" } ], - "peer": true, "peerDependencies": { "jquery": "1.9.1 - 3", "popper.js": "^1.16.1" @@ -7554,7 +7533,6 @@ "url": "https://feross.org/support" } ], - "peer": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -7713,7 +7691,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/cast-array/-/cast-array-1.0.1.tgz", "integrity": "sha512-EiqtV+M9L42wd0IRgYjgVGDq7vdNBUUrdecd03QReJp8pIr59o2A1b0XfP+aCUlzLKx2E7zVetaogeJCtiHa+w==", - "peer": true, "dependencies": { "isarray": "0.0.1" } @@ -7721,8 +7698,7 @@ "node_modules/cast-array/node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "peer": true + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" }, "node_modules/chalk": { "version": "4.1.2", @@ -7750,14 +7726,12 @@ "node_modules/chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "peer": true + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, "node_modules/child_process": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", - "integrity": "sha512-Wmza/JzL0SiWz7kl6MhIKT5ceIlnFPJX+lwUGj7Clhy5MMldsSoJR0+uvRzOS5Kv45Mq7t1PoE8TsOA9bzvb6g==", - "peer": true + "integrity": "sha512-Wmza/JzL0SiWz7kl6MhIKT5ceIlnFPJX+lwUGj7Clhy5MMldsSoJR0+uvRzOS5Kv45Mq7t1PoE8TsOA9bzvb6g==" }, "node_modules/chokidar": { "version": "3.6.0", @@ -7879,7 +7853,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "peer": true, "dependencies": { "restore-cursor": "^3.1.0" }, @@ -7891,7 +7864,6 @@ "version": "2.9.2", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "peer": true, "engines": { "node": ">=6" }, @@ -7903,7 +7875,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "peer": true, "engines": { "node": ">= 10" } @@ -7943,7 +7914,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "peer": true, "engines": { "node": ">=0.8" } @@ -8787,7 +8757,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "peer": true, "dependencies": { "clone": "^1.0.2" }, @@ -8919,8 +8888,7 @@ "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", - "peer": true + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, "node_modules/detect-port-alt": { "version": "1.1.6", @@ -9163,7 +9131,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/email-prop-type/-/email-prop-type-3.0.1.tgz", "integrity": "sha512-tONZGMEOOkadp5OBftuVXU8DsceWmINxYK+pqPFB4LT5ODjrPX/esel3WGqbV7d6in5/MnZE4n4QcqOr4gh7dg==", - "peer": true, "dependencies": { "email-validator": "^2.0.4" } @@ -10280,7 +10247,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "peer": true, "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -10433,7 +10399,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "peer": true, "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -10448,7 +10413,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "peer": true, "engines": { "node": ">=0.8.0" } @@ -10522,7 +10486,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -10637,7 +10600,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-1.0.1.tgz", "integrity": "sha512-4YEXPTg9tATXwaVTpzHxT7GgO+Xot+VAoBSfXakUXXvQIXID0xv43GkZNDXkzWLYW1L9hrbHZ1CQjfT/svK9zA==", - "peer": true, "dependencies": { "tslib": "^2.0.3" }, @@ -10668,7 +10630,6 @@ "version": "4.7.0", "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", "integrity": "sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==", - "peer": true, "engines": { "node": ">=0.10.3" } @@ -11020,7 +10981,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "peer": true, "engines": { "node": ">=6" } @@ -11765,8 +11725,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "peer": true + ] }, "node_modules/ignore": { "version": "5.3.1", @@ -11862,7 +11821,6 @@ "version": "7.4.0", "resolved": "https://registry.npmjs.org/imask/-/imask-7.4.0.tgz", "integrity": "sha512-fU6mCo5YiTeDI8aVreuOKLOWxXIrRVnuQhZQXbjhwHxQb3GOQyCtlDGMyHxu2gq//LnKDxTwDBq1teRHmkzA3Q==", - "peer": true, "dependencies": { "@babel/runtime-corejs3": "^7.23.9" }, @@ -12043,7 +12001,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "peer": true, "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -12121,7 +12078,6 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "peer": true, "dependencies": { "loose-envify": "^1.0.0" } @@ -12389,7 +12345,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "peer": true, "engines": { "node": ">=8" } @@ -12629,7 +12584,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "peer": true, "engines": { "node": ">=10" }, @@ -14564,14 +14518,12 @@ "node_modules/lodash.uniqby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", - "peer": true + "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==" }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "peer": true, "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -14633,7 +14585,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mailto-link/-/mailto-link-2.0.0.tgz", "integrity": "sha512-b5FErkZ4t6mpH1IFZSw7Mm2IQHXQ2R0/5Q4xd7Rv8dVkWvE54mFG/UW7HjfFazXFjXTNsM+dSX2tTeIDrV9K9A==", - "peer": true, "dependencies": { "assert-ok": "~1.0.0", "cast-array": "~1.0.1", @@ -15083,8 +15034,7 @@ "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "peer": true + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/mux.js": { "version": "6.0.1", @@ -15376,8 +15326,7 @@ "node_modules/object-filter": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/object-filter/-/object-filter-1.0.2.tgz", - "integrity": "sha512-NahvP2vZcy1ZiiYah30CEPw0FpDcSkSePJBMpzl5EQgCmISijiGuJm3SPYp7U+Lf2TljyaIw3E5EgkEx/TNEVA==", - "peer": true + "integrity": "sha512-NahvP2vZcy1ZiiYah30CEPw0FpDcSkSePJBMpzl5EQgCmISijiGuJm3SPYp7U+Lf2TljyaIw3E5EgkEx/TNEVA==" }, "node_modules/object-inspect": { "version": "1.13.1", @@ -15604,7 +15553,6 @@ "version": "5.4.1", "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "peer": true, "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -15627,7 +15575,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -16803,7 +16750,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", - "peer": true, "dependencies": { "react-is": "^16.3.2", "warning": "^4.0.0" @@ -16933,7 +16879,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.0.1.tgz", "integrity": "sha512-uIw3iRvHnk9to1blJCG3BTc+Ro56CBowJXKmNNAm3RulvPBzWLRqKSiiDk+IplJhsydwtuNMHi8UGQFcCLVfkA==", - "peer": true, "dependencies": { "decode-uri-component": "^0.2.0", "filter-obj": "^1.1.0", @@ -16951,7 +16896,6 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "peer": true, "engines": { "node": ">=0.10" } @@ -17035,7 +16979,6 @@ "version": "1.6.8", "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.6.8.tgz", "integrity": "sha512-yD6uN78XlFOkETQp6GRuVe0s5509x3XYx8PfPbirwFTYCj5/RfmSs9YZGCwkUrhZNFzj7tZPdpb+3k50mK1E4g==", - "peer": true, "dependencies": { "@babel/runtime": "^7.14.0", "@restart/context": "^2.1.4", @@ -17063,14 +17006,12 @@ "node_modules/react-bootstrap/node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", - "peer": true + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" }, "node_modules/react-clientside-effect": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz", "integrity": "sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==", - "peer": true, "dependencies": { "@babel/runtime": "^7.12.13" }, @@ -17082,7 +17023,6 @@ "version": "5.6.1", "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", - "peer": true, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" @@ -17251,7 +17191,6 @@ "version": "2.9.8", "resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.9.8.tgz", "integrity": "sha512-nLrUCTF8/BWGaWV00wvmIOPe56HTLWtqjqwWebHE80jB0fCMsm/Cl2zbp8ulbCoe5BOU7bWSCg5YhkYhDxykWw==", - "peer": true, "dependencies": { "@babel/runtime": "^7.0.0", "focus-lock": "^1.0.1", @@ -17274,7 +17213,6 @@ "version": "3.9.1", "resolved": "https://registry.npmjs.org/react-focus-on/-/react-focus-on-3.9.1.tgz", "integrity": "sha512-IYo2j4mgNpZEJNv+/XzZs3S3xhJbR+AFop092h4OMW7sbFpIMVWxp/Z61V/gfpsgOi7VnoSFXP2bfOWWkjjtOw==", - "peer": true, "dependencies": { "aria-hidden": "^1.2.2", "react-focus-lock": "^2.9.4", @@ -17320,7 +17258,6 @@ "version": "7.4.0", "resolved": "https://registry.npmjs.org/react-imask/-/react-imask-7.4.0.tgz", "integrity": "sha512-U7O2IhIKIGF0ch16xBinwbWGfsgeDyM3KcftD8/bWLuES+KQOjv8wCjX2QZNiAqsZ3FgSembaJmqAN8XlB5LbA==", - "peer": true, "dependencies": { "imask": "^7.4.0", "prop-types": "^15.8.1" @@ -17336,7 +17273,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "peer": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -17397,14 +17333,12 @@ "node_modules/react-lifecycles-compat": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", - "peer": true + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, "node_modules/react-loading-skeleton": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/react-loading-skeleton/-/react-loading-skeleton-3.4.0.tgz", "integrity": "sha512-1oJEBc9+wn7BbkQQk7YodlYEIjgeR+GrRjD+QXkVjwZN7LGIcAFHrx4NhT7UHGBxNY1+zax3c+Fo6XQM4R7CgA==", - "peer": true, "peerDependencies": { "react": ">=16.8.0" } @@ -17426,7 +17360,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.2.1.tgz", "integrity": "sha512-GLLSOLWr21CqtJn8geSwQfoJufdt3mfdsnIiQswouuQ2MMPns+ihZklxvsTDKD3cR2tF8ELbi5xUsvqVhR6WvA==", - "peer": true, "dependencies": { "@babel/runtime": "^7.13.8", "@popperjs/core": "^2.11.6", @@ -17464,8 +17397,7 @@ "node_modules/react-proptype-conditional-require": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/react-proptype-conditional-require/-/react-proptype-conditional-require-1.0.4.tgz", - "integrity": "sha512-nopsRn7KnGgazBe2c3H2+Kf+Csp6PGDRLiBkYEDMKY8o/EIgft/WnIm/OnAKTawZiLnJXHAqhpFBddvs6NiXlw==", - "peer": true + "integrity": "sha512-nopsRn7KnGgazBe2c3H2+Kf+Csp6PGDRLiBkYEDMKY8o/EIgft/WnIm/OnAKTawZiLnJXHAqhpFBddvs6NiXlw==" }, "node_modules/react-redux": { "version": "7.2.9", @@ -17508,7 +17440,6 @@ "version": "2.5.7", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==", - "peer": true, "dependencies": { "react-remove-scroll-bar": "^2.3.4", "react-style-singleton": "^2.2.1", @@ -17533,7 +17464,6 @@ "version": "2.3.4", "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz", "integrity": "sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==", - "peer": true, "dependencies": { "react-style-singleton": "^2.2.1", "tslib": "^2.0.0" @@ -17623,7 +17553,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", - "peer": true, "dependencies": { "get-nonce": "^1.0.0", "invariant": "^2.2.4", @@ -17646,7 +17575,6 @@ "version": "7.8.0", "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==", - "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" @@ -18164,7 +18092,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "peer": true, "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -18238,7 +18165,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "peer": true, "engines": { "node": ">=0.12.0" } @@ -18277,7 +18203,6 @@ "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -19490,7 +19415,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", - "peer": true, "engines": { "node": ">=6" } @@ -19593,7 +19517,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", - "peer": true, "engines": { "node": ">=4" } @@ -20184,8 +20107,7 @@ "node_modules/tabbable": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", - "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==", - "peer": true + "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==" }, "node_modules/table": { "version": "6.8.1", @@ -20356,8 +20278,7 @@ "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "peer": true + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, "node_modules/thunky": { "version": "1.1.0", @@ -20383,7 +20304,6 @@ "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "peer": true, "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -20749,7 +20669,6 @@ "version": "7.2.1", "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", - "peer": true, "dependencies": { "@babel/runtime": "^7.6.3", "@types/react": ">=16.9.11", @@ -21008,7 +20927,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.1.tgz", "integrity": "sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==", - "peer": true, "dependencies": { "tslib": "^2.0.0" }, @@ -21066,7 +20984,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", - "peer": true, "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" @@ -21274,7 +21191,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "peer": true, "dependencies": { "defaults": "^1.0.3" } diff --git a/package.json b/package.json index d79f64d38b..3dcf95ccc7 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,10 @@ "url": "https://github.com/openedx/frontend-app-course-authoring/issues" }, "dependencies": { + "@dnd-kit/core": "^6.1.0", "@dnd-kit/modifiers": "^7.0.0", "@dnd-kit/sortable": "^8.0.0", + "@dnd-kit/utilities": "^3.2.2", "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", "@edx/frontend-component-ai-translations": "^2.0.0", "@edx/frontend-component-footer": "^13.0.2", @@ -53,14 +55,15 @@ "@fortawesome/react-fontawesome": "0.2.0", "@openedx-plugins/course-app-calculator": "file:plugins/course-apps/calculator", "@openedx-plugins/course-app-edxnotes": "file:plugins/course-apps/edxnotes", + "@openedx-plugins/course-app-learning_assistant": "file:plugins/course-apps/learning_assistant", "@openedx-plugins/course-app-live": "file:plugins/course-apps/live", "@openedx-plugins/course-app-ora_settings": "file:plugins/course-apps/ora_settings", "@openedx-plugins/course-app-proctoring": "file:plugins/course-apps/proctoring", "@openedx-plugins/course-app-progress": "file:plugins/course-apps/progress", "@openedx-plugins/course-app-teams": "file:plugins/course-apps/teams", "@openedx-plugins/course-app-wiki": "file:plugins/course-apps/wiki", - "@openedx-plugins/course-app-learning_assistant": "file:plugins/course-apps/learning_assistant", "@openedx-plugins/course-app-xpert_unit_summary": "file:plugins/course-apps/xpert_unit_summary", + "@openedx/paragon": "^21.5.7", "@reduxjs/toolkit": "1.9.7", "@tanstack/react-query": "4.36.1", "broadcast-channel": "^7.0.0", diff --git a/src/course-outline/CourseOutline.jsx b/src/course-outline/CourseOutline.jsx index 7bf1acf9a5..ff0f0185f3 100644 --- a/src/course-outline/CourseOutline.jsx +++ b/src/course-outline/CourseOutline.jsx @@ -120,7 +120,7 @@ const CourseOutline = ({ courseId }) => { const restoreSectionList = () => { setSections(() => [...sectionsList]); - } + }; const { isShow: isShowProcessingNotification, @@ -150,13 +150,11 @@ const CourseOutline = ({ courseId }) => { * @returns {void} */ const updateSubsectionOrderByIndex = (section, moveDetails) => { - let newSubsections; - let sectionsCopy; const { fn, args, sectionId } = moveDetails; if (!args) { return; } - [sectionsCopy, newSubsections] = fn(...args); + const [sectionsCopy, newSubsections] = fn(...args); if (newSubsections && sectionId) { setSections(sectionsCopy); handleSubsectionDragAndDrop( @@ -175,13 +173,13 @@ const CourseOutline = ({ courseId }) => { * @returns {void} */ const updateUnitOrderByIndex = (section, moveDetails) => { - let newUnits; - let sectionsCopy; - const { fn, args, sectionId, subsectionId } = moveDetails; + const { + fn, args, sectionId, subsectionId, + } = moveDetails; if (!args) { return; } - [sectionsCopy, newUnits] = fn(...args); + const [sectionsCopy, newUnits] = fn(...args); if (newUnits && sectionId && subsectionId) { setSections(sectionsCopy); handleUnitDragAndDrop( @@ -327,7 +325,7 @@ const CourseOutline = ({ courseId }) => { [...sections], sectionIndex, section, - section.childInfo.children + section.childInfo.children, )} isSelfPaced={statusBarData.isSelfPaced} isCustomRelativeDatesActive={isCustomRelativeDatesActive} diff --git a/src/course-outline/CourseOutline.test.jsx b/src/course-outline/CourseOutline.test.jsx index 039048e6c3..1a07353072 100644 --- a/src/course-outline/CourseOutline.test.jsx +++ b/src/course-outline/CourseOutline.test.jsx @@ -1,7 +1,6 @@ import { act, render, waitFor, fireEvent, within, } from '@testing-library/react'; -import userEvent from '@testing-library/user-event' import { IntlProvider } from '@edx/frontend-platform/i18n'; import { AppProvider } from '@edx/frontend-platform/react'; import { initializeMockApp } from '@edx/frontend-platform'; @@ -95,9 +94,8 @@ jest.mock('@dnd-kit/core', () => ({ closestCorners: jest.fn(), })); -const sleep = (ms) => { - return new Promise((resolve) => setTimeout(resolve, ms)); -} +// eslint-disable-next-line no-promise-executor-return +const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const RootWrapper = () => ( @@ -1536,7 +1534,9 @@ describe('', () => { axiosMock .onPut(getCourseItemApiUrl(store.getState().courseOutline.sectionsList[0].id)) .reply(200, { dummy: 'value' }); - const expectedSection = moveSubsection([...courseOutlineIndexMock.courseStructure.childInfo.children], 0, 0, 1)[0][0]; + const expectedSection = moveSubsection([ + ...courseOutlineIndexMock.courseStructure.childInfo.children, + ], 0, 0, 1)[0][0]; axiosMock .onGet(getXBlockApiUrl(section.id)) .reply(200, expectedSection); @@ -1573,7 +1573,7 @@ describe('', () => { .onPut(getCourseItemApiUrl(firstSection.id)) .reply(200, { dummy: 'value' }); const expectedSections = moveSubsectionOver([ - ...courseOutlineIndexMock.courseStructure.childInfo.children + ...courseOutlineIndexMock.courseStructure.childInfo.children, ], 1, 0, 0, firstSection.childInfo.children.length + 1)[0]; axiosMock .onGet(getXBlockApiUrl(firstSection.id)) @@ -1610,7 +1610,7 @@ describe('', () => { .onPut(getCourseItemApiUrl(secondSection.id)) .reply(200, { dummy: 'value' }); const expectedSections = moveSubsectionOver([ - ...courseOutlineIndexMock.courseStructure.childInfo.children + ...courseOutlineIndexMock.courseStructure.childInfo.children, ], 0, lastSubsectionIdx, 1, 0)[0]; axiosMock .onGet(getXBlockApiUrl(section.id)) @@ -1742,7 +1742,7 @@ describe('', () => { .onPut(getCourseItemApiUrl(firstSubsection.id)) .reply(200, { dummy: 'value' }); const expectedSections = moveUnitOver([ - ...courseOutlineIndexMock.courseStructure.childInfo.children + ...courseOutlineIndexMock.courseStructure.childInfo.children, ], 1, 1, 0, 1, 0, firstSubsection.childInfo.children.length)[0]; axiosMock .onGet(getXBlockApiUrl(section.id)) @@ -1785,7 +1785,7 @@ describe('', () => { 0, 0, firstSection.childInfo.children.length - 1, - firstSectionLastSubsection.childInfo.children.length + firstSectionLastSubsection.childInfo.children.length, )[0]; axiosMock .onGet(getXBlockApiUrl(firstSection.id)) @@ -1801,9 +1801,9 @@ describe('', () => { // move first unit to last position of prev subsection const moveUpButton = await within(unitElement).findByTestId('unit-card-header__menu-move-up-button'); await act(async () => fireEvent.click(moveUpButton)); - const firstSectionSubsectionsStore = store.getState().courseOutline.sectionsList[0].childInfo.children; - const firstSectionLastSubsectionUnits = firstSectionSubsectionsStore[firstSectionSubsectionsStore.length - 1].childInfo.children; - expect(firstSectionLastSubsectionUnits[firstSectionLastSubsectionUnits.length - 1].id).toBe(unit.id); + const firstSectionSubStore = store.getState().courseOutline.sectionsList[0].childInfo.children; + const firstSectionLastSubUnits = firstSectionSubStore[firstSectionSubStore.length - 1].childInfo.children; + expect(firstSectionLastSubUnits[firstSectionLastSubUnits.length - 1].id).toBe(unit.id); const secondSubUnits = store.getState().courseOutline.sectionsList[1].childInfo.children[0].childInfo.children; expect(secondSubUnits.length).toBe(subsection.childInfo.children.length - 1); }); @@ -1826,7 +1826,7 @@ describe('', () => { .onPut(getCourseItemApiUrl(subsection.id)) .reply(200, { dummy: 'value' }); const expectedSections = moveUnitOver([ - ...courseOutlineIndexMock.courseStructure.childInfo.children + ...courseOutlineIndexMock.courseStructure.childInfo.children, ], 1, 0, lastUnitIdx, 1, 1, 0)[0]; axiosMock .onGet(getXBlockApiUrl(section.id)) @@ -1871,7 +1871,7 @@ describe('', () => { lastUnitIdx, 2, 0, - 0 + 0, )[0]; axiosMock .onGet(getXBlockApiUrl(secondSection.id)) @@ -1887,9 +1887,9 @@ describe('', () => { // move first unit to last position of prev subsection const moveDownButton = await within(unitElement).findByTestId('unit-card-header__menu-move-down-button'); await act(async () => fireEvent.click(moveDownButton)); - const secondSectionSubsectionsStore = store.getState().courseOutline.sectionsList[1].childInfo.children; - const secondSectionLastSubsectionUnits = secondSectionSubsectionsStore[secondSectionSubsectionsStore.length - 1].childInfo.children; - expect(secondSectionLastSubsectionUnits.length).toBe(secondSectionLastSubsection.childInfo.children.length - 1); + const secondSectionSubStore = store.getState().courseOutline.sectionsList[1].childInfo.children; + const secondSectionLastSubUnits = secondSectionSubStore[secondSectionSubStore.length - 1].childInfo.children; + expect(secondSectionLastSubUnits.length).toBe(secondSectionLastSubsection.childInfo.children.length - 1); const thirdSubUnits = store.getState().courseOutline.sectionsList[2].childInfo.children[0].childInfo.children; expect(thirdSubUnits[0].id).toBe(unit.id); }); @@ -1951,7 +1951,9 @@ describe('', () => { axiosMock .onPut(getCourseItemApiUrl(section.id)) .reply(200, { dummy: 'value' }); - const expectedSection = moveSubsection([...courseOutlineIndexMock.courseStructure.childInfo.children], 0, 1, 0)[0][0]; + const expectedSection = moveSubsection([ + ...courseOutlineIndexMock.courseStructure.childInfo.children, + ], 0, 1, 0)[0][0]; axiosMock .onGet(getXBlockApiUrl(section.id)) .reply(200, expectedSection); diff --git a/src/course-outline/data/slice.js b/src/course-outline/data/slice.js index 1adafc4f61..3e6eaf611f 100644 --- a/src/course-outline/data/slice.js +++ b/src/course-outline/data/slice.js @@ -101,9 +101,7 @@ const slice = createSlice({ state.savingStatus = payload.status; }, updateSectionList: (state, { payload }) => { - state.sectionsList = state.sectionsList.map((section) => { - return section.id in payload ? payload[section.id] : section - }); + state.sectionsList = state.sectionsList.map((section) => (section.id in payload ? payload[section.id] : section)); }, setCurrentItem: (state, { payload }) => { state.currentItem = payload; @@ -114,22 +112,6 @@ const slice = createSlice({ state.sectionsList = [...sectionsList]; }, - reorderSubsectionList: (state, { payload }) => { - const { sectionId, subsectionListIds } = payload; - const sections = [...state.sectionsList]; - const i = sections.findIndex(section => section.id === sectionId); - sections[i].childInfo.children.sort((a, b) => subsectionListIds.indexOf(a.id) - subsectionListIds.indexOf(b.id)); - state.sectionsList = [...sections]; - }, - reorderUnitList: (state, { payload }) => { - const { sectionId, subsectionId, unitListIds } = payload; - const sections = [...state.sectionsList]; - const i = sections.findIndex(section => section.id === sectionId); - const j = sections[i].childInfo.children.findIndex(subsection => subsection.id === subsectionId); - const subsection = sections[i].childInfo.children[j]; - subsection.childInfo.children.sort((a, b) => unitListIds.indexOf(a.id) - unitListIds.indexOf(b.id)); - state.sectionsList = [...sections]; - }, setCurrentSection: (state, { payload }) => { state.currentSection = payload; }, diff --git a/src/course-outline/data/thunk.js b/src/course-outline/data/thunk.js index 7af9d371d5..30b0dea367 100644 --- a/src/course-outline/data/thunk.js +++ b/src/course-outline/data/thunk.js @@ -50,8 +50,6 @@ import { deleteUnit, duplicateSection, reorderSectionList, - reorderSubsectionList, - reorderUnitList, updateClipboardContent, setPasteFiles, } from './slice'; @@ -178,11 +176,12 @@ export function fetchCourseSectionQuery(sectionIds, shouldScroll = false) { dispatch(updateFetchSectionLoadingStatus({ status: RequestStatus.IN_PROGRESS })); try { const sections = {}; - for (let sectionId of sectionIds) { - const data = await getCourseItem(sectionId); + const results = await Promise.all(sectionIds.map((sectionId) => getCourseItem(sectionId))); + results.forEach((data) => { + // eslint-disable-next-line no-param-reassign data.shouldScroll = shouldScroll; sections[data.id] = data; - } + }); dispatch(updateSectionList(sections)); dispatch(updateFetchSectionLoadingStatus({ status: RequestStatus.SUCCESSFUL })); } catch (error) { @@ -565,7 +564,7 @@ export function setSubsectionOrderListQuery( sectionId, prevSectionId, subsectionListIds, - restoreCallback + restoreCallback, ) { return async (dispatch) => { dispatch(setBlockOrderListQuery( @@ -589,7 +588,7 @@ export function setUnitOrderListQuery( subsectionId, prevSectionId, unitListIds, - restoreCallback + restoreCallback, ) { return async (dispatch) => { dispatch(setBlockOrderListQuery( diff --git a/src/course-outline/drag-helper/DragContextProvider.jsx b/src/course-outline/drag-helper/DragContextProvider.jsx index 7aac66342f..d03cfa4cba 100644 --- a/src/course-outline/drag-helper/DragContextProvider.jsx +++ b/src/course-outline/drag-helper/DragContextProvider.jsx @@ -20,7 +20,7 @@ const DragContextProvider = ({ activeId, overId, children }) => { DragContextProvider.defaultProps = { activeId: '', overId: '', -} +}; DragContextProvider.propTypes = { activeId: PropTypes.string, diff --git a/src/course-outline/drag-helper/DraggableList.jsx b/src/course-outline/drag-helper/DraggableList.jsx index 661cadfeab..385cb1d333 100644 --- a/src/course-outline/drag-helper/DraggableList.jsx +++ b/src/course-outline/drag-helper/DraggableList.jsx @@ -3,7 +3,6 @@ import PropTypes from 'prop-types'; import { DndContext, - DragOverlay, closestCorners, KeyboardSensor, PointerSensor, @@ -12,11 +11,9 @@ import { } from '@dnd-kit/core'; import { arrayMove, - SortableContext, sortableKeyboardCoordinates, - verticalListSortingStrategy, } from '@dnd-kit/sortable'; -import { restrictToVerticalAxis } from '@dnd-kit/modifiers' +import { restrictToVerticalAxis } from '@dnd-kit/modifiers'; import DragContextProvider from './DragContextProvider'; import { COURSE_BLOCK_NAMES } from '../constants'; @@ -45,7 +42,7 @@ const DraggableList = ({ }), ); const [activeId, setActiveId] = React.useState(); - const [overId, setOverId] = React.useState(); + const [currentOverId, setCurrentOverId] = React.useState(); const findItemInfo = (id) => { // search id in sections @@ -55,12 +52,13 @@ const DraggableList = ({ index: sectionIndex, item: items[sectionIndex], category: COURSE_BLOCK_NAMES.chapter.id, - parent: "root" + parent: 'root', }; } // search id in subsections - for (let [index, section] of items.entries()) { + for (let index = 0; index < items.length; index++) { + const section = items[index]; const subsectionIndex = section.childInfo.children.findIndex((subsection) => subsection.id === id); if (subsectionIndex !== -1) { return { @@ -68,14 +66,16 @@ const DraggableList = ({ item: section.childInfo.children[subsectionIndex], category: COURSE_BLOCK_NAMES.sequential.id, parentIndex: index, - parent: section + parent: section, }; } - }; + } // search id in units - for (let [index, section] of items.entries()) { - for (let [subIndex, subsection] of section.childInfo.children.entries()) { + for (let index = 0; index < items.length; index++) { + const section = items[index]; + for (let subIndex = 0; subIndex < section.childInfo.children.length; subIndex++) { + const subsection = section.childInfo.children[subIndex]; const unitIndex = subsection.childInfo.children.findIndex((unit) => unit.id === id); if (unitIndex !== -1) { return { @@ -86,12 +86,12 @@ const DraggableList = ({ parent: subsection, grandParentIndex: index, grandParent: section, - } + }; } - }; - }; + } + } return null; - } + }; const subsectionDragOver = (active, over, activeInfo, overInfo) => { if ( @@ -109,12 +109,12 @@ const DraggableList = ({ // We're at the root droppable of a container newIndex = overInfo.item.childInfo.children.length + 1; overSectionIndex = overInfo.index; - setOverId(overInfo.item.id); + setCurrentOverId(overInfo.item.id); } else { const modifier = dragHelpers.isBelowOverItem(active, over) ? 1 : 0; newIndex = overInfo.index >= 0 ? overInfo.index + modifier : overInfo.item.childInfo.children.length + 1; overSectionIndex = overInfo.parentIndex; - setOverId(overInfo.parent.id); + setCurrentOverId(overInfo.parent.id); } setSections((prev) => { @@ -130,7 +130,7 @@ const DraggableList = ({ if (prevContainerInfo.current === null || prevContainerInfo.current === undefined) { prevContainerInfo.current = activeInfo.parent.id; } - } + }; const unitDragOver = (active, over, activeInfo, overInfo) => { if ( @@ -150,13 +150,13 @@ const DraggableList = ({ newIndex = overInfo.item.childInfo.children.length + 1; overSubsectionIndex = overInfo.index; overSectionIndex = overInfo.parentIndex; - setOverId(overInfo.item.id); + setCurrentOverId(overInfo.item.id); } else { const modifier = dragHelpers.isBelowOverItem(active, over) ? 1 : 0; newIndex = overInfo.index >= 0 ? overInfo.index + modifier : overInfo.item.childInfo.children.length + 1; overSubsectionIndex = overInfo.parentIndex; overSectionIndex = overInfo.grandParentIndex; - setOverId(overInfo.parent.id); + setCurrentOverId(overInfo.parent.id); } setSections((prev) => { @@ -174,10 +174,10 @@ const DraggableList = ({ if (prevContainerInfo.current === null || prevContainerInfo.current === undefined) { prevContainerInfo.current = activeInfo.grandParent.id; } - } + }; const handleDragOver = (event) => { - const { active, over } = event; + const { active, over } = event; if (!active || !over) { return; } @@ -191,14 +191,16 @@ const DraggableList = ({ return; } switch (activeInfo.category) { - case COURSE_BLOCK_NAMES.sequential.id: - return subsectionDragOver(active, over, activeInfo, overInfo); - case COURSE_BLOCK_NAMES.vertical.id: - return unitDragOver(active, over, activeInfo, overInfo); - default: - break; + case COURSE_BLOCK_NAMES.sequential.id: + subsectionDragOver(active, over, activeInfo, overInfo); + break; + case COURSE_BLOCK_NAMES.vertical.id: + unitDragOver(active, over, activeInfo, overInfo); + break; + default: + break; } - } + }; const handleDragEnd = (event) => { const { active, over } = event; @@ -206,7 +208,7 @@ const DraggableList = ({ return; } setActiveId(null); - setOverId(null); + setCurrentOverId(null); const { id } = active; const { id: overId } = over; @@ -218,94 +220,92 @@ const DraggableList = ({ if ( activeInfo.category !== overInfo.category - || (activeInfo.parent !== "root" && activeInfo.parentIndex !== overInfo.parentIndex) + || (activeInfo.parent !== 'root' && activeInfo.parentIndex !== overInfo.parentIndex) ) { return; } - let currentItems = items; - if (activeInfo.parent !== 'root') { - currentItems = activeInfo.parent.childInfo.children; - } if (activeInfo.index !== overInfo.index || prevContainerInfo.current) { switch (activeInfo.category) { - case COURSE_BLOCK_NAMES.chapter.id: - setSections((prev) => { - const result = arrayMove(prev, activeInfo.index, overInfo.index); - handleSectionDragAndDrop(result.map(section => section.id), restoreSectionList); - return result; - }); - break; - case COURSE_BLOCK_NAMES.sequential.id: - setSections((prev) => { - const [prevCopy, result] = moveSubsection( - [...prev], - activeInfo.parentIndex, - activeInfo.index, - overInfo.index, - ); - handleSubsectionDragAndDrop( - activeInfo.parent.id, - prevContainerInfo.current, - result.map(subsection => subsection.id), - restoreSectionList, - ); - return prevCopy; - }); - break; - case COURSE_BLOCK_NAMES.vertical.id: - setSections((prev) => { - const [prevCopy, result] = moveUnit( - [...prev], - activeInfo.grandParentIndex, - activeInfo.parentIndex, - activeInfo.index, - overInfo.index, - ); - handleUnitDragAndDrop( - activeInfo.grandParent.id, - prevContainerInfo.current, - activeInfo.parent.id, - result.map(unit => unit.id), - restoreSectionList, - ); - return prevCopy; - }); - break; + case COURSE_BLOCK_NAMES.chapter.id: + setSections((prev) => { + const result = arrayMove(prev, activeInfo.index, overInfo.index); + handleSectionDragAndDrop(result.map(section => section.id), restoreSectionList); + return result; + }); + break; + case COURSE_BLOCK_NAMES.sequential.id: + setSections((prev) => { + const [prevCopy, result] = moveSubsection( + [...prev], + activeInfo.parentIndex, + activeInfo.index, + overInfo.index, + ); + handleSubsectionDragAndDrop( + activeInfo.parent.id, + prevContainerInfo.current, + result.map(subsection => subsection.id), + restoreSectionList, + ); + return prevCopy; + }); + break; + case COURSE_BLOCK_NAMES.vertical.id: + setSections((prev) => { + const [prevCopy, result] = moveUnit( + [...prev], + activeInfo.grandParentIndex, + activeInfo.parentIndex, + activeInfo.index, + overInfo.index, + ); + handleUnitDragAndDrop( + activeInfo.grandParent.id, + prevContainerInfo.current, + activeInfo.parent.id, + result.map(unit => unit.id), + restoreSectionList, + ); + return prevCopy; + }); + break; + default: + break; } prevContainerInfo.current = null; } - } + }; const handleDragStart = (event) => { const { active } = event; const { id } = active; setActiveId(id); - } + }; - const customClosestCorners = ({active, droppableContainers, droppableRects, ...args}) => { + const customClosestCorners = ({ + active, droppableContainers, droppableRects, ...args + }) => { const activeCategory = active.data?.current?.category; - droppableContainers = droppableContainers.filter( + const filteredContainers = droppableContainers.filter( (container) => { switch (activeCategory) { - case COURSE_BLOCK_NAMES.chapter.id: - return container.data?.current?.category === activeCategory; - break; - case COURSE_BLOCK_NAMES.sequential.id: - return [activeCategory, COURSE_BLOCK_NAMES.chapter.id].includes(container.data?.current?.category); - break; - case COURSE_BLOCK_NAMES.vertical.id: - return [activeCategory, COURSE_BLOCK_NAMES.sequential.id].includes(container.data?.current?.category); - break; - default: - return true; - break; + case COURSE_BLOCK_NAMES.chapter.id: + return container.data?.current?.category === activeCategory; + case COURSE_BLOCK_NAMES.sequential.id: + return [activeCategory, COURSE_BLOCK_NAMES.chapter.id].includes(container.data?.current?.category); + case COURSE_BLOCK_NAMES.vertical.id: + return [activeCategory, COURSE_BLOCK_NAMES.sequential.id].includes(container.data?.current?.category); + default: + return true; } - } + }, ); - return closestCorners({active, droppableContainers, droppableRects, ...args}); - } + return closestCorners({ + active, droppableContainers: filteredContainers, droppableRects, ...args, + }); + }; return ( - + {children} @@ -326,6 +326,10 @@ const DraggableList = ({ DraggableList.propTypes = { items: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.string.isRequired, + childInfo: PropTypes.shape({ + // eslint-disable-next-line react/forbid-prop-types + children: PropTypes.arrayOf(PropTypes.object).isRequired, + }).isRequired, })).isRequired, setSections: PropTypes.func.isRequired, restoreSectionList: PropTypes.func.isRequired, diff --git a/src/course-outline/drag-helper/SortableItem.jsx b/src/course-outline/drag-helper/SortableItem.jsx index e349569ab2..ffea67a849 100644 --- a/src/course-outline/drag-helper/SortableItem.jsx +++ b/src/course-outline/drag-helper/SortableItem.jsx @@ -3,7 +3,9 @@ import PropTypes from 'prop-types'; import { intlShape, injectIntl } from '@edx/frontend-platform/i18n'; import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; -import { Col, Icon, IconButtonWithTooltip, Row } from '@openedx/paragon'; +import { + Col, Icon, Row, +} from '@openedx/paragon'; import { DragIndicator } from '@openedx/paragon/icons'; import messages from './messages'; @@ -26,7 +28,6 @@ const SortableItem = ({ transition, isDragging, setActivatorNodeRef, - ...args } = useSortable({ id, data: { @@ -36,7 +37,7 @@ const SortableItem = ({ draggable: !isDraggable, droppable: !isDroppable, }, - animateLayoutChanges: () => false + animateLayoutChanges: () => false, }); const style = { @@ -68,7 +69,6 @@ const SortableItem = ({ aria-label={intl.formatMessage(messages.tooltipContent)} className="btn-icon btn-icon-secondary btn-icon-md" type="button" - role="button" {...attributes} {...listeners} > diff --git a/src/course-outline/drag-helper/utils.js b/src/course-outline/drag-helper/utils.js index 82c653b37f..efe1d7d956 100644 --- a/src/course-outline/drag-helper/utils.js +++ b/src/course-outline/drag-helper/utils.js @@ -2,32 +2,35 @@ import { arrayMove } from '@dnd-kit/sortable'; export const dragHelpers = { copyBlockChildren: (block) => { + // eslint-disable-next-line no-param-reassign block.childInfo = { ...block.childInfo }; + // eslint-disable-next-line no-param-reassign block.childInfo.children = [...block.childInfo.children]; return block; }, setBlockChildren: (block, children) => { + // eslint-disable-next-line no-param-reassign block.childInfo.children = children; return block; }, setBlockChild: (block, child, id) => { + // eslint-disable-next-line no-param-reassign block.childInfo.children[id] = child; return block; }, insertChild: (block, child, index) => { + // eslint-disable-next-line no-param-reassign block.childInfo.children = [ ...block.childInfo.children.slice(0, index), child, - ...block.childInfo.children.slice(index, block.childInfo.children.length) - ] + ...block.childInfo.children.slice(index, block.childInfo.children.length), + ]; return block; }, - isBelowOverItem: (active, over) => { - return over && - active.rect.current.translated && - active.rect.current.translated.top > - over.rect.top + over.rect.height; - } + isBelowOverItem: (active, over) => over + && active.rect.current.translated + && active.rect.current.translated.top + > over.rect.top + over.rect.height, }; export const moveSubsectionOver = ( @@ -45,13 +48,15 @@ export const moveSubsectionOver = ( activeSection = dragHelpers.setBlockChildren( activeSection, - activeSection.childInfo.children.filter((item) => item.id !== subsection.id) - ) + activeSection.childInfo.children.filter((item) => item.id !== subsection.id), + ); + // eslint-disable-next-line no-param-reassign prevCopy[activeSectionIdx] = activeSection; + // eslint-disable-next-line no-param-reassign prevCopy[overSectionIdx] = overSection; return [prevCopy, overSection.childInfo.children]; -} +}; export const moveUnitOver = ( prevCopy, @@ -62,9 +67,9 @@ export const moveUnitOver = ( overSubsectionIdx, newIndex, ) => { - let activeSection = dragHelpers.copyBlockChildren({ ...prevCopy[activeSectionIdx] }); + const activeSection = dragHelpers.copyBlockChildren({ ...prevCopy[activeSectionIdx] }); let activeSubsection = dragHelpers.copyBlockChildren( - { ...activeSection.childInfo.children[activeSubsectionIdx] } + { ...activeSection.childInfo.children[activeSubsectionIdx] }, ); let overSection = { ...prevCopy[overSectionIdx] }; @@ -74,22 +79,24 @@ export const moveUnitOver = ( overSection = dragHelpers.copyBlockChildren(overSection); let overSubsection = dragHelpers.copyBlockChildren( - { ...overSection.childInfo.children[overSubsectionIdx] } + { ...overSection.childInfo.children[overSubsectionIdx] }, ); const unit = activeSubsection.childInfo.children[activeUnitIdx]; - overSubsection = dragHelpers.insertChild( overSubsection, unit , newIndex); + overSubsection = dragHelpers.insertChild(overSubsection, unit, newIndex); overSection = dragHelpers.setBlockChild(overSection, overSubsection, overSubsectionIdx); activeSubsection = dragHelpers.setBlockChildren( activeSubsection, - activeSubsection.childInfo.children.filter((item) => item.id !== unit.id) - ) + activeSubsection.childInfo.children.filter((item) => item.id !== unit.id), + ); - prevCopy[activeSectionIdx] = dragHelpers.setBlockChild(activeSection, activeSubsection, activeSubsectionIdx);; + // eslint-disable-next-line no-param-reassign + prevCopy[activeSectionIdx] = dragHelpers.setBlockChild(activeSection, activeSubsection, activeSubsectionIdx); + // eslint-disable-next-line no-param-reassign prevCopy[overSectionIdx] = overSection; return [prevCopy, overSubsection.childInfo.children]; -} +}; export const moveSubsection = ( prevCopy, @@ -102,9 +109,10 @@ export const moveSubsection = ( const result = arrayMove(section.childInfo.children, currentIdx, newIdx); section = dragHelpers.setBlockChildren(section, result); + // eslint-disable-next-line no-param-reassign prevCopy[sectionIdx] = section; return [prevCopy, result]; -} +}; export const moveUnit = ( prevCopy, @@ -120,9 +128,10 @@ export const moveUnit = ( subsection = dragHelpers.setBlockChildren(subsection, result); section = dragHelpers.setBlockChild(section, subsection, subsectionIdx); + // eslint-disable-next-line no-param-reassign prevCopy[sectionIdx] = section; return [prevCopy, result]; -} +}; /** * Check if section can be moved by given step. @@ -155,11 +164,11 @@ export const possibleSubsectionMoves = (sections, sectionIndex, section, subsect sections, sectionIndex, index, - index+step, + index + step, ], - sectionId: section.id - } - } else if (step === -1 && index === 0 && sectionIndex > 0) { + sectionId: section.id, + }; + } if (step === -1 && index === 0 && sectionIndex > 0) { // move subsection to last position of previous section if (!sections[sectionIndex + step]?.actions?.childAddable) { // return if previous section doesn't allow adding subsections @@ -175,8 +184,8 @@ export const possibleSubsectionMoves = (sections, sectionIndex, section, subsect sections[sectionIndex + step].childInfo.children.length + 1, ], sectionId: sections[sectionIndex + step].id, - } - } else if (step === 1 && index === subsections.length - 1 && sectionIndex < sections.length - 1) { + }; + } if (step === 1 && index === subsections.length - 1 && sectionIndex < sections.length - 1) { // move subsection to first position of next section if (!sections[sectionIndex + step]?.actions?.childAddable) { // return if next section doesn't allow adding subsections @@ -192,8 +201,9 @@ export const possibleSubsectionMoves = (sections, sectionIndex, section, subsect 0, ], sectionId: sections[sectionIndex + step].id, - } + }; } + return {}; }; export const possibleUnitMoves = ( @@ -202,7 +212,7 @@ export const possibleUnitMoves = ( subsectionIndex, section, subsection, - units + units, ) => (index, step) => { if (!units[index].actions.draggable) { return {}; @@ -215,12 +225,12 @@ export const possibleUnitMoves = ( sectionIndex, subsectionIndex, index, - index+step, + index + step, ], sectionId: section.id, subsectionId: subsection.id, - } - } else if (step === -1 && index === 0) { + }; + } if (step === -1 && index === 0) { if (subsectionIndex > 0) { // move unit to last position of previous subsection inside same section. if (!sections[sectionIndex].childInfo.children[subsectionIndex + step]?.actions?.childAddable) { @@ -240,8 +250,8 @@ export const possibleUnitMoves = ( ], sectionId: section.id, subsectionId: sections[sectionIndex].childInfo.children[subsectionIndex + step].id, - } - } else if (sectionIndex > 0) { + }; + } if (sectionIndex > 0) { // move unit to last position of previous subsection inside previous section. const newSectionIndex = sectionIndex + step; if (sections[newSectionIndex].childInfo.children.length === 0) { @@ -266,7 +276,7 @@ export const possibleUnitMoves = ( ], sectionId: sections[newSectionIndex].id, subsectionId: sections[newSectionIndex].childInfo.children[newSubsectionIndex].id, - } + }; } } else if (step === 1 && index === units.length - 1) { if (subsectionIndex < sections[sectionIndex].childInfo.children.length - 1) { @@ -288,8 +298,8 @@ export const possibleUnitMoves = ( ], sectionId: section.id, subsectionId: sections[sectionIndex].childInfo.children[subsectionIndex + step].id, - } - } else if (sectionIndex < sections.length - 1) { + }; + } if (sectionIndex < sections.length - 1) { // move unit to first position of next subsection inside next section. const newSectionIndex = sectionIndex + step; if (sections[newSectionIndex].childInfo.children.length === 0) { @@ -314,9 +324,8 @@ export const possibleUnitMoves = ( ], sectionId: sections[newSectionIndex].id, subsectionId: sections[newSectionIndex].childInfo.children[newSubsectionIndex].id, - } + }; } } return {}; }; - diff --git a/src/course-outline/hooks.jsx b/src/course-outline/hooks.jsx index 4d31dce46e..83290de0ac 100644 --- a/src/course-outline/hooks.jsx +++ b/src/course-outline/hooks.jsx @@ -1,9 +1,8 @@ -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useNavigate } from 'react-router-dom'; import { useToggle } from '@openedx/paragon'; import { getConfig } from '@edx/frontend-platform'; -import { arrayMove } from '@dnd-kit/sortable'; import { RequestStatus } from '../data/constants'; import { COURSE_BLOCK_NAMES } from './constants'; @@ -252,7 +251,7 @@ const useCourseOutline = ({ courseId }) => { dispatch(setSectionOrderListQuery( courseId, sectionListIds, - restoreSectionList + restoreSectionList, )); }; @@ -266,7 +265,7 @@ const useCourseOutline = ({ courseId }) => { sectionId, prevSectionId, subsectionListIds, - restoreSectionList + restoreSectionList, )); }; diff --git a/src/course-outline/section-card/SectionCard.jsx b/src/course-outline/section-card/SectionCard.jsx index 32e47f6856..6e3f617f7c 100644 --- a/src/course-outline/section-card/SectionCard.jsx +++ b/src/course-outline/section-card/SectionCard.jsx @@ -236,6 +236,7 @@ SectionCard.propTypes = { section: PropTypes.shape({ id: PropTypes.string.isRequired, displayName: PropTypes.string.isRequired, + category: PropTypes.string.isRequired, published: PropTypes.bool.isRequired, hasChanges: PropTypes.bool.isRequired, visibilityState: PropTypes.string.isRequired, diff --git a/src/course-outline/subsection-card/SubsectionCard.jsx b/src/course-outline/subsection-card/SubsectionCard.jsx index 21ced567b3..8019042e5b 100644 --- a/src/course-outline/subsection-card/SubsectionCard.jsx +++ b/src/course-outline/subsection-card/SubsectionCard.jsx @@ -1,4 +1,6 @@ -import { useContext, useEffect, useState, useRef } from 'react'; +import { + useContext, useEffect, useState, useRef, +} from 'react'; import PropTypes from 'prop-types'; import { useDispatch } from 'react-redux'; import { useSearchParams } from 'react-router-dom'; @@ -241,6 +243,7 @@ SubsectionCard.propTypes = { subsection: PropTypes.shape({ id: PropTypes.string.isRequired, displayName: PropTypes.string.isRequired, + category: PropTypes.string.isRequired, published: PropTypes.bool.isRequired, hasChanges: PropTypes.bool.isRequired, visibilityState: PropTypes.string.isRequired, diff --git a/src/course-outline/unit-card/UnitCard.jsx b/src/course-outline/unit-card/UnitCard.jsx index 5af23e4c94..14b10687bc 100644 --- a/src/course-outline/unit-card/UnitCard.jsx +++ b/src/course-outline/unit-card/UnitCard.jsx @@ -188,6 +188,7 @@ UnitCard.propTypes = { unit: PropTypes.shape({ id: PropTypes.string.isRequired, displayName: PropTypes.string.isRequired, + category: PropTypes.string.isRequired, published: PropTypes.bool.isRequired, hasChanges: PropTypes.bool.isRequired, visibilityState: PropTypes.string.isRequired,