Compare commits
5 Commits
dependabot
...
PowerPlant
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd931338d8 | ||
|
|
f03d5afa0d | ||
|
|
910e17f75d | ||
|
|
2fa5cadf22 | ||
|
|
bd8221997e |
395
package-lock.json
generated
395
package-lock.json
generated
@@ -10,9 +10,9 @@
|
|||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@edx/brand": "npm:@edx/brand-openedx@1.2.0",
|
"@edx/brand": "npm:@edx/brand-openedx@1.2.0",
|
||||||
"@edx/frontend-component-footer": "12.3.0",
|
"@edx/frontend-component-footer": "12.4.0",
|
||||||
"@edx/frontend-component-header": "4.7.1",
|
"@edx/frontend-component-header": "4.7.1",
|
||||||
"@edx/frontend-platform": "5.4.0",
|
"@edx/frontend-platform": "5.6.1",
|
||||||
"@edx/paragon": "^20.44.0",
|
"@edx/paragon": "^20.44.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||||
"@fortawesome/free-brands-svg-icons": "5.15.4",
|
"@fortawesome/free-brands-svg-icons": "5.15.4",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"@fortawesome/react-fontawesome": "0.2.0",
|
"@fortawesome/react-fontawesome": "0.2.0",
|
||||||
"@pact-foundation/pact": "^11.0.2",
|
"@pact-foundation/pact": "^11.0.2",
|
||||||
"classnames": "2.3.2",
|
"classnames": "2.3.2",
|
||||||
"core-js": "3.32.2",
|
"core-js": "3.33.0",
|
||||||
"history": "5.3.0",
|
"history": "5.3.0",
|
||||||
"lodash.camelcase": "4.3.0",
|
"lodash.camelcase": "4.3.0",
|
||||||
"lodash.get": "4.4.2",
|
"lodash.get": "4.4.2",
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
"prop-types": "15.8.1",
|
"prop-types": "15.8.1",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
|
"react-error-boundary": "^4.0.11",
|
||||||
"react-helmet": "6.1.0",
|
"react-helmet": "6.1.0",
|
||||||
"react-redux": "7.2.9",
|
"react-redux": "7.2.9",
|
||||||
"react-router": "6.16.0",
|
"react-router": "6.16.0",
|
||||||
@@ -44,8 +45,8 @@
|
|||||||
"universal-cookie": "4.0.4"
|
"universal-cookie": "4.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "17.7.2",
|
"@commitlint/cli": "17.8.0",
|
||||||
"@commitlint/config-angular": "17.7.0",
|
"@commitlint/config-angular": "17.8.0",
|
||||||
"@edx/browserslist-config": "^1.1.1",
|
"@edx/browserslist-config": "^1.1.1",
|
||||||
"@edx/frontend-build": "12.9.17",
|
"@edx/frontend-build": "12.9.17",
|
||||||
"@edx/reactifex": "2.2.0",
|
"@edx/reactifex": "2.2.0",
|
||||||
@@ -127,16 +128,81 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.13",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
|
||||||
"integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
|
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/highlight": "^7.22.5"
|
"@babel/highlight": "^7.22.13",
|
||||||
|
"chalk": "^2.4.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@babel/code-frame/node_modules/ansi-styles": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^1.9.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/code-frame/node_modules/chalk": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^3.2.1",
|
||||||
|
"escape-string-regexp": "^1.0.5",
|
||||||
|
"supports-color": "^5.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/code-frame/node_modules/color-convert": {
|
||||||
|
"version": "1.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
|
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "1.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/code-frame/node_modules/color-name": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||||
|
},
|
||||||
|
"node_modules/@babel/code-frame/node_modules/escape-string-regexp": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/code-frame/node_modules/has-flag": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/code-frame/node_modules/supports-color": {
|
||||||
|
"version": "5.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||||
|
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||||
|
"dependencies": {
|
||||||
|
"has-flag": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@babel/compat-data": {
|
"node_modules/@babel/compat-data": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz",
|
||||||
@@ -208,11 +274,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/generator": {
|
"node_modules/@babel/generator": {
|
||||||
"version": "7.22.5",
|
"version": "7.23.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
|
||||||
"integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==",
|
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.22.5",
|
"@babel/types": "^7.23.0",
|
||||||
"@jridgewell/gen-mapping": "^0.3.2",
|
"@jridgewell/gen-mapping": "^0.3.2",
|
||||||
"@jridgewell/trace-mapping": "^0.3.17",
|
"@jridgewell/trace-mapping": "^0.3.17",
|
||||||
"jsesc": "^2.5.1"
|
"jsesc": "^2.5.1"
|
||||||
@@ -348,20 +414,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-environment-visitor": {
|
"node_modules/@babel/helper-environment-visitor": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.20",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
||||||
"integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
|
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-function-name": {
|
"node_modules/@babel/helper-function-name": {
|
||||||
"version": "7.22.5",
|
"version": "7.23.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
||||||
"integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
|
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.22.5",
|
"@babel/template": "^7.22.15",
|
||||||
"@babel/types": "^7.22.5"
|
"@babel/types": "^7.23.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -493,9 +559,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-split-export-declaration": {
|
"node_modules/@babel/helper-split-export-declaration": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
||||||
"integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==",
|
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.22.5"
|
"@babel/types": "^7.22.5"
|
||||||
},
|
},
|
||||||
@@ -512,9 +578,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-identifier": {
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.20",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||||
"integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
|
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
@@ -555,12 +621,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/highlight": {
|
"node_modules/@babel/highlight": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.20",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
|
||||||
"integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
|
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.22.5",
|
"@babel/helper-validator-identifier": "^7.22.20",
|
||||||
"chalk": "^2.0.0",
|
"chalk": "^2.4.2",
|
||||||
"js-tokens": "^4.0.0"
|
"js-tokens": "^4.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -632,9 +698,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.22.5",
|
"version": "7.23.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
|
||||||
"integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==",
|
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
},
|
},
|
||||||
@@ -1978,31 +2044,31 @@
|
|||||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
||||||
},
|
},
|
||||||
"node_modules/@babel/template": {
|
"node_modules/@babel/template": {
|
||||||
"version": "7.22.5",
|
"version": "7.22.15",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
|
||||||
"integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
|
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.22.5",
|
"@babel/code-frame": "^7.22.13",
|
||||||
"@babel/parser": "^7.22.5",
|
"@babel/parser": "^7.22.15",
|
||||||
"@babel/types": "^7.22.5"
|
"@babel/types": "^7.22.15"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/traverse": {
|
"node_modules/@babel/traverse": {
|
||||||
"version": "7.22.5",
|
"version": "7.23.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
|
||||||
"integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==",
|
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.22.5",
|
"@babel/code-frame": "^7.22.13",
|
||||||
"@babel/generator": "^7.22.5",
|
"@babel/generator": "^7.23.0",
|
||||||
"@babel/helper-environment-visitor": "^7.22.5",
|
"@babel/helper-environment-visitor": "^7.22.20",
|
||||||
"@babel/helper-function-name": "^7.22.5",
|
"@babel/helper-function-name": "^7.23.0",
|
||||||
"@babel/helper-hoist-variables": "^7.22.5",
|
"@babel/helper-hoist-variables": "^7.22.5",
|
||||||
"@babel/helper-split-export-declaration": "^7.22.5",
|
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||||
"@babel/parser": "^7.22.5",
|
"@babel/parser": "^7.23.0",
|
||||||
"@babel/types": "^7.22.5",
|
"@babel/types": "^7.23.0",
|
||||||
"debug": "^4.1.0",
|
"debug": "^4.1.0",
|
||||||
"globals": "^11.1.0"
|
"globals": "^11.1.0"
|
||||||
},
|
},
|
||||||
@@ -2011,12 +2077,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.22.5",
|
"version": "7.23.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
|
||||||
"integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
|
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-string-parser": "^7.22.5",
|
"@babel/helper-string-parser": "^7.22.5",
|
||||||
"@babel/helper-validator-identifier": "^7.22.5",
|
"@babel/helper-validator-identifier": "^7.22.20",
|
||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2044,14 +2110,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@commitlint/cli": {
|
"node_modules/@commitlint/cli": {
|
||||||
"version": "17.7.2",
|
"version": "17.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.8.0.tgz",
|
||||||
"integrity": "sha512-t3N7TZq7lOeqTOyEgfGcaltHqEJf7YDlPg75MldeVPPyz14jZq/+mbGF9tueDLFX8R6RwdymrN6D+U5XwZ8Iwg==",
|
"integrity": "sha512-D3LdyZYbiRyAChfJMNlAd9f2P9vNQ7GWbI9gN2o7L5hF07QJDqj4z/pcJF3PjDbJWOaUUXla287RdDmmKqH2WQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@commitlint/format": "^17.4.4",
|
"@commitlint/format": "^17.4.4",
|
||||||
"@commitlint/lint": "^17.7.0",
|
"@commitlint/lint": "^17.8.0",
|
||||||
"@commitlint/load": "^17.7.2",
|
"@commitlint/load": "^17.8.0",
|
||||||
"@commitlint/read": "^17.5.1",
|
"@commitlint/read": "^17.5.1",
|
||||||
"@commitlint/types": "^17.4.4",
|
"@commitlint/types": "^17.4.4",
|
||||||
"execa": "^5.0.0",
|
"execa": "^5.0.0",
|
||||||
@@ -2068,9 +2134,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@commitlint/config-angular": {
|
"node_modules/@commitlint/config-angular": {
|
||||||
"version": "17.7.0",
|
"version": "17.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@commitlint/config-angular/-/config-angular-17.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@commitlint/config-angular/-/config-angular-17.8.0.tgz",
|
||||||
"integrity": "sha512-ZWLgVw4se/vmNHfWiti3OIx295KgyCgZ5LjDeLFbHQe9WXMX3lhwnaeJkum4smsQhQaa3/JvufKzxV/3LDGMJA==",
|
"integrity": "sha512-3Jygi+j6AqbVbzZujQZqQhk1WPF4ipeh8MHcXlHa1humQQ2ROqfWUqdFlAxn9iIE93lbJz/ANGthJ9+k9sG7Zg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@commitlint/config-angular-type-enum": "^17.4.0"
|
"@commitlint/config-angular-type-enum": "^17.4.0"
|
||||||
@@ -2141,9 +2207,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@commitlint/is-ignored": {
|
"node_modules/@commitlint/is-ignored": {
|
||||||
"version": "17.7.0",
|
"version": "17.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.8.0.tgz",
|
||||||
"integrity": "sha512-043rA7m45tyEfW7Zv2vZHF++176MLHH9h70fnPoYlB1slKBeKl8BwNIlnPg4xBdRBVNPaCqvXxWswx2GR4c9Hw==",
|
"integrity": "sha512-8bR6rxNcWaNprPBdE4ePIOwbxutTQGOsRPYWssX+zjGxnEljzaZSGzFUOMxapYILlf8Tts/O1wPQgG549Rdvdg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@commitlint/types": "^17.4.4",
|
"@commitlint/types": "^17.4.4",
|
||||||
@@ -2154,12 +2220,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@commitlint/lint": {
|
"node_modules/@commitlint/lint": {
|
||||||
"version": "17.7.0",
|
"version": "17.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-17.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-17.8.0.tgz",
|
||||||
"integrity": "sha512-TCQihm7/uszA5z1Ux1vw+Nf3yHTgicus/+9HiUQk+kRSQawByxZNESeQoX9ujfVd3r4Sa+3fn0JQAguG4xvvbA==",
|
"integrity": "sha512-4ihwnqOY4TcJN6iz5Jv1LeYavvBllONwFyGxOIWmCT5s4PNMb43cws2TUdbXTZL1Vq59etGKd5LWYDFPVbs5EA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@commitlint/is-ignored": "^17.7.0",
|
"@commitlint/is-ignored": "^17.8.0",
|
||||||
"@commitlint/parse": "^17.7.0",
|
"@commitlint/parse": "^17.7.0",
|
||||||
"@commitlint/rules": "^17.7.0",
|
"@commitlint/rules": "^17.7.0",
|
||||||
"@commitlint/types": "^17.4.4"
|
"@commitlint/types": "^17.4.4"
|
||||||
@@ -2169,9 +2235,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@commitlint/load": {
|
"node_modules/@commitlint/load": {
|
||||||
"version": "17.7.2",
|
"version": "17.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@commitlint/load/-/load-17.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/@commitlint/load/-/load-17.8.0.tgz",
|
||||||
"integrity": "sha512-XA7WTnsjHZ4YH6ZYsrnxgLdXzriwMMq+utZUET6spbOEEIPBCDLdOQXS26P+v3TTO4hUHOEhzUquaBv3jbBixw==",
|
"integrity": "sha512-9VnGXYJCP4tXmR4YrwP8n5oX6T5ZsHfPQq6WuUQOvAI+QsDQMaTGgTRXr7us+xsjz+b+mMBSagogqfUx2aixyw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@commitlint/config-validator": "^17.6.7",
|
"@commitlint/config-validator": "^17.6.7",
|
||||||
@@ -2514,9 +2580,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@edx/frontend-component-footer": {
|
"node_modules/@edx/frontend-component-footer": {
|
||||||
"version": "12.3.0",
|
"version": "12.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-12.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-12.4.0.tgz",
|
||||||
"integrity": "sha512-ivCtioyP4SceYM4/ugVtif4c41Y+epA0NM7sSB/x6s9A/RTQXb2TY3fDc9lB3ah/0+pRwGVJJEVYkPAZ4JdC/g==",
|
"integrity": "sha512-DmAC8eTB4ARYlzBewzxWB3Afn9v8j9nSudqDd6LiXHUYDZ8Z7QPrMfmrmfDHllflVd22NvljmP2hp+WdtjkgMA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@edx/paragon": "^21.3.1",
|
"@edx/paragon": "^21.3.1",
|
||||||
"@fortawesome/fontawesome-svg-core": "6.4.2",
|
"@fortawesome/fontawesome-svg-core": "6.4.2",
|
||||||
@@ -2534,9 +2600,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@edx/frontend-component-footer/node_modules/@edx/paragon": {
|
"node_modules/@edx/frontend-component-footer/node_modules/@edx/paragon": {
|
||||||
"version": "21.3.1",
|
"version": "21.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-21.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-21.5.3.tgz",
|
||||||
"integrity": "sha512-bXTUaOEmT8XLnDQzYS8QLMvWK5K2BN4jHlx25lO8N0XWRQeDiQTdbx8OrEbv8QOPTlrv0an5MZc+qjlleJFObg==",
|
"integrity": "sha512-Xyq7gWLb4n8qWMsNBIPV3tZnOK0bBdHyqj8UVOrFbpBCSPlOES06qpcpT4IrtpfCh0LmUCBiIk5j9XMz3p6zaw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.1.1",
|
"@fortawesome/fontawesome-svg-core": "^6.1.1",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.18",
|
"@fortawesome/react-fontawesome": "^0.1.18",
|
||||||
@@ -2855,9 +2921,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@edx/frontend-platform": {
|
"node_modules/@edx/frontend-platform": {
|
||||||
"version": "5.4.0",
|
"version": "5.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-5.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-5.6.1.tgz",
|
||||||
"integrity": "sha512-cz9yQfHJk1PMQdhxeyIXXiBNqaG9dQZpcBgodmVlLnL/PeN1CuRVjjW98WlKYSrxoZAH5wdgUOr0hKRW3OyBAA==",
|
"integrity": "sha512-7MOIjGGYplVY7yHrSea90EkQ24UxKxRKU9FaihB41yUSL/Vin1txDuIn3059Xr+60QfIKRsym+LogXe9IZ47Dw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cospired/i18n-iso-languages": "4.1.0",
|
"@cospired/i18n-iso-languages": "4.1.0",
|
||||||
"@formatjs/intl-pluralrules": "4.3.3",
|
"@formatjs/intl-pluralrules": "4.3.3",
|
||||||
@@ -2944,9 +3010,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@edx/paragon": {
|
"node_modules/@edx/paragon": {
|
||||||
"version": "20.46.2",
|
"version": "20.46.3",
|
||||||
"resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.46.2.tgz",
|
"resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.46.3.tgz",
|
||||||
"integrity": "sha512-px+KS/BV1CbiMKgfVgUofyjJi4CHUCUOLRukJbT66VPPqWP4Xon5Rns6uohoratPXMg2kNN46v2L8wIwqKQ4Lw==",
|
"integrity": "sha512-cHxoxoOREVFbBqW9IRAtlIAQo1lcF9JJXkLoEw1Vam6oetKSa5Mc0SL5kykbV+1iRPP7kS8A0Csf5nRr0oolLQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.1.1",
|
"@fortawesome/fontawesome-svg-core": "^6.1.1",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.18",
|
"@fortawesome/react-fontawesome": "^0.1.18",
|
||||||
@@ -2981,21 +3047,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@edx/paragon/node_modules/@fortawesome/fontawesome-common-types": {
|
"node_modules/@edx/paragon/node_modules/@fortawesome/fontawesome-common-types": {
|
||||||
"version": "6.4.0",
|
"version": "6.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz",
|
||||||
"integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==",
|
"integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@edx/paragon/node_modules/@fortawesome/fontawesome-svg-core": {
|
"node_modules/@edx/paragon/node_modules/@fortawesome/fontawesome-svg-core": {
|
||||||
"version": "6.4.0",
|
"version": "6.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz",
|
||||||
"integrity": "sha512-Bertv8xOiVELz5raB2FlXDPKt+m94MQ3JgDfsVbrqNpLU9+UE2E18GKjLKw+d3XbeYPqg1pzyQKGsrzbw+pPaw==",
|
"integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-common-types": "6.4.0"
|
"@fortawesome/fontawesome-common-types": "6.4.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
@@ -5006,11 +5072,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@restart/hooks": {
|
"node_modules/@restart/hooks": {
|
||||||
"version": "0.4.9",
|
"version": "0.4.11",
|
||||||
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.9.tgz",
|
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.11.tgz",
|
||||||
"integrity": "sha512-3BekqcwB6Umeya+16XPooARn4qEPW6vNvwYnlofIYe6h9qG1/VeD7UvShCWx11eFz5ELYmwIEshz+MkPX3wjcQ==",
|
"integrity": "sha512-Ft/ncTULZN6ldGHiF/k5qt72O8JyRMOeg0tApvCni8LkoiEahO+z3TNxfXIVGy890YtWVDvJAl662dVJSJXvMw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dequal": "^2.0.2"
|
"dequal": "^2.0.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": ">=16.8.0"
|
"react": ">=16.8.0"
|
||||||
@@ -5644,9 +5710,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/react-transition-group": {
|
"node_modules/@types/react-transition-group": {
|
||||||
"version": "4.4.6",
|
"version": "4.4.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.7.tgz",
|
||||||
"integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==",
|
"integrity": "sha512-ICCyBl5mvyqYp8Qeq9B5G/fyBSRC0zx3XM3sCC6KkcMsNeAHqXBKkmat4GqdJET5jtYUpZXrxI5flve5qhi2Eg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
@@ -5710,9 +5776,9 @@
|
|||||||
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
|
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/warning": {
|
"node_modules/@types/warning": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.1.tgz",
|
||||||
"integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA=="
|
"integrity": "sha512-ywJmriP+nvjBKNBEMaNZgj2irZHoxcKeYcyMLbqhYKbDVn8yCIULy2Ol/tvIb37O3IBeZj3RU4tXqQTtGwoAMg=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/ws": {
|
"node_modules/@types/ws": {
|
||||||
"version": "8.5.5",
|
"version": "8.5.5",
|
||||||
@@ -7279,9 +7345,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001546",
|
"version": "1.0.30001549",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz",
|
||||||
"integrity": "sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==",
|
"integrity": "sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -7921,9 +7987,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/core-js": {
|
"node_modules/core-js": {
|
||||||
"version": "3.32.2",
|
"version": "3.33.0",
|
||||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.32.2.tgz",
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.33.0.tgz",
|
||||||
"integrity": "sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ==",
|
"integrity": "sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -10292,6 +10358,14 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/filter-obj": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/finalhandler": {
|
"node_modules/finalhandler": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
||||||
@@ -14563,9 +14637,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jquery": {
|
"node_modules/jquery": {
|
||||||
"version": "3.7.0",
|
"version": "3.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
|
||||||
"integrity": "sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ==",
|
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/js-base64": {
|
"node_modules/js-base64": {
|
||||||
@@ -15084,39 +15158,6 @@
|
|||||||
"node": ">= 12"
|
"node": ">= 12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mailto-link/node_modules/filter-obj": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mailto-link/node_modules/query-string": {
|
|
||||||
"version": "7.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.0.1.tgz",
|
|
||||||
"integrity": "sha512-uIw3iRvHnk9to1blJCG3BTc+Ro56CBowJXKmNNAm3RulvPBzWLRqKSiiDk+IplJhsydwtuNMHi8UGQFcCLVfkA==",
|
|
||||||
"dependencies": {
|
|
||||||
"decode-uri-component": "^0.2.0",
|
|
||||||
"filter-obj": "^1.1.0",
|
|
||||||
"split-on-first": "^1.0.0",
|
|
||||||
"strict-uri-encode": "^2.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mailto-link/node_modules/split-on-first": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/make-dir": {
|
"node_modules/make-dir": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
|
||||||
@@ -15791,9 +15832,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/object-code": {
|
"node_modules/object-code": {
|
||||||
"version": "1.2.4",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/object-code/-/object-code-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/object-code/-/object-code-1.3.0.tgz",
|
||||||
"integrity": "sha512-uGq4ETUuWe+GA586NXEriiaozNuff+YNFXlpD8cVrM1GoiuTZpCABP+bZCWDrvQDoCiSTyiWAFHD/HF/iwhb2w=="
|
"integrity": "sha512-PLplgvzuFhSPBuTX/mtaXEnU3c6g7qKflVVQbV9VWEnV/34iKeAX1jeDNCKq1OgGlsnkA/NjldCzTbHxa7Wj4A=="
|
||||||
},
|
},
|
||||||
"node_modules/object-copy": {
|
"node_modules/object-copy": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
@@ -17508,6 +17549,23 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/query-string": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-uIw3iRvHnk9to1blJCG3BTc+Ro56CBowJXKmNNAm3RulvPBzWLRqKSiiDk+IplJhsydwtuNMHi8UGQFcCLVfkA==",
|
||||||
|
"dependencies": {
|
||||||
|
"decode-uri-component": "^0.2.0",
|
||||||
|
"filter-obj": "^1.1.0",
|
||||||
|
"split-on-first": "^1.0.0",
|
||||||
|
"strict-uri-encode": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/querystringify": {
|
"node_modules/querystringify": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
||||||
@@ -17825,6 +17883,17 @@
|
|||||||
"react": ">= 16.8 || 18.0.0"
|
"react": ">= 16.8 || 18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-error-boundary": {
|
||||||
|
"version": "4.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.11.tgz",
|
||||||
|
"integrity": "sha512-U13ul67aP5DOSPNSCWQ/eO0AQEYzEFkVljULQIjMV0KlffTAhxuDoBKdO0pb/JZ8mDhMKFZ9NZi0BmLGUiNphw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.12.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-error-overlay": {
|
"node_modules/react-error-overlay": {
|
||||||
"version": "6.0.11",
|
"version": "6.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
|
||||||
@@ -17836,9 +17905,9 @@
|
|||||||
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
|
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
|
||||||
},
|
},
|
||||||
"node_modules/react-focus-lock": {
|
"node_modules/react-focus-lock": {
|
||||||
"version": "2.9.4",
|
"version": "2.9.5",
|
||||||
"resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.9.5.tgz",
|
||||||
"integrity": "sha512-7pEdXyMseqm3kVjhdVH18sovparAzLg5h6WvIx7/Ck3ekjhrrDMEegHSa3swwC8wgfdd7DIdUVRGeiHT9/7Sgg==",
|
"integrity": "sha512-h6vrdgUbsH2HeD5I7I3Cx1PPrmwGuKYICS+kB9m+32X/9xHRrAbxgvaBpG7BFBN9h3tO+C3qX1QAVESmi4CiIA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.0.0",
|
"@babel/runtime": "^7.0.0",
|
||||||
"focus-lock": "^0.11.6",
|
"focus-lock": "^0.11.6",
|
||||||
@@ -17858,12 +17927,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-focus-on": {
|
"node_modules/react-focus-on": {
|
||||||
"version": "3.8.1",
|
"version": "3.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-focus-on/-/react-focus-on-3.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-focus-on/-/react-focus-on-3.9.1.tgz",
|
||||||
"integrity": "sha512-fQcBx+SZMgXoRL+69r5+ic4bdVgqaCeKeoFPra8yhcSuL/3unWavfdirEFBGgH71K+RiocMTS6DETHcX0SlOZg==",
|
"integrity": "sha512-IYo2j4mgNpZEJNv+/XzZs3S3xhJbR+AFop092h4OMW7sbFpIMVWxp/Z61V/gfpsgOi7VnoSFXP2bfOWWkjjtOw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aria-hidden": "^1.2.2",
|
"aria-hidden": "^1.2.2",
|
||||||
"react-focus-lock": "^2.9.2",
|
"react-focus-lock": "^2.9.4",
|
||||||
"react-remove-scroll": "^2.5.6",
|
"react-remove-scroll": "^2.5.6",
|
||||||
"react-style-singleton": "^2.2.0",
|
"react-style-singleton": "^2.2.0",
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1",
|
||||||
@@ -20116,6 +20185,14 @@
|
|||||||
"wbuf": "^1.7.3"
|
"wbuf": "^1.7.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/split-on-first": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/split-string": {
|
"node_modules/split-string": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
|
||||||
@@ -21563,9 +21640,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/uuid": {
|
"node_modules/uuid": {
|
||||||
"version": "9.0.0",
|
"version": "9.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||||
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
|
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
"bin": {
|
"bin": {
|
||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
|
|||||||
11
package.json
11
package.json
@@ -29,9 +29,9 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@edx/brand": "npm:@edx/brand-openedx@1.2.0",
|
"@edx/brand": "npm:@edx/brand-openedx@1.2.0",
|
||||||
"@edx/frontend-component-footer": "12.3.0",
|
"@edx/frontend-component-footer": "12.4.0",
|
||||||
"@edx/frontend-component-header": "4.7.1",
|
"@edx/frontend-component-header": "4.7.1",
|
||||||
"@edx/frontend-platform": "5.4.0",
|
"@edx/frontend-platform": "5.6.1",
|
||||||
"@edx/paragon": "^20.44.0",
|
"@edx/paragon": "^20.44.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||||
"@fortawesome/free-brands-svg-icons": "5.15.4",
|
"@fortawesome/free-brands-svg-icons": "5.15.4",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
"@fortawesome/react-fontawesome": "0.2.0",
|
"@fortawesome/react-fontawesome": "0.2.0",
|
||||||
"@pact-foundation/pact": "^11.0.2",
|
"@pact-foundation/pact": "^11.0.2",
|
||||||
"classnames": "2.3.2",
|
"classnames": "2.3.2",
|
||||||
"core-js": "3.32.2",
|
"core-js": "3.33.0",
|
||||||
"history": "5.3.0",
|
"history": "5.3.0",
|
||||||
"lodash.camelcase": "4.3.0",
|
"lodash.camelcase": "4.3.0",
|
||||||
"lodash.get": "4.4.2",
|
"lodash.get": "4.4.2",
|
||||||
@@ -49,6 +49,7 @@
|
|||||||
"prop-types": "15.8.1",
|
"prop-types": "15.8.1",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
|
"react-error-boundary": "^4.0.11",
|
||||||
"react-helmet": "6.1.0",
|
"react-helmet": "6.1.0",
|
||||||
"react-redux": "7.2.9",
|
"react-redux": "7.2.9",
|
||||||
"react-router": "6.16.0",
|
"react-router": "6.16.0",
|
||||||
@@ -63,8 +64,8 @@
|
|||||||
"universal-cookie": "4.0.4"
|
"universal-cookie": "4.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "17.7.2",
|
"@commitlint/cli": "17.8.0",
|
||||||
"@commitlint/config-angular": "17.7.0",
|
"@commitlint/config-angular": "17.8.0",
|
||||||
"@edx/browserslist-config": "^1.1.1",
|
"@edx/browserslist-config": "^1.1.1",
|
||||||
"@edx/frontend-build": "12.9.17",
|
"@edx/frontend-build": "12.9.17",
|
||||||
"@edx/reactifex": "2.2.0",
|
"@edx/reactifex": "2.2.0",
|
||||||
|
|||||||
93
plugins/Plugin.jsx
Normal file
93
plugins/Plugin.jsx
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, {
|
||||||
|
useEffect, useMemo, useState,
|
||||||
|
} from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { ErrorBoundary } from 'react-error-boundary';
|
||||||
|
import { logError } from '@edx/frontend-platform/logging';
|
||||||
|
import {
|
||||||
|
dispatchMountedEvent, dispatchReadyEvent, dispatchUnmountedEvent, useHostEvent,
|
||||||
|
} from './data/hooks';
|
||||||
|
import { PLUGIN_RESIZE } from './data/constants';
|
||||||
|
|
||||||
|
// see example-plugin-app/src/PluginOne.jsx for example of customizing errorFallback
|
||||||
|
function errorFallbackDefault() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>
|
||||||
|
Oops! An error occurred. Please refresh the screen to try again.
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/function-component-definition
|
||||||
|
export default function Plugin({
|
||||||
|
children, className, style, ready, errorFallbackProp,
|
||||||
|
}) {
|
||||||
|
const [dimensions, setDimensions] = useState({
|
||||||
|
width: null,
|
||||||
|
height: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const finalStyle = useMemo(() => ({
|
||||||
|
...dimensions,
|
||||||
|
...style,
|
||||||
|
}), [dimensions, style]);
|
||||||
|
|
||||||
|
const errorFallback = errorFallbackProp || errorFallbackDefault;
|
||||||
|
|
||||||
|
// Error logging function
|
||||||
|
// Need to confirm: When an error is caught here, the logging will be sent to the child MFE's logging service
|
||||||
|
const logErrorToService = (error, info) => {
|
||||||
|
logError(error, { stack: info.componentStack });
|
||||||
|
};
|
||||||
|
|
||||||
|
useHostEvent(PLUGIN_RESIZE, ({ payload }) => {
|
||||||
|
setDimensions({
|
||||||
|
width: payload.width,
|
||||||
|
height: payload.height,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatchMountedEvent();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
dispatchUnmountedEvent();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (ready) {
|
||||||
|
dispatchReadyEvent();
|
||||||
|
}
|
||||||
|
}, [ready]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className} style={finalStyle}>
|
||||||
|
<ErrorBoundary
|
||||||
|
FallbackComponent={errorFallback}
|
||||||
|
onError={logErrorToService}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ErrorBoundary>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Plugin.propTypes = {
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
className: PropTypes.string,
|
||||||
|
errorFallbackProp: PropTypes.func,
|
||||||
|
ready: PropTypes.bool,
|
||||||
|
style: PropTypes.object, // eslint-disable-line
|
||||||
|
};
|
||||||
|
|
||||||
|
Plugin.defaultProps = {
|
||||||
|
className: null,
|
||||||
|
errorFallbackProp: null,
|
||||||
|
style: {},
|
||||||
|
ready: true,
|
||||||
|
};
|
||||||
42
plugins/PluginContainer.jsx
Normal file
42
plugins/PluginContainer.jsx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
|
import PluginContainerIframe from './PluginContainerIframe';
|
||||||
|
|
||||||
|
import {
|
||||||
|
IFRAME_PLUGIN,
|
||||||
|
} from './data/constants';
|
||||||
|
import { pluginConfigShape } from './data/shapes';
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/function-component-definition
|
||||||
|
export default function PluginContainer({ config, ...props }) {
|
||||||
|
if (config === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this will allow for future plugin types to be inserted in the PluginErrorBoundary
|
||||||
|
let renderer = null;
|
||||||
|
switch (config.type) {
|
||||||
|
case IFRAME_PLUGIN:
|
||||||
|
renderer = (
|
||||||
|
<PluginContainerIframe config={config} {...props} />
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
// istanbul ignore next: default isn't meaningful, just satisfying linter
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
renderer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginContainer.propTypes = {
|
||||||
|
config: pluginConfigShape,
|
||||||
|
};
|
||||||
|
|
||||||
|
PluginContainer.defaultProps = {
|
||||||
|
config: null,
|
||||||
|
};
|
||||||
99
plugins/PluginContainerIframe.jsx
Normal file
99
plugins/PluginContainerIframe.jsx
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import React, {
|
||||||
|
useEffect, useState,
|
||||||
|
} from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import {
|
||||||
|
PLUGIN_MOUNTED,
|
||||||
|
PLUGIN_READY,
|
||||||
|
PLUGIN_RESIZE,
|
||||||
|
} from './data/constants';
|
||||||
|
import {
|
||||||
|
dispatchPluginEvent,
|
||||||
|
useElementSize,
|
||||||
|
usePluginEvent,
|
||||||
|
} from './data/hooks';
|
||||||
|
import { pluginConfigShape } from './data/shapes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feature policy for iframe, allowing access to certain courseware-related media.
|
||||||
|
*
|
||||||
|
* We must use the wildcard (*) origin for each feature, as courseware content
|
||||||
|
* may be embedded in external iframes. Notably, xblock-lti-consumer is a popular
|
||||||
|
* block that iframes external course content.
|
||||||
|
|
||||||
|
* This policy was selected in conference with the edX Security Working Group.
|
||||||
|
* Changes to it should be vetted by them (security@edx.org).
|
||||||
|
*/
|
||||||
|
export const IFRAME_FEATURE_POLICY = (
|
||||||
|
'fullscreen; microphone *; camera *; midi *; geolocation *; encrypted-media *'
|
||||||
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/function-component-definition
|
||||||
|
export default function PluginContainerIframe({
|
||||||
|
config, fallback, className, ...props
|
||||||
|
}) {
|
||||||
|
const { url } = config;
|
||||||
|
const { title, scrolling } = props;
|
||||||
|
const [mounted, setMounted] = useState(false);
|
||||||
|
const [ready, setReady] = useState(false);
|
||||||
|
|
||||||
|
const [iframeRef, iframeElement, width, height] = useElementSize();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (mounted) {
|
||||||
|
dispatchPluginEvent(iframeElement, {
|
||||||
|
type: PLUGIN_RESIZE,
|
||||||
|
payload: {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
},
|
||||||
|
}, url);
|
||||||
|
}
|
||||||
|
}, [iframeElement, mounted, width, height, url]);
|
||||||
|
|
||||||
|
usePluginEvent(iframeElement, PLUGIN_MOUNTED, () => {
|
||||||
|
setMounted(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
usePluginEvent(iframeElement, PLUGIN_READY, () => {
|
||||||
|
setReady(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<iframe
|
||||||
|
ref={iframeRef}
|
||||||
|
title={title}
|
||||||
|
src={url}
|
||||||
|
allow={IFRAME_FEATURE_POLICY}
|
||||||
|
scrolling={scrolling}
|
||||||
|
referrerPolicy="origin" // The sent referrer will be limited to the origin of the referring page: its scheme, host, and port.
|
||||||
|
className={classNames(
|
||||||
|
'border border-0',
|
||||||
|
{ 'd-none': !ready },
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
{!ready && fallback}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginContainerIframe.propTypes = {
|
||||||
|
config: pluginConfigShape,
|
||||||
|
fallback: PropTypes.node,
|
||||||
|
scrolling: PropTypes.oneOf(['auto', 'yes', 'no']),
|
||||||
|
title: PropTypes.string,
|
||||||
|
className: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
PluginContainerIframe.defaultProps = {
|
||||||
|
config: null,
|
||||||
|
fallback: null,
|
||||||
|
scrolling: 'auto',
|
||||||
|
title: null,
|
||||||
|
className: null,
|
||||||
|
};
|
||||||
45
plugins/PluginErrorBoundary.jsx
Normal file
45
plugins/PluginErrorBoundary.jsx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { logError } from '@edx/frontend-platform/logging';
|
||||||
|
|
||||||
|
export default class PluginErrorBoundary extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = { hasError: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromError() {
|
||||||
|
// Update state so the next render will show the fallback UI.
|
||||||
|
return { hasError: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidCatch(error, info) {
|
||||||
|
logError(error, { stack: info.componentStack });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.hasError) {
|
||||||
|
// You can render any custom fallback UI
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id="plugin.load.failure.text"
|
||||||
|
defaultMessage="This content failed to load."
|
||||||
|
description="error message when an unexpected error occurs"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginErrorBoundary.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
PluginErrorBoundary.defaultProps = {
|
||||||
|
children: null,
|
||||||
|
};
|
||||||
75
plugins/PluginSlot.jsx
Normal file
75
plugins/PluginSlot.jsx
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
import React, { forwardRef } from 'react';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Spinner } from '@edx/paragon';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
|
// import { usePluginSlot } from './data/hooks';
|
||||||
|
import PluginContainer from './PluginContainer';
|
||||||
|
|
||||||
|
const PluginSlot = forwardRef(({
|
||||||
|
as, id, intl, pluginProps, children, ...props
|
||||||
|
}, ref) => {
|
||||||
|
/* the plugins below are obtained by the id passed into PluginSlot by the Host MFE. See example/src/PluginsPage.jsx
|
||||||
|
for an example of how PluginSlot is populated, and example/src/index.jsx for a dummy JS config that holds all plugins
|
||||||
|
*/
|
||||||
|
// const { plugins, keepDefault } = usePluginSlot(id);
|
||||||
|
|
||||||
|
const { fallback } = pluginProps;
|
||||||
|
|
||||||
|
// TODO: Add internationalization to the "Loading" text on the spinner.
|
||||||
|
let finalFallback = (
|
||||||
|
<div className={classNames(pluginProps.className, 'd-flex justify-content-center align-items-center')}>
|
||||||
|
<Spinner animation="border" screenReaderText="Loading" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
if (fallback !== undefined) {
|
||||||
|
finalFallback = fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
let finalChildren = [];
|
||||||
|
// if (plugins.length > 0) {
|
||||||
|
// if (keepDefault) {
|
||||||
|
// finalChildren.push(children);
|
||||||
|
// }
|
||||||
|
// plugins.forEach((pluginConfig) => {
|
||||||
|
// finalChildren.push(
|
||||||
|
// <PluginContainer
|
||||||
|
// key={pluginConfig.url}
|
||||||
|
// config={pluginConfig}
|
||||||
|
// fallback={finalFallback}
|
||||||
|
// {...pluginProps}
|
||||||
|
// />,
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
finalChildren = children;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return React.createElement(
|
||||||
|
as,
|
||||||
|
{
|
||||||
|
...props,
|
||||||
|
ref,
|
||||||
|
},
|
||||||
|
finalChildren,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default injectIntl(PluginSlot);
|
||||||
|
|
||||||
|
PluginSlot.propTypes = {
|
||||||
|
as: PropTypes.elementType,
|
||||||
|
children: PropTypes.node,
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
intl: intlShape.isRequired,
|
||||||
|
pluginProps: PropTypes.object, // eslint-disable-line
|
||||||
|
};
|
||||||
|
|
||||||
|
PluginSlot.defaultProps = {
|
||||||
|
as: 'div',
|
||||||
|
children: null,
|
||||||
|
pluginProps: {},
|
||||||
|
};
|
||||||
8
plugins/data/constants.js
Normal file
8
plugins/data/constants.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// TODO: We expect other plugin types to be added here, such as LTI_PLUGIN and BUILD_TIME_PLUGIN.
|
||||||
|
export const IFRAME_PLUGIN = 'IFRAME_PLUGIN'; // loads iframe at the URL, rather than loading a JS file.
|
||||||
|
|
||||||
|
// Plugin lifecycle events
|
||||||
|
export const PLUGIN_MOUNTED = 'PLUGIN_MOUNTED';
|
||||||
|
export const PLUGIN_READY = 'PLUGIN_READY';
|
||||||
|
export const PLUGIN_UNMOUNTED = 'PLUGIN_UNMOUNTED';
|
||||||
|
export const PLUGIN_RESIZE = 'PLUGIN_RESIZE';
|
||||||
96
plugins/data/hooks.js
Normal file
96
plugins/data/hooks.js
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import {
|
||||||
|
useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState,
|
||||||
|
} from 'react';
|
||||||
|
import { PLUGIN_MOUNTED, PLUGIN_READY, PLUGIN_UNMOUNTED } from './constants';
|
||||||
|
|
||||||
|
export function useMessageEvent(srcWindow, type, callback) {
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
const listener = (event) => {
|
||||||
|
// Filter messages to those from our source window.
|
||||||
|
if (event.source === srcWindow) {
|
||||||
|
if (event.data.type === type) {
|
||||||
|
callback({ type, payload: event.data.payload });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (srcWindow !== null) {
|
||||||
|
global.addEventListener('message', listener);
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
global.removeEventListener('message', listener);
|
||||||
|
};
|
||||||
|
}, [srcWindow, type, callback]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useHostEvent(type, callback) {
|
||||||
|
useMessageEvent(global.parent, type, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function usePluginEvent(iframeElement, type, callback) {
|
||||||
|
const contentWindow = iframeElement ? iframeElement.contentWindow : null;
|
||||||
|
useMessageEvent(contentWindow, type, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dispatchMessageEvent(targetWindow, message, targetOrigin) {
|
||||||
|
// Checking targetOrigin falsiness here since '', null or undefined would all be reasons not to
|
||||||
|
// try to post a message to the origin.
|
||||||
|
if (targetOrigin) {
|
||||||
|
targetWindow.postMessage(message, targetOrigin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dispatchPluginEvent(iframeElement, message, targetOrigin) {
|
||||||
|
dispatchMessageEvent(iframeElement.contentWindow, message, targetOrigin);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dispatchHostEvent(message) {
|
||||||
|
dispatchMessageEvent(global.parent, message, global.document.referrer);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dispatchReadyEvent() {
|
||||||
|
dispatchHostEvent({ type: PLUGIN_READY });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dispatchMountedEvent() {
|
||||||
|
dispatchHostEvent({ type: PLUGIN_MOUNTED });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dispatchUnmountedEvent() {
|
||||||
|
dispatchHostEvent({ type: PLUGIN_UNMOUNTED });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useElementSize() {
|
||||||
|
const observerRef = useRef();
|
||||||
|
|
||||||
|
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
|
||||||
|
const [offset, setOffset] = useState({ x: 0, y: 0 });
|
||||||
|
|
||||||
|
const [element, setElement] = useState(null);
|
||||||
|
|
||||||
|
const measuredRef = useCallback(_element => {
|
||||||
|
setElement(_element);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
observerRef.current = new ResizeObserver(() => {
|
||||||
|
if (element) {
|
||||||
|
setDimensions({
|
||||||
|
width: element.clientWidth,
|
||||||
|
height: element.clientHeight,
|
||||||
|
});
|
||||||
|
setOffset({
|
||||||
|
x: element.offsetLeft,
|
||||||
|
y: element.offsetTop,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (element) {
|
||||||
|
observerRef.current.observe(element);
|
||||||
|
}
|
||||||
|
}, [element]);
|
||||||
|
|
||||||
|
return useMemo(
|
||||||
|
() => ([measuredRef, element, dimensions.width, dimensions.height, offset.x, offset.y]),
|
||||||
|
[measuredRef, element, dimensions, offset],
|
||||||
|
);
|
||||||
|
}
|
||||||
10
plugins/data/shapes.js
Normal file
10
plugins/data/shapes.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/* eslint-disable import/prefer-default-export */
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { IFRAME_PLUGIN } from './constants';
|
||||||
|
|
||||||
|
export const pluginConfigShape = PropTypes.shape({
|
||||||
|
url: PropTypes.string.isRequired,
|
||||||
|
type: PropTypes.oneOf([IFRAME_PLUGIN]).isRequired,
|
||||||
|
// This is a place for us to put any generic props we want to pass to the component. We need it.
|
||||||
|
props: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||||
|
});
|
||||||
18
plugins/index.js
Normal file
18
plugins/index.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// export {
|
||||||
|
// usePluginSlot,
|
||||||
|
// } from './data/hooks';
|
||||||
|
export {
|
||||||
|
default as Plugin,
|
||||||
|
} from './Plugin';
|
||||||
|
export {
|
||||||
|
default as PluginContainer,
|
||||||
|
} from './PluginContainer';
|
||||||
|
export {
|
||||||
|
default as PluginSlot,
|
||||||
|
} from './PluginSlot';
|
||||||
|
export {
|
||||||
|
IFRAME_PLUGIN,
|
||||||
|
} from './data/constants';
|
||||||
|
export {
|
||||||
|
default as PluginErrorBoundary,
|
||||||
|
} from './PluginErrorBoundary';
|
||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
import Header from '@edx/frontend-component-header';
|
import Header from '@edx/frontend-component-header';
|
||||||
import Footer from '@edx/frontend-component-footer';
|
import Footer from '@edx/frontend-component-footer';
|
||||||
@@ -27,15 +28,25 @@ import Head from './head/Head';
|
|||||||
|
|
||||||
import AppRoutes from './routes/AppRoutes';
|
import AppRoutes from './routes/AppRoutes';
|
||||||
|
|
||||||
|
const RenderFooter = () => {
|
||||||
|
const location = useLocation();
|
||||||
|
return ['/u/edx/plugin'].includes(location.pathname) ? null : <Footer />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const RenderHeader = () => {
|
||||||
|
const location = useLocation();
|
||||||
|
return ['/u/edx/plugin'].includes(location.pathname) ? null : <Header />;
|
||||||
|
};
|
||||||
|
|
||||||
subscribe(APP_READY, () => {
|
subscribe(APP_READY, () => {
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<AppProvider store={configureStore()}>
|
<AppProvider store={configureStore()}>
|
||||||
<Head />
|
<Head />
|
||||||
<Header />
|
<RenderHeader />
|
||||||
<main>
|
<main id="main">
|
||||||
<AppRoutes />
|
<AppRoutes />
|
||||||
</main>
|
</main>
|
||||||
<Footer />
|
<RenderFooter />
|
||||||
</AppProvider>,
|
</AppProvider>,
|
||||||
document.getElementById('root'),
|
document.getElementById('root'),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ const DateJoined = ({ date }) => {
|
|||||||
if (date == null) {
|
if (date == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p className="mb-0">
|
<p className="mb-0">
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
|||||||
@@ -212,6 +212,7 @@ class ProfilePage extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>PluginPOC</div>
|
||||||
<div className="col pl-0">
|
<div className="col pl-0">
|
||||||
<div className="d-md-none">
|
<div className="d-md-none">
|
||||||
{this.renderHeadingLockup()}
|
{this.renderHeadingLockup()}
|
||||||
|
|||||||
217
src/profile/ProfilePluginPage.jsx
Normal file
217
src/profile/ProfilePluginPage.jsx
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { ensureConfig } from '@edx/frontend-platform';
|
||||||
|
import { AppContext } from '@edx/frontend-platform/react';
|
||||||
|
import { injectIntl, intlShape, FormattedDate } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { faTwitter, faFacebook, faLinkedin } from '@fortawesome/free-brands-svg-icons';
|
||||||
|
import {
|
||||||
|
ActionRow, Avatar, Card, Hyperlink, Icon,
|
||||||
|
} from '@edx/paragon';
|
||||||
|
import { HistoryEdu, VerifiedUser } from '@edx/paragon/icons';
|
||||||
|
|
||||||
|
import get from 'lodash.get';
|
||||||
|
|
||||||
|
import PluginCountry from './forms/PluginCountry';
|
||||||
|
import { Plugin } from '../../plugins';
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
import {
|
||||||
|
fetchProfile,
|
||||||
|
} from './data/actions';
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import PageLoading from './PageLoading';
|
||||||
|
|
||||||
|
// Selectors
|
||||||
|
import { profilePageSelector } from './data/selectors';
|
||||||
|
|
||||||
|
// i18n
|
||||||
|
import messages from './ProfilePage.messages';
|
||||||
|
import eduMessages from './forms/Education.messages';
|
||||||
|
|
||||||
|
import withParams from '../utils/hoc';
|
||||||
|
|
||||||
|
ensureConfig(['CREDENTIALS_BASE_URL', 'LMS_BASE_URL'], 'ProfilePage');
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/function-component-definition
|
||||||
|
function Fallback() {
|
||||||
|
return (
|
||||||
|
<div>this is broken as all get</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const platformDisplayInfo = {
|
||||||
|
facebook: {
|
||||||
|
icon: faFacebook,
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
icon: faTwitter,
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
linkedin: {
|
||||||
|
icon: faLinkedin,
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProfilePluginPage extends React.Component {
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.fetchProfile(this.props.params.username);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderContent() {
|
||||||
|
const {
|
||||||
|
profileImage,
|
||||||
|
country,
|
||||||
|
levelOfEducation,
|
||||||
|
socialLinks,
|
||||||
|
isLoadingProfile,
|
||||||
|
dateJoined,
|
||||||
|
intl,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
if (isLoadingProfile) {
|
||||||
|
return <PageLoading srMessage={this.props.intl.formatMessage(messages['profile.loading'])} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Plugin fallbackComponent={<Fallback />}>
|
||||||
|
<Card className="mb-2">
|
||||||
|
<Card.Header
|
||||||
|
className="pb-5"
|
||||||
|
subtitle={(
|
||||||
|
<Hyperlink destination={`http://localhost:1995/u/${this.props.params.username}`}>
|
||||||
|
View public profile
|
||||||
|
</Hyperlink>
|
||||||
|
)}
|
||||||
|
actions={
|
||||||
|
(
|
||||||
|
<ActionRow className="mt-3">
|
||||||
|
{socialLinks
|
||||||
|
.filter(({ socialLink }) => Boolean(socialLink))
|
||||||
|
.map(({ platform, socialLink }) => (
|
||||||
|
<StaticListItem
|
||||||
|
key={platform}
|
||||||
|
name={platformDisplayInfo[platform].name}
|
||||||
|
url={socialLink}
|
||||||
|
platform={platform}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ActionRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Card.Section className="text-center" muted>
|
||||||
|
<Avatar
|
||||||
|
size="xl"
|
||||||
|
className="profile-plugin-avatar"
|
||||||
|
src={profileImage.src}
|
||||||
|
alt="Profile image"
|
||||||
|
/>
|
||||||
|
<h1 className="h2 mb-0 font-weight-bold">{this.props.params.username}</h1>
|
||||||
|
<PluginCountry
|
||||||
|
country={country}
|
||||||
|
/>
|
||||||
|
</Card.Section>
|
||||||
|
<Card.Footer className="p-0">
|
||||||
|
<Card.Section className="pgn-icons-cell-vertical">
|
||||||
|
<Icon src={VerifiedUser} />
|
||||||
|
<p>
|
||||||
|
since <FormattedDate value={new Date(dateJoined)} year="numeric" />
|
||||||
|
</p>
|
||||||
|
</Card.Section>
|
||||||
|
<Card.Section className="pgn-icons-cell-vertical">
|
||||||
|
<Icon src={HistoryEdu} />
|
||||||
|
<p>
|
||||||
|
{intl.formatMessage(get(
|
||||||
|
eduMessages,
|
||||||
|
`profile.education.levels.${levelOfEducation}`,
|
||||||
|
eduMessages['profile.education.levels.o'],
|
||||||
|
))}
|
||||||
|
</p>
|
||||||
|
</Card.Section>
|
||||||
|
</Card.Footer>
|
||||||
|
</Card>
|
||||||
|
</Plugin>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="profile-page">
|
||||||
|
{this.renderContent()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SocialLink = ({ url, name, platform }) => (
|
||||||
|
<a href={url} className="font-weight-bold">
|
||||||
|
<FontAwesomeIcon className="mr-2" icon={platformDisplayInfo[platform].icon} />
|
||||||
|
{name}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
|
||||||
|
const StaticListItem = ({ url, name, platform }) => (
|
||||||
|
<ul className="list-inline">
|
||||||
|
<SocialLink name={name} url={url} platform={platform} />
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
|
||||||
|
ProfilePluginPage.contextType = AppContext;
|
||||||
|
|
||||||
|
ProfilePluginPage.propTypes = {
|
||||||
|
// Account data
|
||||||
|
dateJoined: PropTypes.string,
|
||||||
|
|
||||||
|
// Country form data
|
||||||
|
country: PropTypes.string,
|
||||||
|
|
||||||
|
// Education form data
|
||||||
|
levelOfEducation: PropTypes.string,
|
||||||
|
|
||||||
|
// Social links form data
|
||||||
|
socialLinks: PropTypes.arrayOf(PropTypes.shape({
|
||||||
|
platform: PropTypes.string,
|
||||||
|
socialLink: PropTypes.string,
|
||||||
|
})),
|
||||||
|
|
||||||
|
// Other data we need
|
||||||
|
profileImage: PropTypes.shape({
|
||||||
|
src: PropTypes.string,
|
||||||
|
isDefault: PropTypes.bool,
|
||||||
|
}),
|
||||||
|
isLoadingProfile: PropTypes.bool.isRequired,
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
fetchProfile: PropTypes.func.isRequired,
|
||||||
|
|
||||||
|
// Router
|
||||||
|
params: PropTypes.shape({
|
||||||
|
username: PropTypes.string.isRequired,
|
||||||
|
}).isRequired,
|
||||||
|
|
||||||
|
// i18n
|
||||||
|
intl: intlShape.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
ProfilePluginPage.defaultProps = {
|
||||||
|
profileImage: {},
|
||||||
|
levelOfEducation: null,
|
||||||
|
country: null,
|
||||||
|
socialLinks: [],
|
||||||
|
dateJoined: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
profilePageSelector,
|
||||||
|
{
|
||||||
|
fetchProfile,
|
||||||
|
},
|
||||||
|
)(injectIntl(withParams(ProfilePluginPage)));
|
||||||
@@ -103,6 +103,9 @@ exports[`<ProfilePage /> Renders correctly in various states test country edit w
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
PluginPOC
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="col pl-0"
|
className="col pl-0"
|
||||||
>
|
>
|
||||||
@@ -2486,6 +2489,9 @@ exports[`<ProfilePage /> Renders correctly in various states test education edit
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
PluginPOC
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="col pl-0"
|
className="col pl-0"
|
||||||
>
|
>
|
||||||
@@ -3663,6 +3669,9 @@ exports[`<ProfilePage /> Renders correctly in various states test preferreded la
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
PluginPOC
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="col pl-0"
|
className="col pl-0"
|
||||||
>
|
>
|
||||||
@@ -5692,6 +5701,9 @@ exports[`<ProfilePage /> Renders correctly in various states viewing other profi
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
PluginPOC
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="col pl-0"
|
className="col pl-0"
|
||||||
>
|
>
|
||||||
@@ -5947,6 +5959,9 @@ exports[`<ProfilePage /> Renders correctly in various states viewing own profile
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
PluginPOC
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="col pl-0"
|
className="col pl-0"
|
||||||
>
|
>
|
||||||
@@ -6997,6 +7012,9 @@ exports[`<ProfilePage /> Renders correctly in various states while saving an edi
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
PluginPOC
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="col pl-0"
|
className="col pl-0"
|
||||||
>
|
>
|
||||||
@@ -8114,6 +8132,9 @@ exports[`<ProfilePage /> Renders correctly in various states while saving an edi
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
PluginPOC
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="col pl-0"
|
className="col pl-0"
|
||||||
>
|
>
|
||||||
@@ -9239,6 +9260,9 @@ exports[`<ProfilePage /> Renders correctly in various states without credentials
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
PluginPOC
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="col pl-0"
|
className="col pl-0"
|
||||||
>
|
>
|
||||||
|
|||||||
40
src/profile/forms/PluginCountry.jsx
Normal file
40
src/profile/forms/PluginCountry.jsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { injectIntl } from '@edx/frontend-platform/i18n';
|
||||||
|
import { Icon } from '@edx/paragon';
|
||||||
|
import { LocationOn } from '@edx/paragon/icons';
|
||||||
|
|
||||||
|
// Selectors
|
||||||
|
import { countrySelector } from '../data/selectors';
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/prefer-stateless-function
|
||||||
|
class PluginCountry extends React.Component {
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
country,
|
||||||
|
countryMessages,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="pgn-icons-cell-horizontal">
|
||||||
|
<Icon src={LocationOn} />
|
||||||
|
<p className="h5 mt-1 ml-1">{countryMessages[country]}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginCountry.propTypes = {
|
||||||
|
country: PropTypes.string,
|
||||||
|
countryMessages: PropTypes.objectOf(PropTypes.string).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
PluginCountry.defaultProps = {
|
||||||
|
country: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
countrySelector,
|
||||||
|
{},
|
||||||
|
)(injectIntl(PluginCountry));
|
||||||
@@ -3,3 +3,4 @@ export { default as saga } from './data/sagas';
|
|||||||
export { default as ProfilePage } from './ProfilePage';
|
export { default as ProfilePage } from './ProfilePage';
|
||||||
export { default as NotFoundPage } from './NotFoundPage';
|
export { default as NotFoundPage } from './NotFoundPage';
|
||||||
export { default as messages } from './ProfilePage.messages';
|
export { default as messages } from './ProfilePage.messages';
|
||||||
|
export { default as ProfilePluginPage } from './ProfilePluginPage';
|
||||||
|
|||||||
@@ -162,4 +162,28 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pgn-icons-cell-vertical {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
margin: 1px;
|
||||||
|
}
|
||||||
|
.pgn-icons-cell-horizontal {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-plugin-avatar {
|
||||||
|
@include media-breakpoint-up(xs) {
|
||||||
|
max-width: 12rem;
|
||||||
|
margin-right: 0;
|
||||||
|
margin-top: -4rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ import {
|
|||||||
PageWrap,
|
PageWrap,
|
||||||
} from '@edx/frontend-platform/react';
|
} from '@edx/frontend-platform/react';
|
||||||
import { Routes, Route } from 'react-router-dom';
|
import { Routes, Route } from 'react-router-dom';
|
||||||
import { ProfilePage, NotFoundPage } from '../profile';
|
import { ProfilePage, NotFoundPage, ProfilePluginPage } from '../profile';
|
||||||
|
|
||||||
const AppRoutes = () => (
|
const AppRoutes = () => (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/u/:username" element={<AuthenticatedPageRoute><ProfilePage /></AuthenticatedPageRoute>} />
|
<Route path="/u/:username" element={<AuthenticatedPageRoute><ProfilePage /></AuthenticatedPageRoute>} />
|
||||||
|
<Route path="/u/:username/plugin" element={<AuthenticatedPageRoute><ProfilePluginPage /></AuthenticatedPageRoute>} />
|
||||||
<Route path="/notfound" element={<PageWrap><NotFoundPage /></PageWrap>} />
|
<Route path="/notfound" element={<PageWrap><NotFoundPage /></PageWrap>} />
|
||||||
<Route path="*" element={<PageWrap><NotFoundPage /></PageWrap>} />
|
<Route path="*" element={<PageWrap><NotFoundPage /></PageWrap>} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ jest.mock('@edx/frontend-platform/auth', () => ({
|
|||||||
jest.mock('../profile', () => ({
|
jest.mock('../profile', () => ({
|
||||||
ProfilePage: () => (<div>Profile page</div>),
|
ProfilePage: () => (<div>Profile page</div>),
|
||||||
NotFoundPage: () => (<div>Not found page</div>),
|
NotFoundPage: () => (<div>Not found page</div>),
|
||||||
|
ProfilePluginPage: () => (<div>Plugin page</div>),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const RoutesWithProvider = (context, path) => (
|
const RoutesWithProvider = (context, path) => (
|
||||||
@@ -54,6 +55,22 @@ describe('routes', () => {
|
|||||||
expect(screen.getByText('Profile page')).toBeTruthy();
|
expect(screen.getByText('Profile page')).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Profile Plugin page should be accessible for authenticated users', () => {
|
||||||
|
render(
|
||||||
|
RoutesWithProvider(
|
||||||
|
{
|
||||||
|
authenticatedUser: {
|
||||||
|
username: 'edx',
|
||||||
|
email: 'edx@example.com',
|
||||||
|
},
|
||||||
|
config: getConfig(),
|
||||||
|
},
|
||||||
|
'/u/edx/plugin',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Plugin page')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
test('should show NotFound page for a bad route', () => {
|
test('should show NotFound page for a bad route', () => {
|
||||||
render(
|
render(
|
||||||
RoutesWithProvider(unauthenticatedUser, '/nonMatchingRoute'),
|
RoutesWithProvider(unauthenticatedUser, '/nonMatchingRoute'),
|
||||||
|
|||||||
Reference in New Issue
Block a user